make font rendering unicode aware
This commit is contained in:
parent
e4ecc217e3
commit
1cbdc27a4c
17
src/draw.c
17
src/draw.c
@ -275,24 +275,18 @@ void draw_text_ex(struct renderer_canvas *canvas, struct font *font, struct v2 p
|
||||
struct v2 draw_pos = pos;
|
||||
draw_pos.y += font->point_size * scale;
|
||||
|
||||
for (u64 i = 0; i < str.len; ++i) {
|
||||
u8 c = str.text[i];
|
||||
struct string_codepoint_iter iter = string_codepoint_iter_begin(str);
|
||||
while (string_codepoint_iter_next(&iter)) {
|
||||
u32 codepoint = iter.codepoint;
|
||||
|
||||
/* TODO: Remove this (placeholder \n) */
|
||||
if (c == '\n') {
|
||||
if (codepoint == '\n') {
|
||||
draw_pos.x = pos.x;
|
||||
draw_pos.y += (font->point_size * 1.5f) * scale;
|
||||
continue;
|
||||
}
|
||||
|
||||
struct font_glyph *glyph = font_get_glyph(font, c);
|
||||
if (!glyph) {
|
||||
glyph = font_get_glyph(font, (u8)'?');
|
||||
if (!glyph) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
struct font_glyph *glyph = font_get_glyph(font, codepoint);
|
||||
f32 x = draw_pos.x + glyph->off_x * scale;
|
||||
f32 y = draw_pos.y + glyph->off_y * scale;
|
||||
f32 width = glyph->width * scale;
|
||||
@ -315,4 +309,5 @@ void draw_text_ex(struct renderer_canvas *canvas, struct font *font, struct v2 p
|
||||
|
||||
draw_pos.x += glyph->advance * scale;
|
||||
}
|
||||
string_codepoint_iter_end(&iter);
|
||||
}
|
||||
|
||||
24
src/font.c
24
src/font.c
@ -9,9 +9,12 @@
|
||||
#include "string.h"
|
||||
#include "renderer.h"
|
||||
|
||||
#define FONT_CHARS " !\"#$%&\'()-.,*/0123456789:;<=+>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
|
||||
#define LOOKUP_TABLE_SIZE (256)
|
||||
|
||||
GLOBAL u32 g_font_codes[] = {
|
||||
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
|
||||
};
|
||||
|
||||
struct font_task_params {
|
||||
struct font_task_params *next_free;
|
||||
|
||||
@ -111,11 +114,11 @@ INTERNAL WORK_TASK_FUNC_DEF(font_load_asset_task, vparams)
|
||||
FMT_STR(path)));
|
||||
}
|
||||
|
||||
struct string font_chars = STR(FONT_CHARS);
|
||||
ASSERT(ARRAY_COUNT(g_font_codes) < LOOKUP_TABLE_SIZE);
|
||||
|
||||
/* Decode */
|
||||
struct resource res = resource_open(path);
|
||||
struct ttf_decode_result result = ttf_decode(scratch.arena, res.bytes, point_size, font_chars);
|
||||
struct ttf_decode_result result = ttf_decode(scratch.arena, res.bytes, point_size, g_font_codes, ARRAY_COUNT(g_font_codes));
|
||||
resource_close(res);
|
||||
|
||||
/* Send texture to GPU */
|
||||
@ -150,9 +153,9 @@ INTERNAL WORK_TASK_FUNC_DEF(font_load_asset_task, vparams)
|
||||
MEMCPY(font->glyphs, result.glyphs, sizeof(*font->glyphs) * result.glyphs_count);
|
||||
|
||||
/* Build lookup table */
|
||||
for (u64 i = 0; i < font_chars.len; ++i) {
|
||||
u8 c = font_chars.text[i];
|
||||
font->lookup[c] = result.cache_indices[i];
|
||||
for (u64 i = 0; i < ARRAY_COUNT(g_font_codes); ++i) {
|
||||
u32 codepoint = g_font_codes[i];
|
||||
font->lookup[codepoint] = result.cache_indices[i];
|
||||
}
|
||||
|
||||
font_task_params_release(params);
|
||||
@ -227,14 +230,13 @@ struct font *font_load(struct string path, f32 point_size)
|
||||
* Other
|
||||
* ========================== */
|
||||
|
||||
struct font_glyph *font_get_glyph(struct font *font, u8 c)
|
||||
struct font_glyph *font_get_glyph(struct font *font, u32 codepoint)
|
||||
{
|
||||
/* Need to add a check here for c < LOOKUP_TABLE_SIZE if range is ever increased */
|
||||
CT_ASSERT(sizeof(c) == 1 && LOOKUP_TABLE_SIZE >= 256);
|
||||
|
||||
u16 index = font->lookup[c];
|
||||
if (codepoint < LOOKUP_TABLE_SIZE) {
|
||||
u16 index = font->lookup[codepoint];
|
||||
if (index < font->glyphs_count) {
|
||||
return &font->glyphs[index];
|
||||
}
|
||||
}
|
||||
return &font->glyphs[0];
|
||||
}
|
||||
|
||||
@ -40,6 +40,6 @@ struct asset *font_load_asset(struct string path, f32 point_size, b32 help);
|
||||
struct font *font_load_async(struct string path, f32 point_size);
|
||||
struct font *font_load(struct string path, f32 point_size);
|
||||
|
||||
struct font_glyph *font_get_glyph(struct font *font, u8 c);
|
||||
struct font_glyph *font_get_glyph(struct font *font, u32 codepoint);
|
||||
|
||||
#endif
|
||||
|
||||
26
src/string.c
26
src/string.c
@ -467,6 +467,32 @@ struct string _string_format(struct arena *arena, struct string fmt, ...)
|
||||
* Unicode
|
||||
* ========================== */
|
||||
|
||||
struct string_codepoint_iter string_codepoint_iter_begin(struct string str)
|
||||
{
|
||||
return (struct string_codepoint_iter) {
|
||||
.src = str
|
||||
};
|
||||
}
|
||||
|
||||
b32 string_codepoint_iter_next(struct string_codepoint_iter *iter)
|
||||
{
|
||||
if (iter->pos < iter->src.len) {
|
||||
struct string str_remaining = { .len = (iter->src.len - iter->pos), .text = iter->src.text + iter->pos };
|
||||
struct utf8_decode_result decoded = utf8_decode(str_remaining);
|
||||
iter->pos += decoded.advance8;
|
||||
iter->codepoint = decoded.codepoint;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void string_codepoint_iter_end(struct string_codepoint_iter *iter)
|
||||
{
|
||||
/* Do nothing */
|
||||
(UNUSED)iter;
|
||||
}
|
||||
|
||||
/* utf8 <- utf16 */
|
||||
struct string string_from_string16(struct arena *arena, struct string16 str16)
|
||||
{
|
||||
|
||||
13
src/string.h
13
src/string.h
@ -84,8 +84,21 @@ struct string string_formatv(struct arena *arena, struct string fmt, va_list arg
|
||||
* Unicode
|
||||
* ========================== */
|
||||
|
||||
struct string_codepoint_iter {
|
||||
u32 codepoint;
|
||||
|
||||
/* Internal */
|
||||
struct string src;
|
||||
u64 pos;
|
||||
};
|
||||
|
||||
struct string_codepoint_iter string_codepoint_iter_begin(struct string str);
|
||||
b32 string_codepoint_iter_next(struct string_codepoint_iter *iter);
|
||||
void string_codepoint_iter_end(struct string_codepoint_iter *iter);
|
||||
|
||||
struct string string_from_string16(struct arena *arena, struct string16 str16);
|
||||
struct string string_from_string32(struct arena *arena, struct string32 str32);
|
||||
|
||||
struct string16 string16_from_string(struct arena *arena, struct string str8);
|
||||
struct string32 string32_from_string(struct arena *arena, struct string str8);
|
||||
|
||||
|
||||
@ -14,6 +14,6 @@ struct ttf_decode_result {
|
||||
|
||||
struct ttf_startup_receipt { i32 _; };
|
||||
struct ttf_startup_receipt ttf_startup(void);
|
||||
struct ttf_decode_result ttf_decode(struct arena *arena, struct buffer encoded, f32 point_size, struct string cache_chars);
|
||||
struct ttf_decode_result ttf_decode(struct arena *arena, struct buffer encoded, f32 point_size, u32 *cache_codes, u32 cache_codes_count);
|
||||
|
||||
#endif
|
||||
|
||||
@ -68,7 +68,7 @@ struct ttf_startup_receipt ttf_startup(void)
|
||||
return (struct ttf_startup_receipt) { 0 };
|
||||
}
|
||||
|
||||
struct ttf_decode_result ttf_decode(struct arena *arena, struct buffer encoded, f32 point_size, struct string cache_chars)
|
||||
struct ttf_decode_result ttf_decode(struct arena *arena, struct buffer encoded, f32 point_size, u32 *cache_codes, u32 cache_codes_count)
|
||||
{
|
||||
COLORREF bg_color = RGB(0,0,0);
|
||||
COLORREF fg_color = RGB(255,255,255);
|
||||
@ -274,12 +274,9 @@ struct ttf_decode_result ttf_decode(struct arena *arena, struct buffer encoded,
|
||||
|
||||
/* Construct indices array */
|
||||
u16 *cache_indices = NULL;
|
||||
if (cache_chars.len > 0) {
|
||||
struct temp_arena scratch = scratch_begin(arena);
|
||||
cache_indices = arena_push_array_zero(arena, u16, cache_chars.len);
|
||||
struct string32 str32 = string32_from_string(scratch.arena, cache_chars);
|
||||
font_face->GetGlyphIndicesA(str32.text, (u32)str32.len, cache_indices);
|
||||
scratch_end(scratch);
|
||||
if (cache_codes_count > 0) {
|
||||
cache_indices = arena_push_array_zero(arena, u16, cache_codes_count);
|
||||
font_face->GetGlyphIndices(cache_codes, cache_codes_count, cache_indices);
|
||||
}
|
||||
|
||||
/* Release */
|
||||
|
||||
Loading…
Reference in New Issue
Block a user