summaryrefslogtreecommitdiff
path: root/font.c
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-07-23 17:55:23 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-07-23 17:55:23 +0300
commit99a002630c8f09b05d68213412185e71daec6e1d (patch)
tree176741aa685bc4f3b81b6cb92984fc7f84cad1ce /font.c
initial commitHEADmain
Diffstat (limited to 'font.c')
-rw-r--r--font.c211
1 files changed, 211 insertions, 0 deletions
diff --git a/font.c b/font.c
new file mode 100644
index 0000000..f57209f
--- /dev/null
+++ b/font.c
@@ -0,0 +1,211 @@
+#include "freetype/fttypes.h"
+#include <wayland-client.h>
+#include <ft2build.h>
+#include <stdint.h>
+#include <string.h>
+#include FT_FREETYPE_H
+#include <stdlib.h>
+#include <time.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "utf_8.h"
+
+static int canvas_width = 0;
+static int canvas_height = 0;
+#define COLOR 3
+
+double now_sec(void) {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return ts.tv_sec + ts.tv_nsec * 1e-9;
+}
+
+typedef struct {
+ int rows;
+ int width;
+ int advance_x;
+ int advance_y;
+ int bitmap_top;
+ int bitmap_left;
+ unsigned char *buffer;
+}CachedGlyph;
+
+static CachedGlyph ascii_cache[256] = {0};
+
+CachedGlyph *get_glyph(FT_Face face, uint32_t codepoint)
+{
+ if (codepoint < 256)
+ {
+ return &ascii_cache[codepoint];
+ }
+ else {
+ printf("Ohno.");
+ return 0;
+ }
+}
+
+int load_font(FT_Library library, char *path, FT_Face *face)
+{
+ int error;
+ error = FT_New_Face(library, path, 0, face);
+ if (error)
+ {
+ printf("Error while loading font");
+ return 1;
+ }
+ error = FT_Set_Char_Size(*face, 0, 48*64, 300, 300);
+ if (error)
+ {
+ printf("Error during setting char size %d", error);
+ return 1;
+ }
+
+ for (int i = 0; i < 255; i++)
+ {
+ int error;
+ int glyph_index = 0;
+ glyph_index = FT_Get_Char_Index(*face, i);
+ error = FT_Load_Glyph(*face, glyph_index, FT_LOAD_RENDER);
+ if (error)
+ {
+ printf("Error during LoadGlyph %d", error);
+ continue;
+ }
+ FT_GlyphSlot slot = (*face)->glyph;
+
+ CachedGlyph val = {
+ .rows = slot->bitmap.rows,
+ .width = slot->bitmap.width,
+ .advance_x = slot->advance.x,
+ .advance_y = slot->advance.y,
+ .bitmap_top = slot->bitmap_top,
+ .bitmap_left = slot->bitmap_left,
+ };
+ size_t bytes = slot->bitmap.rows * abs(slot->bitmap.pitch) * COLOR;
+ val.buffer = malloc(bytes);
+
+ for (int r = 0; r < val.rows; r++)
+ {
+ unsigned char *src = slot->bitmap.buffer + r * abs(slot->bitmap.pitch);
+ unsigned char *target = val.buffer + r * abs(slot->bitmap.pitch) * COLOR;
+
+ for (int c = 0; c < val.width; c++)
+ {
+ unsigned char alpha = src[c];
+ target[c * COLOR + 0] = alpha;
+ target[c * COLOR + 1] = alpha;
+ target[c * COLOR + 2] = alpha;
+ }
+ }
+ ascii_cache[i] = val;
+ }
+ return 0;
+}
+
+int dumbRenderer(FT_Face face, unsigned int codepoint, unsigned char *canvas, int pen_x, int pen_y)
+{
+ int x = 0;
+ int y = 0;
+ CachedGlyph *glyph = get_glyph(face, codepoint);
+ int dst_x = pen_x + glyph->bitmap_left;
+ int dst_y = pen_y - glyph->bitmap_top;
+
+ for (y = 0; y < glyph->rows; y++)
+ {
+ int target_y = dst_y + y;
+ int dst_idx = (target_y * canvas_width + dst_x) * COLOR;
+ unsigned char *row = glyph->buffer + y * abs(glyph->width * COLOR);
+ memcpy(&canvas[dst_idx], row, glyph->width * COLOR);
+ // stupe loop
+ // for (x = 0; x < bitmap.width; x++)
+ // {
+ // int target_x = dst_x + x;
+ // int idx = (target_y * width + target_x) * COLOR;
+ // unsigned char alpha = row[x];
+ // canvas[idx + 0] |= alpha;
+ // canvas[idx + 1] |= alpha;
+ // canvas[idx + 2] |= alpha;
+ // }
+ }
+ return (glyph->advance_x >> 6);
+}
+
+int main(int argc, char **argv)
+{
+ double t0 = now_sec();
+ FT_Library library;
+ FT_Face face;
+ int error = FT_Init_FreeType(&library);
+ if (error)
+ return 1;
+ // shut up gemini this is where my fonts live
+ error = load_font(library, "/usr/share/fonts/ubuntu/UbuntuMono-R.ttf", &face);
+ printf("sucees\n");
+ if (error)
+ return 1;
+ double t1 = now_sec();
+
+ // ARGV[1] to Glyph Index Array
+ uint32_t state = 0;
+ uint32_t codep = 0;
+ int glyph_count = 0;
+ int string_len = strlen(argv[1]);
+ FT_UInt target_string[string_len + 1];
+ for (int i = 0; i < string_len; i++) {
+ utf8_decode(&state, &codep, (uint8_t)argv[1][i]);
+ if (state == UTF8_REJECT)
+ printf("Invalid utf8 char: %u\n", (uint8_t)argv[1][i]);
+ else if (state == UTF8_ACCEPT)
+ {
+ target_string[glyph_count] = codep;
+ glyph_count += 1;
+ }
+ }
+ target_string[glyph_count] = 0;
+ double t2 = now_sec();
+
+ unsigned int *cp = &target_string[0];
+ char *fname = "out2.ppm";
+
+ CachedGlyph *test = get_glyph(face, 65);
+ int padding = 80;
+ canvas_width = ((test->advance_x >> 6) * glyph_count) + padding;
+ printf("width set!");
+ canvas_height = 360;
+ unsigned char *canvas = calloc(canvas_width * canvas_height * COLOR, sizeof(unsigned char));
+ int pen_x = 20;
+ int pen_y = canvas_height / 2;
+ printf("Malloc succees");
+
+ for (int i = 0; i < 200; i++)
+ { // benchmaxxing
+ unsigned int *cp = &target_string[0];
+ pen_x = 20;
+ double t2 = now_sec();
+ for (; *cp; cp++) {
+ pen_x += dumbRenderer(face, *cp, canvas, pen_x, pen_y);
+ }
+ double t3 = now_sec();
+ printf("Render: %.6f ms\n", (t3 - t2) * 1000.0);
+ }
+ //for (; *cp; cp++)
+ //{
+ // pen_x += dumbRenderer(face, *cp, canvas, pen_x, pen_y);
+ //}
+
+ double t3 = now_sec();
+ int fd = open(fname, O_CREAT | O_RDWR | O_TRUNC);
+ dprintf(fd, "P6\n%d %d\n255\n", canvas_width, canvas_height);
+ write(fd, canvas, canvas_width * canvas_height * COLOR);
+ double t4 = now_sec();
+
+ printf("Font Load: %.6f ms\n", (t1 - t0) * 1000.0);
+ printf("UTF-8 parse: %.6f ms\n", (t2 - t1) * 1000.0);
+ printf("Render: %.6f ms\n", (t3 - t2) * 1000.0);
+ printf("Write to file: %.6f ms\n", (t4 - t3) * 1000.0);
+
+ close(fd);
+ free(canvas);
+}