summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabrice <fabrice@schaub-dev.xyz>2026-02-13 07:09:38 +0100
committerFabrice <fabrice@schaub-dev.xyz>2026-02-13 07:09:38 +0100
commite40037fd7a922132015340a758468cb5dec71096 (patch)
tree5f57004ffc0bed7c0d1b2e3ae5a45df104d9eabd
parent2600ac4737d0098d650b792a30ccc557f6d76d16 (diff)
rasterizing and caching
-rw-r--r--src/atlas.cc53
-rw-r--r--src/atlas.h10
-rw-r--r--src/text.cc36
-rw-r--r--src/text.h21
-rw-r--r--src/wayclock.cc17
5 files changed, 129 insertions, 8 deletions
diff --git a/src/atlas.cc b/src/atlas.cc
index ad697f1..5e7d5c2 100644
--- a/src/atlas.cc
+++ b/src/atlas.cc
@@ -2,6 +2,7 @@
#include <cstring>
+#include "cglm/types.h"
#include "mimalloc.h"
#include "utils.h"
@@ -55,12 +56,62 @@ enum atlas_error_e wayc_atlas_init(struct atlas_s* atlas, u32 width, u32 height,
atlas->format = format;
atlas->cpu_atlas = cpu_atlas;
atlas->gpu_atlas = gpu_atlas;
- atlas->cpu_dirty = false;
success = true;
return ATLAS_ERROR_NONE;
}
+enum atlas_error_e wayc_atlas_insert(struct atlas_s* atlas, u32 width,
+ u32 height, const u8* data, vec2* uv0,
+ vec2* uv1) {
+ wayc_notnull(atlas);
+ wayc_notnull(data);
+ wayc_notnull(uv0);
+ wayc_notnull(uv1);
+
+ struct atlas_packer_s* packer = &atlas->packer;
+
+ u32 x = WAYC_X(packer->cursor);
+ u32 y = WAYC_Y(packer->cursor);
+
+ // wrap
+ if (x + width > atlas->width) {
+ x = 0;
+ y += packer->row_height;
+ packer->row_height = 0;
+ }
+
+ if (y + height > atlas->height) return ATLAS_ERROR_ATLAS_FULL;
+
+ const int atlas_pitch =
+ sg_query_surface_pitch(atlas->format, atlas->width, 1, 1);
+ const int bpp = sg_query_surface_pitch(atlas->format, 1, 1, 1);
+ const int src_pitch = width * bpp;
+
+ for (u32 row = 0; row < height; row++) {
+ const u8* src_row = data + row * src_pitch;
+ u8* dst_row = atlas->cpu_atlas + (y + row) * atlas_pitch;
+ u8* dst_px = dst_row + x * bpp;
+
+ memcpy(dst_px, src_row, src_pitch);
+ }
+
+ const f32 W = (f32)atlas->width;
+ const f32 H = (f32)atlas->height;
+
+ WAYC_X(*uv0) = (f32)x / W;
+ WAYC_Y(*uv0) = (f32)y / H;
+ WAYC_X(*uv1) = (f32)(x + width) / W;
+ WAYC_Y(*uv1) = (f32)(y + height) / H;
+
+ WAYC_X(packer->cursor) = x + width;
+ WAYC_Y(packer->cursor) = y;
+ packer->row_height = wayc_max(packer->row_height, height);
+ atlas->cpu_dirty = true;
+
+ return ATLAS_ERROR_NONE;
+}
+
enum atlas_error_e wayc_atlas_flush(struct atlas_s* atlas) {
wayc_notnull(atlas);
if (!atlas->cpu_dirty) return ATLAS_ERROR_NONE;
diff --git a/src/atlas.h b/src/atlas.h
index 66813a8..993b8f3 100644
--- a/src/atlas.h
+++ b/src/atlas.h
@@ -1,5 +1,6 @@
#pragma once
+#include "cglm/types.h"
#include "sokol_gfx.h"
#include "utils.h"
@@ -10,15 +11,24 @@ enum atlas_error_e : u8 {
ATLAS_ERROR_UPLOAD_FAILED,
};
+struct atlas_packer_s {
+ vec2 cursor;
+ u32 row_height;
+};
+
struct atlas_s {
u32 width, height;
enum sg_pixel_format format;
struct sg_image gpu_atlas;
u8* cpu_atlas;
bool cpu_dirty;
+ struct atlas_packer_s packer;
};
enum atlas_error_e wayc_atlas_init(struct atlas_s* atlas, u32 width, u32 height,
enum sg_pixel_format format);
+enum atlas_error_e wayc_atlas_insert(struct atlas_s* atlas, u32 width,
+ u32 height, const u8* data, vec2* uv0,
+ vec2* uv1);
enum atlas_error_e wayc_atlas_flush(struct atlas_s* atlas);
void wayc_atlas_deinit(struct atlas_s* atlas);
diff --git a/src/text.cc b/src/text.cc
index b703ad1..6de3506 100644
--- a/src/text.cc
+++ b/src/text.cc
@@ -4,7 +4,10 @@
#include <cstring>
#include "atlas.h"
+#include "cglm/types.h"
+#include "cglm/vec2.h"
#include "freetype/freetype.h"
+#include "freetype/fttypes.h"
#include "hash.h"
#include "shaders.h"
#include "utils.h"
@@ -124,9 +127,10 @@ enum font_error_e wayc_font_init(struct font_s* font,
FT_Face face;
FT_Error fterr = FT_New_Face(context->ft, path, 0, &face);
if (fterr) return FONT_ERROR_LOAD_FACE;
-
wayc_defer_cond(FT_Done_Face(face), success, true);
+ FT_Set_Pixel_Sizes(face, 0, font_size);
+
struct atlas_s atlas;
enum atlas_error_e aterr =
wayc_atlas_init(&atlas, atlas_width, atlas_height, SG_PIXELFORMAT_R8);
@@ -146,14 +150,36 @@ enum font_error_e wayc_font_render(struct font_s* font, codepoint_t codepoint,
wayc_notnull(font);
wayc_notnull(glyph);
- struct glyph_s cached;
- if (wayc_hashmap_get(&font->cached, &codepoint, &cached)) {
- *glyph = cached;
+ struct glyph_s got;
+ if (wayc_hashmap_get(&font->cached, &codepoint, &got)) {
+ *glyph = got;
return FONT_ERROR_NONE;
}
-
+ u32 index = FT_Get_Char_Index(font->face, codepoint);
+ if (index == 0) return FONT_ERROR_LOAD_GLYPH;
+
+ FT_Error fterr = FT_Load_Glyph(font->face, index, FT_LOAD_RENDER);
+ if (fterr) return FONT_ERROR_LOAD_GLYPH;
+
+ FT_GlyphSlot slot = font->face->glyph;
+ FT_Bitmap bitmap = slot->bitmap;
+
+ vec2 uv0, uv1;
+
+ enum atlas_error_e aterr = wayc_atlas_insert(
+ &font->atlas, bitmap.width, bitmap.rows, bitmap.buffer, &uv0, &uv1);
+ if (aterr) return FONT_ERROR_ATLAS_FAILED;
+
+ vec2 bearing = {(f32)slot->bitmap_left, (f32)slot->bitmap_top};
+ f32 advance = (f32)slot->advance.x / WAYC_SCALE;
+
+ glm_vec2_copy(uv0, got.uv0);
+ glm_vec2_copy(uv1, got.uv1);
+ glm_vec2_copy(bearing, got.bearing);
+ got.advance = advance;
+ wayc_hashmap_insert(&font->cached, &codepoint, &got);
return FONT_ERROR_NONE;
}
diff --git a/src/text.h b/src/text.h
index 4dd495b..c93f968 100644
--- a/src/text.h
+++ b/src/text.h
@@ -33,15 +33,27 @@ enum font_context_error_e wayc_font_context_init(
void wayc_font_context_deinit(struct font_context_s* context);
struct glyph_s {
+ vec2 uv0, uv1;
vec2 bearing;
- vec2 size;
- vec2 uv;
+ f32 advance;
};
+static inline void glyph_print(struct glyph_s* glyph) {
+ u32 uv0x = WAYC_X(glyph->uv0);
+ u32 uv0y = WAYC_Y(glyph->uv0);
+ u32 uv1x = WAYC_X(glyph->uv1);
+ u32 uv1y = WAYC_Y(glyph->uv1);
+ fprintf(stderr,
+ "uv0: (%u, %u), uv1: (%u, %u), bearing: (%f, %f), advance: %f\n",
+ uv0x, uv0y, uv1x, uv1y, WAYC_X(glyph->bearing),
+ WAYC_Y(glyph->bearing), glyph->advance);
+}
+
enum font_error_e : u8 {
FONT_ERROR_NONE = 0,
FONT_ERROR_LOAD_FACE,
FONT_ERROR_ATLAS_FAILED,
+ FONT_ERROR_LOAD_GLYPH,
};
struct font_s {
@@ -58,4 +70,9 @@ enum font_error_e wayc_font_init(struct font_s* font,
u32 atlas_width, u32 atlas_height);
enum font_error_e wayc_font_render(struct font_s* font, codepoint_t codepoint,
struct glyph_s* glyph);
+static inline enum font_error_e wayc_font_flush(struct font_s* font) {
+ enum atlas_error_e atlas_err = wayc_atlas_flush(&font->atlas);
+ return atlas_err == ATLAS_ERROR_NONE ? FONT_ERROR_NONE
+ : FONT_ERROR_ATLAS_FAILED;
+}
void wayc_font_deinit(struct font_s* font);
diff --git a/src/wayclock.cc b/src/wayclock.cc
index bd8491e..dc52aed 100644
--- a/src/wayclock.cc
+++ b/src/wayclock.cc
@@ -101,6 +101,23 @@ int main() {
wayc_panic("Failed to initialize font");
wayc_defer(wayc_font_deinit(&font));
+ struct glyph_s glyph_A;
+ if (wayc_font_render(&font, (codepoint_t)'A', &glyph_A) != FONT_ERROR_NONE)
+ wayc_panic("Failed to render glyph");
+ glyph_print(&glyph_A);
+
+ struct glyph_s glyph_X;
+ if (wayc_font_render(&font, (codepoint_t)'X', &glyph_X) != FONT_ERROR_NONE)
+ wayc_panic("Failed to render glyph");
+ glyph_print(&glyph_X);
+
+ struct glyph_s glyph_0;
+ if (wayc_font_render(&font, (codepoint_t)'0', &glyph_0) != FONT_ERROR_NONE)
+ wayc_panic("Failed to render glyph");
+ glyph_print(&glyph_0);
+
+ wayc_font_flush(&font);
+
struct app_s app = {&renderer};
while (wayc_eventloop_running(&loop)) {