diff --git a/src/config.h b/src/config.h index 630dd3c0..51fca89a 100644 --- a/src/config.h +++ b/src/config.h @@ -1,8 +1,5 @@ /* Project-wide configurable constants */ -/* TODO: Remove this */ -#define FONT_TEST 0 - #define WRITE_DIR "power_play" #define SETTINGS_FILENAME "settings.json" diff --git a/src/draw.c b/src/draw.c index 6968e972..f9eb21d3 100644 --- a/src/draw.c +++ b/src/draw.c @@ -270,64 +270,6 @@ void draw_text(struct renderer_canvas *canvas, struct font *font, struct v2 pos, void draw_text_ex(struct renderer_canvas *canvas, struct font *font, struct v2 pos, f32 scale, struct string str) { -#if FONT_TEST - - struct temp_arena scratch = scratch_begin_no_conflict(); - - renderer_canvas_ensure_texture_cmd(canvas, (struct texture_shader_parameters) { .texture = font->texture.renderer_handle }); - struct string32 str32 = string32_from_string(scratch.arena, str); - - struct v2 draw_pos = pos; - draw_pos.y += font->point_size * scale; - - struct font_glyphs_list glyphs = font_get_glyphs(font, str32); - for (struct font_glyph *glyph = glyphs->first; glyph; glyph = glyph->next) { - - } - - - - - - - - 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 (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, codepoint); - f32 x = draw_pos.x + glyph->off_x * scale; - f32 y = draw_pos.y + glyph->off_y * scale; - f32 width = glyph->width * scale; - f32 height = glyph->height * scale; - - struct clip_rect clip = { - { - glyph->atlas_rect.x / font->texture.size.x, - glyph->atlas_rect.y / font->texture.size.y - }, - - { - (glyph->atlas_rect.x + glyph->atlas_rect.width) / font->texture.size.x, - (glyph->atlas_rect.y + glyph->atlas_rect.height) / font->texture.size.y - } - }; - - struct quad quad = quad_from_rect(RECT(x, y, width, height)); - draw_texture_quad_internal(canvas, clip, 0xFFFFFFFF, quad); - - draw_pos.x += glyph->advance * scale; - } - string_codepoint_iter_end(&iter); - -#else renderer_canvas_ensure_texture_cmd(canvas, (struct texture_shader_parameters) { .texture = font->texture.renderer_handle }); struct v2 draw_pos = pos; @@ -368,5 +310,4 @@ 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); -#endif } diff --git a/src/font.c b/src/font.c index 4c7b55cb..f90a57b6 100644 --- a/src/font.c +++ b/src/font.c @@ -1,5 +1,3 @@ -#if FONT_TEST - #include "font.h" #include "arena.h" #include "ttf.h" @@ -11,280 +9,11 @@ #include "string.h" #include "renderer.h" -#if FONT_TEST - -#define LOOKUP_TABLE_SIZE (ARRAY_COUNT(g_font_codes) * 2) -GLOBAL u32 g_font_codes[(1 << 20)] = { 0 }; - -#else - #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 }; -#endif - -struct font_task_params { - struct font_task_params *next_free; - - struct asset *asset; - f32 point_size; - u64 path_len; - char path_cstr[1024]; -}; - -struct font_task_params_store { - struct font_task_params *head_free; - struct arena arena; - struct sys_mutex mutex; -}; - -/* ========================== * - * Global state - * ========================== */ - -GLOBAL struct { - struct font_task_params_store params; -} G = { 0 }, DEBUG_ALIAS(G, G_font); - -/* ========================== * - * Startup - * ========================== */ - -struct font_startup_receipt font_startup(struct work_startup_receipt *work_sr, - struct renderer_startup_receipt *renderer_sr, - struct asset_cache_startup_receipt *asset_cache_sr, - struct ttf_startup_receipt *ttf_sr, - struct resource_startup_receipt *resource_sr) -{ - (UNUSED)work_sr; - (UNUSED)renderer_sr; - (UNUSED)asset_cache_sr; - (UNUSED)ttf_sr; - (UNUSED)resource_sr; - - G.params.arena = arena_alloc(GIGABYTE(64)); - G.params.mutex = sys_mutex_alloc(); - -#if FONT_TEST - for (u64 i = 0; i < ARRAY_COUNT(g_font_codes); ++i) { - g_font_codes[i] = i; - } -#endif - - return (struct font_startup_receipt) { 0 }; -} - -/* ========================== * - * Load task param store - * ========================== */ - -INTERNAL struct font_task_params *font_task_params_alloc(void) -{ - struct font_task_params *p = NULL; - sys_mutex_lock(&G.params.mutex); - { - if (G.params.head_free) { - p = G.params.head_free; - G.params.head_free = p->next_free; - } else { - p = arena_push_zero(&G.params.arena, struct font_task_params); - } - } - sys_mutex_unlock(&G.params.mutex); - return p; -} - -INTERNAL void font_task_params_release(struct font_task_params *p) -{ - sys_mutex_lock(&G.params.mutex); - { - p->next_free = G.params.head_free; - G.params.head_free = p; - } - sys_mutex_unlock(&G.params.mutex); -} - -/* ========================== * - * Load - * ========================== */ - -INTERNAL WORK_TASK_FUNC_DEF(font_load_asset_task, vparams) -{ - __prof; - struct font_task_params *params = (struct font_task_params *)vparams; - struct temp_arena scratch = scratch_begin_no_conflict(); - struct string path = string_from_cstr_len(params->path_cstr, params->path_len); - f32 point_size = params->point_size; - struct asset *asset = params->asset; - - logf_info("Loading font \"%F\" (point size %F)", FMT_STR(path), FMT_FLOAT((f64)point_size)); - sys_timestamp_t start_ts = sys_timestamp(); - - ASSERT(string_ends_with(path, STR(".ttf"))); - if (!resource_exists(path)) { - /* FIME: Load baked font instead of panicking */ - sys_panic(string_format(scratch.arena, - STR("Font \"%F\" not found"), - FMT_STR(path))); - } - - 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, g_font_codes, ARRAY_COUNT(g_font_codes)); - resource_close(res); - - /* Send texture to GPU */ - struct renderer_handle texture_renderer_handle = renderer_texture_alloc(result.image_data); - - /* Allocate store memory */ - struct font *font = NULL; - { - struct asset_cache_store store = asset_cache_store_open(); - font = arena_push_zero(store.arena, struct font); - font->glyphs = arena_push_array(store.arena, struct font_glyph, result.glyphs_count); - font->lookup = arena_push_array_zero(store.arena, u16, LOOKUP_TABLE_SIZE); - asset_cache_store_close(&store); - } - - /* Set font data */ - font->texture = (struct texture) { - .renderer_handle = texture_renderer_handle, - .size = V2(result.image_data.width, result.image_data.height), - }; - font->glyphs_count = result.glyphs_count; - font->point_size = point_size; - - /* FIXME: Load baked font instead of panicking */ - if (font->glyphs_count <= 0) { - sys_panic(string_format(scratch.arena, - STR("Parsed 0 glyphs from font \"%F\"!"), - FMT_STR(path))); - } - - /* Copy glyphs from decode result */ - MEMCPY(font->glyphs, result.glyphs, sizeof(*font->glyphs) * result.glyphs_count); - - /* Build lookup table */ - 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); - - logf_info("Finished loading font \"%F\" (point size %F) in %F seconds", FMT_STR(path), FMT_FLOAT((f64)point_size), FMT_FLOAT(sys_timestamp_seconds(sys_timestamp() - start_ts))); - asset_cache_mark_ready(asset, font); - - scratch_end_and_decommit(scratch); -} - -/* Returns the asset from the asset cache */ -struct asset *font_load_asset(struct string path, f32 point_size, b32 help) -{ - __prof; - struct temp_arena scratch = scratch_begin_no_conflict(); - - /* Concatenate point_size to path for key */ - struct string key = string_format(scratch.arena, - STR("%F%F_font"), - FMT_STR(path), - FMT_FLOAT_P((f64)point_size, 3)); - u64 hash = asset_cache_hash(key); - b32 is_first_touch; - struct asset *asset = asset_cache_touch(key, hash, &is_first_touch); - - if (is_first_touch) { - /* Assemble task params */ - struct font_task_params *params = font_task_params_alloc(); - if (path.len > (sizeof(params->path_cstr) - 1)) { - sys_panic(string_format(scratch.arena, - STR("Font path \"%F\" too long!"), - FMT_STR(path))); - } - cstr_buff_from_string(BUFFER_FROM_ARRAY(params->path_cstr), path); - params->path_len = path.len; - params->asset = asset; - params->point_size = point_size; - - /* Push task */ - asset_cache_mark_loading(asset); - struct work_handle wh = { 0 }; - if (help) { - wh = work_push_task_and_help(&font_load_asset_task, params, WORK_PRIORITY_NORMAL); - } else { - wh = work_push_task(&font_load_asset_task, params, WORK_PRIORITY_NORMAL); - } - asset_cache_set_work(asset, &wh); - } - - scratch_end(scratch); - return asset; -} - -struct font *font_load_async(struct string path, f32 point_size) -{ - __prof; - struct asset *asset = font_load_asset(path, point_size, false); - struct font *f = (struct font *)asset_cache_get_store_data(asset); - return f; -} - -struct font *font_load(struct string path, f32 point_size) -{ - __prof; - struct asset *asset = font_load_asset(path, point_size, true); - asset_cache_wait(asset); - struct font *f = (struct font *)asset_cache_get_store_data(asset); - return f; -} - -/* ========================== * - * Other - * ========================== */ - -struct font_glyph *font_get_glyph(struct font *font, u32 codepoint) -{ - if (codepoint < LOOKUP_TABLE_SIZE) { - u16 index = font->lookup[codepoint]; - if (index < font->glyphs_count) { - return &font->glyphs[index]; - } - } - return &font->glyphs[0]; -} - - -#else - -#include "font.h" -#include "arena.h" -#include "ttf.h" -#include "work.h" -#include "scratch.h" -#include "asset_cache.h" -#include "resource.h" -#include "log.h" -#include "string.h" -#include "renderer.h" - -#if FONT_TEST - -#define LOOKUP_TABLE_SIZE (ARRAY_COUNT(g_font_codes) * 2) -GLOBAL u32 g_font_codes[(1 << 20)] = { 0 }; - -#else - -#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 -}; - -#endif - struct font_task_params { struct font_task_params *next_free; @@ -327,12 +56,6 @@ struct font_startup_receipt font_startup(struct work_startup_receipt *work_sr, G.params.arena = arena_alloc(GIGABYTE(64)); G.params.mutex = sys_mutex_alloc(); -#if FONT_TEST - for (u64 i = 0; i < ARRAY_COUNT(g_font_codes); ++i) { - g_font_codes[i] = i; - } -#endif - return (struct font_startup_receipt) { 0 }; } @@ -514,7 +237,9 @@ struct font_glyph *font_get_glyph(struct font *font, u32 codepoint) return &font->glyphs[index]; } } - return &font->glyphs[0]; + if (codepoint == '?') { + return &font->glyphs[font->lookup[0]]; + } else { + return &font->glyphs[font->lookup['?']]; + } } - -#endif diff --git a/src/font.h b/src/font.h index 4d62abe0..3757f99f 100644 --- a/src/font.h +++ b/src/font.h @@ -1,60 +1,3 @@ -#if FONT_TEST - -#ifndef FONT_H -#define FONT_H - -#include "texture.h" -#include "util.h" - - -struct asset; -struct work_startup_receipt; -struct renderer_startup_receipt; -struct asset_cache_startup_receipt; -struct ttf_startup_receipt; -struct resource_startup_receipt; - -struct font_glyph_list { - struct font_glyph *first; - struct font_glyph *last; -}; - -struct font_glyph { - f32 off_x; - f32 off_y; - i32 advance; - f32 width; - f32 height; - struct rect atlas_rect; - - struct font_glyph *next; -}; - -struct font { - f32 point_size; - struct texture texture; - u16 glyphs_count; - struct font_glyph *glyphs; - u16 *lookup; -}; - -struct font_startup_receipt { i32 _; }; -struct font_startup_receipt font_startup(struct work_startup_receipt *work_sr, - struct renderer_startup_receipt *renderer_sr, - struct asset_cache_startup_receipt *asset_cache_sr, - struct ttf_startup_receipt *ttf_sr, - struct resource_startup_receipt *resource_sr); - -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, u32 codepoint); - -#endif - -#else - #ifndef FONT_H #define FONT_H @@ -100,5 +43,3 @@ struct font *font_load(struct string path, f32 point_size); struct font_glyph *font_get_glyph(struct font *font, u32 codepoint); #endif - -#endif diff --git a/src/ttf_dwrite.cpp b/src/ttf_dwrite.cpp index 2e977061..5ffbb969 100644 --- a/src/ttf_dwrite.cpp +++ b/src/ttf_dwrite.cpp @@ -1,308 +1,3 @@ -#if FONT_TEST -/* Based on Allen Webster's dwrite rasterizer example - - * https://github.com/4th-dimention/examps */ - -extern "C" -{ -#include "ttf.h" -#include "scratch.h" -#include "util.h" -#include "string.h" -#include "memory.h" -#include "arena.h" -#include "font.h" -} - -#include -#include - -#pragma comment(lib, "dwrite") -#pragma comment(lib, "gdi32") - -/* TODO: Determine DPI accurately? */ -#define DPI (96.0f) - -#define CPPSTR(cstr_lit) { (sizeof((cstr_lit)) - 1), (u8 *)(cstr_lit) } - -/* ========================== * - * Global state - * ========================== */ - -GLOBAL struct { - /* FIXME: Do we need to wrap this in a mutex? */ - IDWriteFactory5 *factory; -} G = { 0 }, DEBUG_ALIAS(G, G_ttf_dwrite); - -/* ========================== * - * Decode font - * ========================== */ - -INTERNAL i32 round_up(f32 x) -{ - i32 r = (i32)x; - if ((f32)r < x) { - r += 1; - } - return r; -} - -/* Call this during font system startup */ -struct ttf_startup_receipt ttf_startup(void) -{ - ASSERT(!G.factory); - /* FIXME: I think IDWriteFactory5 only exists on later updates of windows - * 10? Need to verify. Maybe should just use a custom loader. (We're only - * using a factory5 since I think WriteInMemoryFileLoader wasn't - * implemented until then) */ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wlanguage-extension-token" /* for __uuidof */ - HRESULT error = DWriteCreateFactory( - DWRITE_FACTORY_TYPE_SHARED, - __uuidof(IDWriteFactory5), - (IUnknown **)&G.factory - ); -#pragma clang diagnostic pop - if (error) { - sys_panic(STR("Error creating DWrite factory")); - } - - return (struct ttf_startup_receipt) { 0 }; -} - -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); - - IDWriteFactory5 *factory = G.factory; - - /* TODO: handle errors */ - HRESULT error = 0; - (UNUSED)error; - - /* File */ - IDWriteFontFile *font_file = NULL; - { - /* Create in memory loader */ - IDWriteInMemoryFontFileLoader *loader = NULL; - error = factory->CreateInMemoryFontFileLoader(&loader); - error = factory->RegisterFontFileLoader(loader); - - IDWriteFontSetBuilder1 *builder = NULL; - error = factory->CreateFontSetBuilder(&builder); - error = loader->CreateInMemoryFontFileReference(factory, encoded.data, (u32)encoded.size, NULL, &font_file); - error = builder->AddFontFile(font_file); - } - - /* Face */ - IDWriteFontFace *font_face = NULL; - error = factory->CreateFontFace(DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &font_file, 0, DWRITE_FONT_SIMULATIONS_NONE, &font_face); - - /* Render settings */ - IDWriteRenderingParams *default_rendering_params = NULL; - error = factory->CreateRenderingParams(&default_rendering_params); - IDWriteRenderingParams *rendering_params = NULL; - FLOAT gamma = default_rendering_params->GetGamma(); - FLOAT enhanced_contrast = default_rendering_params->GetEnhancedContrast(); - FLOAT clear_type_level = default_rendering_params->GetClearTypeLevel(); - error = factory->CreateCustomRenderingParams(gamma, - enhanced_contrast, - clear_type_level, - DWRITE_PIXEL_GEOMETRY_FLAT, - DWRITE_RENDERING_MODE_DEFAULT, - &rendering_params); - - /* Interop */ - IDWriteGdiInterop *dwrite_gdi_interop = NULL; - error = factory->GetGdiInterop(&dwrite_gdi_interop); - - /* Get Metrics */ - DWRITE_FONT_METRICS metrics = { 0 }; - font_face->GetMetrics(&metrics); - - f32 pixel_per_em = point_size * (DPI / 72.0f); - f32 pixel_per_design_unit = pixel_per_em / ((f32)metrics.designUnitsPerEm); - - i32 raster_target_w = (i32)(8.0f * ((f32)metrics.capHeight) * pixel_per_design_unit); - i32 raster_target_h = raster_target_w; - - f32 raster_target_x = (f32)(raster_target_w / 2); - f32 raster_target_y = raster_target_x; - - ASSERT((f32)((i32)raster_target_x) == raster_target_x); - ASSERT((f32)((i32)raster_target_y) == raster_target_y); - - /* Glyph count */ - u16 glyph_count = font_face->GetGlyphCount(); - - /* Render target */ - IDWriteBitmapRenderTarget *render_target = NULL; - /* FIXME: errors when point_size too high */ - error = dwrite_gdi_interop->CreateBitmapRenderTarget(0, raster_target_w, raster_target_h, &render_target); - render_target->SetPixelsPerDip(1.0); - - /* Clear the render target */ - HDC dc = 0; - { - dc = render_target->GetMemoryDC(); - HGDIOBJ original = SelectObject(dc, GetStockObject(DC_PEN)); - SetDCPenColor(dc, bg_color); - SelectObject(dc, GetStockObject(DC_BRUSH)); - SetDCBrushColor(dc, bg_color); - Rectangle(dc, 0, 0, raster_target_w, raster_target_h); - SelectObject(dc, original); - } - - /* Allocate font memory */ - struct font_glyph *glyphs = (struct font_glyph *)arena_push_array_zero(arena, struct font_glyph, glyph_count); - - /* Allocate (starting) atlas memory - * NOTE: This is unecessary since atlas memory will grow anyway. Could - * just start w/ atlas height 0. - */ - u64 atlas_w = 1024; - u64 atlas_h = 1; - u32 *atlas_memory = arena_push_array_zero(arena, u32, atlas_w * atlas_h); - - /* Fill CPU side atlas & metric data */ - u32 out_offset_x = 0; - u32 out_offset_y = 0; - u32 row_height = 0; - for (u16 i = 0; i < glyph_count; ++i) { - /* Render glyph to target */ - DWRITE_GLYPH_RUN glyph_run = { 0 }; - glyph_run.fontFace = font_face; - glyph_run.fontEmSize = pixel_per_em; - glyph_run.glyphCount = 1; - glyph_run.glyphIndices = &i; - - RECT bounding_box = { 0 }; - error = render_target->DrawGlyphRun( - raster_target_x, - raster_target_y, - DWRITE_MEASURING_MODE_NATURAL, - &glyph_run, - rendering_params, - fg_color, - &bounding_box - ); - - if (bounding_box.left < 0 - || bounding_box.top < 0 - || bounding_box.right > raster_target_w - || bounding_box.bottom > raster_target_h) { - /* Skip */ - continue; - } - - /* Compute glyph metrics */ - DWRITE_GLYPH_METRICS glyph_metrics = { 0 }; - error = font_face->GetDesignGlyphMetrics(&i, 1, &glyph_metrics, false); - - f32 off_x = (f32)bounding_box.left - raster_target_x; - f32 off_y = (f32)bounding_box.top - raster_target_y; - f32 advance = (f32)glyph_metrics.advanceWidth * pixel_per_design_unit; - i32 tex_w = bounding_box.right - bounding_box.left; - i32 tex_h = bounding_box.bottom - bounding_box.top; - - struct font_glyph *glyph = &glyphs[i]; - glyph->off_x = off_x; - glyph->off_y = off_y; - glyph->advance = round_up(advance); - glyph->width = (f32)tex_w; - glyph->height = (f32)tex_h; - - /* Get the bitmap */ - HBITMAP bitmap = (HBITMAP)GetCurrentObject(dc, OBJ_BITMAP); - DIBSECTION dib = { 0 }; - GetObject(bitmap, sizeof(dib), &dib); - - /* Start new row if necessary */ - if ((out_offset_x + tex_w) >= atlas_w) { - out_offset_y += row_height; - out_offset_x = 0; - row_height = 0; - } - - /* Grow atlas height */ - if ((out_offset_y + tex_h) > atlas_h) { - u64 diff = (out_offset_y + tex_h) - atlas_h; - /* NOTE: This allocation must be contiguous with the initial atlas - * allocation (IE: No non-atlas arena PUSHes) */ - arena_push_array_zero(arena, u32, diff * atlas_w); - atlas_h += diff; - } - - /* Set bounding box metrics (now that we know atlas x & y) */ - glyph->atlas_rect = { 0 }; - glyph->atlas_rect.x = (f32)out_offset_x; - glyph->atlas_rect.y = (f32)out_offset_y; - glyph->atlas_rect.width = (f32)tex_w; - glyph->atlas_rect.height = (f32)tex_h; - - /* Fill atlas */ - u64 in_pitch = dib.dsBm.bmWidthBytes / 4; - u32 *in_data = (u32 *)dib.dsBm.bmBits; - u32 *out_data = atlas_memory; - for (i32 y = 0; y < tex_h; ++y) { - u64 out_y = out_offset_y + y; - u64 in_y = bounding_box.top + y; - for (i32 x = 0; x < tex_w; ++x) { - u64 out_x = out_offset_x + x; - u64 in_x = bounding_box.left + x; - u32 *out_pixel = out_data + (out_x + (out_y * atlas_w)); - u32 *in_pixel = in_data + (in_x + (in_y * in_pitch)); - *out_pixel = RGBA(0xFF, 0xFF, 0xFF, *in_pixel & 0xFF); - } - } - out_offset_x += tex_w; - - /* Grow row height */ - if ((u32)tex_h > row_height) { - row_height = tex_h; - } - - /* Clear the render target */ - { - HGDIOBJ original = SelectObject(dc, GetStockObject(DC_PEN)); - SetDCPenColor(dc, bg_color); - SelectObject(dc, GetStockObject(DC_BRUSH)); - SetDCBrushColor(dc, bg_color); - Rectangle(dc, bounding_box.left, bounding_box.top, bounding_box.right, bounding_box.bottom); - SelectObject(dc, original); - } - } - - /* Construct indices array */ - u16 *cache_indices = NULL; - 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 */ - dwrite_gdi_interop->Release(); - rendering_params->Release(); - default_rendering_params->Release(); - // NOTE FROM ALLEN: We don't release font face because we intend to keep the font face around after the baking process - // font_face->Release(); - font_file->Release(); - //loader->Release(); - factory->Release(); - - /* Return */ - struct ttf_decode_result result = { 0 }; - result.glyphs = glyphs; - result.glyphs_count = glyph_count; - result.cache_indices = cache_indices; - result.image_data.pixels = (u32 *)atlas_memory; - result.image_data.width = (u32)atlas_w; - result.image_data.height = (u32)atlas_h; - return result; -} - -#else - /* Based on Allen Webster's dwrite rasterizer example - * https://github.com/4th-dimention/examps */ @@ -604,5 +299,3 @@ struct ttf_decode_result ttf_decode(struct arena *arena, struct buffer encoded, result.image_data.height = (u32)atlas_h; return result; } - -#endif