glyph cache progress

This commit is contained in:
jacob 2025-12-13 13:12:45 -06:00
parent c8a9970438
commit 77434a988b
10 changed files with 263 additions and 1033 deletions

View File

@ -1020,11 +1020,6 @@ Vec2 RoundVec2(Vec2 a)
return VEC2(RoundF32(a.x), RoundF32(a.y)); return VEC2(RoundF32(a.x), RoundF32(a.y));
} }
Vec2I32 RoundVec2ToVec2I32(Vec2 a)
{
return VEC2I32(RoundF32ToI32(a.x), RoundF32ToI32(a.y));
}
Vec2 FloorVec2(Vec2 a) Vec2 FloorVec2(Vec2 a)
{ {
return VEC2(FloorF32(a.x), FloorF32(a.y)); return VEC2(FloorF32(a.x), FloorF32(a.y));
@ -1035,6 +1030,21 @@ Vec2 CeilVec2(Vec2 a)
return VEC2(CeilF32(a.x), CeilF32(a.y)); return VEC2(CeilF32(a.x), CeilF32(a.y));
} }
Vec2I32 RoundVec2ToI32(Vec2 a)
{
return VEC2I32(RoundF32ToI32(a.x), RoundF32ToI32(a.y));
}
Vec2I32 FloorVec2ToI32(Vec2 a)
{
return VEC2I32(FloorF32ToI32(a.x), FloorF32ToI32(a.y));
}
Vec2I32 CeilVec2ToI32(Vec2 a)
{
return VEC2I32(CeilF32ToI32(a.x), CeilF32ToI32(a.y));
}
//- Angle //- Angle
/* Returns 1 if winding between vectors a & b is clockwise or straight, -1 if counter-clockwise */ /* Returns 1 if winding between vectors a & b is clockwise or straight, -1 if counter-clockwise */
@ -1184,16 +1194,16 @@ Rng2 UnionRng2(Rng2 a, Rng2 b)
Rng2 AddRng2Vec2(Rng2 r, Vec2 v) Rng2 AddRng2Vec2(Rng2 r, Vec2 v)
{ {
Rng2 result = ZI; Rng2 result = ZI;
result.p0 = AddVec2(result.p0, v); result.p0 = AddVec2(r.p0, v);
result.p1 = AddVec2(result.p1, v); result.p1 = AddVec2(r.p1, v);
return result; return result;
} }
Rng2 DivRng2Vec2(Rng2 r, Vec2 v) Rng2 DivRng2Vec2(Rng2 r, Vec2 v)
{ {
Rng2 result = ZI; Rng2 result = ZI;
result.p0 = DivVec2Vec2(result.p0, v); result.p0 = DivVec2Vec2(r.p0, v);
result.p1 = DivVec2Vec2(result.p1, v); result.p1 = DivVec2Vec2(r.p1, v);
return result; return result;
} }
@ -1220,16 +1230,16 @@ Rng2I32 UnionRng2I32(Rng2I32 a, Rng2I32 b)
Rng2I32 AddRng2I32Vec2I32(Rng2I32 r, Vec2I32 v) Rng2I32 AddRng2I32Vec2I32(Rng2I32 r, Vec2I32 v)
{ {
Rng2I32 result = ZI; Rng2I32 result = ZI;
result.p0 = AddVec2I32(result.p0, v); result.p0 = AddVec2I32(r.p0, v);
result.p1 = AddVec2I32(result.p1, v); result.p1 = AddVec2I32(r.p1, v);
return result; return result;
} }
Rng2I32 DivRng2I32Vec2I32(Rng2I32 r, Vec2I32 v) Rng2I32 DivRng2I32Vec2I32(Rng2I32 r, Vec2I32 v)
{ {
Rng2I32 result = ZI; Rng2I32 result = ZI;
result.p0 = DivVec2I32Vec2I32(result.p0, v); result.p0 = DivVec2I32Vec2I32(r.p0, v);
result.p1 = DivVec2I32Vec2I32(result.p1, v); result.p1 = DivVec2I32Vec2I32(r.p1, v);
return result; return result;
} }

View File

@ -349,9 +349,11 @@ Vec2 PerpVec2TowardsDir(Vec2 v, Vec2 dir);
//- Round / floor / ceil //- Round / floor / ceil
Vec2 RoundVec2(Vec2 a); Vec2 RoundVec2(Vec2 a);
Vec2I32 RoundVec2ToVec2I32(Vec2 a);
Vec2 FloorVec2(Vec2 a); Vec2 FloorVec2(Vec2 a);
Vec2 CeilVec2(Vec2 a); Vec2 CeilVec2(Vec2 a);
Vec2I32 RoundVec2ToI32(Vec2 a);
Vec2I32 FloorVec2ToI32(Vec2 a);
Vec2I32 CeilVec2ToI32(Vec2 a);
//- Angle //- Angle
i32 WindingFromVec2(Vec2 a, Vec2 b); i32 WindingFromVec2(Vec2 a, Vec2 b);

View File

@ -69,8 +69,8 @@
#define FLOOD_DEBUG 0 #define FLOOD_DEBUG 0
#define GPU_DEBUG 1 #define GPU_DEBUG 0
#define GPU_DEBUG_VALIDATION 1 #define GPU_DEBUG_VALIDATION 0
#define GPU_SHADER_PRINT 1 #define GPU_SHADER_PRINT 1
#define GPU_SHADER_PRINT_BUFFER_SIZE Kibi(64); #define GPU_SHADER_PRINT_BUFFER_SIZE Kibi(64);

View File

@ -172,8 +172,8 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size
GC_RunRect *rect = &result.rects[glyph_idx]; GC_RunRect *rect = &result.rects[glyph_idx];
rect->tex = glyph->tex_ref; rect->tex = glyph->tex_ref;
rect->tex_uv = glyph->tex_uv; rect->tex_slice = glyph->tex_slice;
rect->tex_rect = glyph->tex_rect; rect->tex_slice_uv = glyph->tex_slice_uv;
rect->baseline_pos = baseline_pos; rect->baseline_pos = baseline_pos;
rect->advance = glyph->advance; rect->advance = glyph->advance;
@ -202,7 +202,7 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size
result.font_cap = glyph->font_cap; result.font_cap = glyph->font_cap;
} }
result.ready = uncached_codepoints_count == 0 && pending_glyphs_count; result.ready = uncached_codepoints_count == 0 && pending_glyphs_count == 0;
EndScratch(scratch); EndScratch(scratch);
return result; return result;
@ -251,17 +251,22 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
{ {
/* TODO: Remove this */ /* TODO: Remove this */
/* Create atlas */ /* Create atlas */
Vec2I32 atlas_size = VEC2I32(8192, 8192); Vec2I32 atlas_dims = VEC2I32(1024, 1024);
if (G_IsResourceNil(GC.atlas)) if (G_IsResourceNil(GC.atlas))
{ {
G_ArenaHandle gpu_arena = G_PermArena(); G_ArenaHandle gpu_perm = G_PermArena();
GC.atlas = G_PushTexture2D( GC.atlas = G_PushTexture2D(
gpu_arena, gpu_perm,
G_Format_R8G8B8A8_Unorm_Srgb, G_Format_R8G8B8A8_Unorm_Srgb,
atlas_size, atlas_dims,
/* FIXME: We may need simultaneous access? */ /* FIXME: We may need simultaneous access? */
G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present, // G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present,
G_Layout_Simultaneous,
.flags = G_ResourceFlag_HostMemory,
); );
GC.atlas_ref = G_PushTexture2DRef(gpu_perm, GC.atlas);
} }
for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx) for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx)
@ -275,52 +280,51 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
GC_GlyphDesc desc = glyph->desc; GC_GlyphDesc desc = glyph->desc;
TTF_GlyphDesc ttf_desc = TTF_GlyphDescFromCodepoint(desc.codepoint, resource, desc.font_size); TTF_GlyphResult ttf_info = TTF_RasterizeGlyphFromCodepoint(tick->arena, desc.codepoint, resource, desc.font_size);
glyph->font_size = ttf_desc.font_size; glyph->font_size = desc.font_size;
glyph->font_ascent = ttf_desc.font_ascent; glyph->font_ascent = ttf_info.font_ascent;
glyph->font_descent = ttf_desc.font_descent; glyph->font_descent = ttf_info.font_descent;
glyph->font_cap = ttf_desc.font_cap; glyph->font_cap = ttf_info.font_cap;
glyph->advance = ttf_info.advance;
glyph->bounds = ttf_info.bounds;
u32 *image_pixels = ttf_info.image_pixels;
Vec2I32 image_dims = ttf_info.image_dims;
glyph->advance = ttf_desc.advance;
glyph->bounds = ttf_desc.bounds;
Vec2 dims = DimsFromRng2(glyph->bounds);
Vec2I32 atlas_offset = GC.atlas_pos; Vec2I32 atlas_offset = GC.atlas_pos;
GC.atlas_row_height = MaxI32(GC.atlas_row_height, dims.y); GC.atlas_row_height = MaxI32(GC.atlas_row_height, image_dims.y);
if (atlas_offset.x + dims.x > atlas_size.x); if (atlas_offset.x + image_dims.x > atlas_dims.x);
{ {
GC.atlas_pos.x = 0; GC.atlas_pos.x = 0;
GC.atlas_pos.y += GC.atlas_row_height; GC.atlas_pos.y += GC.atlas_row_height;
GC.atlas_row_height = dims.y; GC.atlas_row_height = image_dims.y;
} }
GC.atlas_pos.x += dims.x; GC.atlas_pos.x += image_dims.x;
Rng2I32 src_slice = ZI; /* Atlas info */
src_slice.p0.x = 0; glyph->tex_ref = GC.atlas_ref;
src_slice.p0.y = 0; glyph->tex_slice = RNG2I32(atlas_offset, AddVec2I32(atlas_offset, image_dims));
src_slice.p1.x = RoundF32ToI32(dims.x); glyph->tex_slice_uv.p0.x = (f32)glyph->tex_slice.p0.x / (f32)atlas_dims.x;
src_slice.p1.y = RoundF32ToI32(dims.y); glyph->tex_slice_uv.p0.y = (f32)glyph->tex_slice.p0.y / (f32)atlas_dims.x;
glyph->tex_slice_uv.p1.x = (f32)glyph->tex_slice.p1.x / (f32)atlas_dims.x;
glyph->tex_slice_uv.p1.y = (f32)glyph->tex_slice.p1.y / (f32)atlas_dims.x;
Vec2I32 src_dims = DimsFromRng2I32(src_slice); if (image_dims.x > 0 && image_dims.y > 0)
if (src_dims.x > 0 && src_dims.y > 0)
{ {
u64 src_pixels_count = src_dims.x * src_dims.y;
u32 *src_pixels = PushStructsNoZero(tick->arena, u32, src_pixels_count);
TTF_RasterizeGlyph(src_pixels, src_dims, src_slice, ttf_desc);
DEBUGBREAKABLE;
// G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_AsyncCopy); // G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_AsyncCopy);
G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct); G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct);
{ {
G_CopyCpuToTexture( G_CopyCpuToTexture(
cl, cl,
GC.atlas, VEC3I32(atlas_offset.x, atlas_offset.y, 0), GC.atlas, VEC3I32(atlas_offset.x, atlas_offset.y, 0),
src_pixels, VEC3I32(src_dims.x, src_dims.y, 0), image_pixels, VEC3I32(image_dims.x, image_dims.y, 0),
RNG3I32( RNG3I32(
VEC3I32(src_slice.p0.x, src_slice.p0.y, 0), VEC3I32(0, 0, 0),
VEC3I32(src_slice.p1.x, src_slice.p1.y, 1) VEC3I32(image_dims.x, image_dims.y, 1)
) )
); );
} }
@ -330,14 +334,105 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
} }
Atomic32Set(&glyph->ready, 1); Atomic32Set(&glyph->ready, 1);
// ResourceKey resource = desc.font.r;
// String resource_data = DataFromResource(resource);
} }
} }
WaveSync(lane); WaveSync(lane);
// //////////////////////////////
// //- Allocate atlas rects
// if (lane->idx == 0)
// {
// /* TODO: Remove this */
// /* Create atlas */
// Vec2I32 atlas_dims = VEC2I32(8192, 8192);
// if (G_IsResourceNil(GC.atlas))
// {
// G_ArenaHandle gpu_perm = G_PermArena();
// GC.atlas = G_PushTexture2D(
// gpu_perm,
// G_Format_R8G8B8A8_Unorm_Srgb,
// atlas_dims,
// /* FIXME: We may need simultaneous access? */
// G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present,
// );
// }
// for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx)
// {
// GC_Cmd *cmd = &async->cmds.v[cmd_idx];
// GC_Glyph *glyph = cmd->glyph;
// ResourceKey resource = glyph->desc.font.r;
// String resource_data = DataFromResource(resource);
// String resource_name = NameFromResource(resource);
// GC_GlyphDesc desc = glyph->desc;
// TTF_GlyphDesc ttf_desc = TTF_GlyphDescFromCodepoint(desc.codepoint, resource, desc.font_size);
// glyph->font_size = ttf_desc.font_size;
// glyph->font_ascent = ttf_desc.font_ascent;
// glyph->font_descent = ttf_desc.font_descent;
// glyph->font_cap = ttf_desc.font_cap;
// glyph->advance = ttf_desc.advance;
// glyph->bounds = ttf_desc.bounds;
// Vec2 dims = DimsFromRng2(glyph->bounds);
// Vec2I32 atlas_offset = GC.atlas_pos;
// GC.atlas_row_height = MaxI32(GC.atlas_row_height, dims.y);
// if (atlas_offset.x + dims.x > atlas_dims.x);
// {
// GC.atlas_pos.x = 0;
// GC.atlas_pos.y += GC.atlas_row_height;
// GC.atlas_row_height = dims.y;
// }
// GC.atlas_pos.x += dims.x;
// Rng2I32 src_slice = ZI;
// src_slice.p0.x = 0;
// src_slice.p0.y = 0;
// src_slice.p1.x = RoundF32ToI32(dims.x);
// src_slice.p1.y = RoundF32ToI32(dims.y);
// Vec2I32 src_dims = DimsFromRng2I32(src_slice);
// if (src_dims.x > 0 && src_dims.y > 0)
// {
// u64 src_pixels_count = src_dims.x * src_dims.y;
// u32 *src_pixels = PushStructsNoZero(tick->arena, u32, src_pixels_count);
// TTF_RasterizeGlyph(src_pixels, src_dims, src_slice, ttf_desc);
// DEBUGBREAKABLE;
// // G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_AsyncCopy);
// G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct);
// {
// G_CopyCpuToTexture(
// cl,
// GC.atlas, VEC3I32(atlas_offset.x, atlas_offset.y, 0),
// src_pixels, VEC3I32(src_dims.x, src_dims.y, 0),
// RNG3I32(
// VEC3I32(src_slice.p0.x, src_slice.p0.y, 0),
// VEC3I32(src_slice.p1.x, src_slice.p1.y, 1)
// )
// );
// }
// G_CommitCommandList(cl);
// G_SyncCpu(G_QueueMask_All);
// }
// Atomic32Set(&glyph->ready, 1);
// // ResourceKey resource = desc.font.r;
// // String resource_data = DataFromResource(resource);
// }
// }
// WaveSync(lane);
////////////////////////////// //////////////////////////////
//- Process cmds //- Process cmds
@ -365,253 +460,3 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
WaveSync(lane); WaveSync(lane);
} }
//////////////////////////////////////////////////////////
// //~ Font load job
// JobImpl(F_Load, sig, _)
// {
// TempArena scratch = BeginScratchNoConflict();
// PERSIST Readonly u32 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
// };
// ResourceKey resource = sig->resource;
// String name = NameFromResource(resource);
// f32 font_size = sig->size;
// f32 em_size = font_size * (3.0 / 4.0);
// AC_Asset *asset = sig->asset;
// LogInfoF("Loading font \"%F\" (font size: %F, em size: %F)", FmtString(name), FmtFloat((f64)font_size), FmtFloat((f64)em_size));
// i64 start_ns = TimeNs();
// Assert(StringEndsWith(name, Lit(".ttf")));
// Assert(countof(font_codes) < F_LookupTableSize);
// /* Decode */
// String resource_data = DataFromResource(resource);
// if (resource_data.len == 0)
// {
// /* FIME: Load baked font instead of panicking */
// Panic(StringF(scratch.arena,
// "Font \"%F\" not found",
// FmtString(name)));
// }
// TTF_Decoded decoded = TTF_Decode(scratch.arena, resource_data, em_size, font_codes, countof(font_codes));
// /* Upload texture to GPU */
// Fence completion_fence = ZI;
// {
// GPU_CommandList *cl = GPU_BeginCommandList(GPU_QueueKind_BackgroundCopy);
// GPU_Arena *gpu_temp = GPU_AcquireArena();
// {
// GpuTexture gpu_texture = ZI;
// {
// GPU_Arena *gpu_perm = GPU_Perm();
// GPU_ResourceDesc desc = ZI;
// desc.texture.format = GPU_Format_R8G8B8A8_Unorm_Srgb;
// desc.texture.size = VEC3I32(decoded.image_width, decoded.image_height, 1);
// gpu_texture = GPU_PushTexture(gpu_perm, GPU_TextureKind_2D, desc);
// }
// texture->gpu_texture = gpu_texture;
// texture->width = decoded.width;
// texture->height = decoded.height;
// GpuBuffer src_buff = GPU_PushBuffer(gpu_temp, GPU_GetFootprintSize(gpu_texture), GPU_BufferFlag_CpuWritable);
// GpuAddress src_addr = ZI;
// {
// u32 *p = GPU_PushStructsNoZero(src_buff, u32, decoded.width * decoded.height);
// CopyStructs(p, decoded.pixels, decoded.width * decoded.heigth);
// GPU_TransitionBufferToCopySrc(src_buff);
// GPU_TransitionTextureToCopyDst(gpu_texture);
// GPU_CopyBytesToFootprint(gpu_texture, src_buff, src_addr, decoded.width * decoded.height * 4);
// GPU_TransitionTextureToReadonly(gpu_texture);
// }
// GPU_SetFence(&completion_fence, 1);
// }
// GPU_ReleaseArena(gpu_temp);
// GPU_EndCommandList(cl);
// }
// /* Acquire store memory */
// F_Font *font = 0;
// {
// AC_Store store = AC_OpenStore();
// font = PushStruct(store.arena, F_Font);
// font->glyphs = PushStructsNoZero(store.arena, F_Glyph, decoded.glyphs_count);
// font->lookup = PushStructs(store.arena, u16, F_LookupTableSize);
// AC_CloseStore(&store);
// }
// /* Set font data */
// font->texture = texture;
// font->image_width = decoded.image_width;
// font->image_height = decoded.image_height;
// font->glyphs_count = decoded.glyphs_count;
// font->size = font_size;
// font->ascent = decoded.ascent;
// font->descent = decoded.descent;
// font->cap = decoded.cap;
// /* FIXME: Load baked font instead of panicking */
// if (font->glyphs_count <= 0)
// {
// Panic(StringF(scratch.arena,
// "Parsed 0 glyphs from font \"%F\"!",
// FmtString(name)));
// }
// /* Copy glyphs from decode decoded */
// /* NOTE: Font glyph size must match TTF glyph size for memcpy */
// StaticAssert(sizeof(*font->glyphs) == sizeof(*decoded.glyphs));
// CopyBytes(font->glyphs, decoded.glyphs, sizeof(*font->glyphs) * decoded.glyphs_count);
// /* Build lookup table */
// for (u64 i = 0; i < countof(font_codes); ++i)
// {
// u32 codepoint = font_codes[i];
// font->lookup[codepoint] = decoded.cache_indices[i];
// }
// YieldOnFence(&completion_fence, 1);
// LogSuccessF("Loaded font \"%F\" (font size: %F, em size: %F) in %F seconds", FmtString(name), FmtFloat((f64)font_size), FmtFloat((f64)em_size), FmtFloat(SecondsFromNs(TimeNs() - start_ns)));
// AC_MarkReady(asset, font);
// EndScratch(scratch);
// }
// ////////////////////////////////////////////////////////////
// //~ Font load
// /* Returns the asset from the asset cache */
// AC_Asset *F_LoadAsset(ResourceKey resource, f32 size, b32 wait)
// {
// TempArena scratch = BeginScratchNoConflict();
// String name = NameFromResource(resource);
// /* Concatenate size to name for key */
// String key = StringF(scratch.arena,
// "%F%F_font",
// FmtString(name),
// FmtFloatP((f64)size, 1));
// u64 hash = AC_HashFromKey(key);
// b32 is_first_touch;
// AC_Asset *asset = AC_TouchCache(key, hash, &is_first_touch);
// if (is_first_touch)
// {
// AC_MarkLoading(asset);
// {
// Job *job = OpenJob(F_Load, AsyncPool());
// F_Load_Sig *sig = PushStruct(job->arena, F_Load_Sig);
// job->sig = sig;
// sig->asset = asset;
// sig->resource = resource;
// sig->size = size;
// CloseJob(job);
// }
// if (wait)
// {
// AC_YieldOnAssetReady(asset);
// }
// }
// EndScratch(scratch);
// return asset;
// }
// F_Font *F_LoadFontAsync(ResourceKey resource, f32 point_size)
// {
// AC_Asset *asset = F_LoadAsset(resource, point_size, 0);
// F_Font *f = (F_Font *)AC_DataFromStore(asset);
// return f;
// }
// F_Font *F_LoadFontWait(ResourceKey resource, f32 point_size)
// {
// AC_Asset *asset = F_LoadAsset(resource, point_size, 1);
// AC_YieldOnAssetReady(asset);
// F_Font *f = (F_Font *)AC_DataFromStore(asset);
// return f;
// }
// ////////////////////////////////////////////////////////////
// //~ Font data
// F_Glyph F_GlyphFromCodepoint(F_Font *font, u32 codepoint)
// {
// if (codepoint < F_LookupTableSize)
// {
// u16 index = font->lookup[codepoint];
// if (index < font->glyphs_count)
// {
// return font->glyphs[index];
// }
// }
// if (codepoint == '?')
// {
// return font->glyphs[font->lookup[0]];
// }
// else
// {
// return font->glyphs[font->lookup['?']];
// }
// }
// F_Run F_RunFromString(Arena *arena, F_Font *font, String str)
// {
// F_Run result = ZI;
// result.rects = ArenaNext(arena, F_RunRect);
// f32 baseline_length = 0;
// for (CodepointIter it = InitCodepointIter(str); NextCodepoint(&it);)
// {
// u32 codepoint = it.codepoint;
// if (font->glyphs_count <= codepoint)
// {
// codepoint = '?';
// }
// if (codepoint < font->glyphs_count)
// {
// u16 index = font->lookup[codepoint];
// F_Glyph glyph = font->glyphs[index];
// F_RunRect *rect = PushStruct(arena, F_RunRect);
// ++result.count;
// rect->atlas_p0 = glyph.atlas_p0;
// rect->atlas_p1 = glyph.atlas_p1;
// Vec2I32 size = SubVec2I32(glyph.atlas_p1, glyph.atlas_p0);
// rect->pos = baseline_length;
// rect->offset = glyph.baseline_offset;
// rect->advance = glyph.advance;
// result.p0.x = MinF32(result.p0.x, rect->offset.x + rect->pos); /* Left run bounds */
// result.p1.x = MaxF32(result.p1.x, rect->offset.x + rect->pos + size.x); /* Right run bounds */
// result.p0.y = MinF32(result.p0.y, rect->offset.y); /* Top run bounds */
// result.p1.y = MaxF32(result.p1.y, rect->offset.y + size.y); /* Bottom run bounds */
// baseline_length += rect->advance;
// }
// }
// return result;
// }

View File

@ -33,12 +33,12 @@ Struct(GC_Glyph)
/* Layout info */ /* Layout info */
f32 advance; f32 advance;
Rng2 bounds; /* Bounds relative to baseline position */ Rng2 bounds;
/* Atlas info */ /* Atlas info */
G_Texture2DRef tex_ref; G_Texture2DRef tex_ref;
Rng2 tex_uv; Rng2I32 tex_slice;
Rng2 tex_rect; Rng2 tex_slice_uv;
}; };
Struct(GC_GlyphBin) Struct(GC_GlyphBin)
@ -63,8 +63,8 @@ Struct(GC_RunRect)
f32 advance; f32 advance;
G_Texture2DRef tex; G_Texture2DRef tex;
Rng2 tex_uv; Rng2I32 tex_slice;
Rng2 tex_rect; Rng2 tex_slice_uv;
}; };
Struct(GC_Run) Struct(GC_Run)
@ -161,77 +161,3 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size
//~ Async //~ Async
void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *ctx); void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *ctx);
// ////////////////////////////////////////////////////////////
// //~ Font types
// Struct(GC_FontKey)
// {
// u64 v;
// };
// Struct(GC_Glyph)
// {
// i32 advance;
// Vec2 baseline_offset;
// Vec2I32 atlas_p0;
// Vec2I32 atlas_p1;
// };
// Struct(GC_Font)
// {
// GPU_Resource *texture;
// u32 image_width;
// u32 image_height;
// u16 glyphs_count;
// F_Glyph *glyphs;
// u16 *lookup;
// /* Metrics */
// f32 size;
// f32 ascent;
// f32 descent;
// f32 cap;
// };
// ////////////////////////////////////////////////////////////
// //~ Run types
// Struct(F_RunRect)
// {
// Vec2 offset; /* Vector from baseline offset to top left of glyph rect */
// f32 pos; /* Horizontal distance from start of baseline */
// f32 advance;
// Vec2I32 atlas_p0;
// Vec2I32 atlas_p1;
// };
// Struct(F_Run)
// {
// Vec2 p0; /* Start of baseline to top-left-most rect */
// Vec2 p1; /* Start of baseline to bottom-right-most rect corner */
// u32 count;
// F_RunRect *rects;
// };
// ////////////////////////////////////////////////////////////
// //~ Font load job
// JobDecl(F_Load, { AC_Asset *asset; f32 size; ResourceKey resource; });
// ////////////////////////////////////////////////////////////
// //~ Font load
// AC_Asset *F_LoadAsset(ResourceKey resource, f32 size, b32 wait);
// F_Font *F_LoadFontAsync(ResourceKey resource, f32 size);
// F_Font *F_LoadFontWait(ResourceKey resource, f32 size);
// ////////////////////////////////////////////////////////////
// //~ Run
// F_Glyph F_GlyphFromCodepoint(F_Font *font, u32 codepoint);
// F_Run F_RunFromString(Arena *arena, F_Font *font, String str);

View File

@ -2331,8 +2331,8 @@ void G_CopyBufferToBuffer(G_CommandListHandle cl_handle, G_ResourceHandle dst_ha
G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle);
G_D12_Cmd *cmd = G_D12_PushCmd(cl); G_D12_Cmd *cmd = G_D12_PushCmd(cl);
cmd->kind = G_D12_CmdKind_CopyBytes; cmd->kind = G_D12_CmdKind_CopyBytes;
cmd->copy_bytes.dst = G_D12_ResourceFromHandle(dst_handle);
cmd->copy_bytes.src = G_D12_ResourceFromHandle(src_handle); cmd->copy_bytes.src = G_D12_ResourceFromHandle(src_handle);
cmd->copy_bytes.dst = G_D12_ResourceFromHandle(dst_handle);
cmd->copy_bytes.dst_offset = dst_offset; cmd->copy_bytes.dst_offset = dst_offset;
cmd->copy_bytes.src_copy_range = src_copy_range; cmd->copy_bytes.src_copy_range = src_copy_range;
} }
@ -2341,13 +2341,13 @@ void G_CopyBufferToTexture(G_CommandListHandle cl_handle, G_ResourceHandle dst_h
{ {
G_D12_SharedState *g = &G_D12_shared_state; G_D12_SharedState *g = &G_D12_shared_state;
G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle);
G_D12_Resource *dst = G_D12_ResourceFromHandle(dst_handle);
G_D12_Resource *src = G_D12_ResourceFromHandle(src_handle); G_D12_Resource *src = G_D12_ResourceFromHandle(src_handle);
Assert(dst->is_texture); G_D12_Resource *dst = G_D12_ResourceFromHandle(dst_handle);
Assert(!src->is_texture); Assert(!src->is_texture);
Assert(dst->is_texture);
/* Grab footprint info */ /* Grab footprint info */
D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint = ZI; D3D12_PLACED_SUBRESOURCE_FOOTPRINT src_footprint = ZI;
{ {
D3D12_RESOURCE_DESC src_desc = ZI; D3D12_RESOURCE_DESC src_desc = ZI;
{ {
@ -2356,21 +2356,21 @@ void G_CopyBufferToTexture(G_CommandListHandle cl_handle, G_ResourceHandle dst_h
src_desc.Height = src_dims.y; src_desc.Height = src_dims.y;
src_desc.DepthOrArraySize = src_dims.z; src_desc.DepthOrArraySize = src_dims.z;
} }
ID3D12Device_GetCopyableFootprints(g->device, &src_desc, 0, 1, 0, &footprint, 0, 0, 0); ID3D12Device_GetCopyableFootprints(g->device, &src_desc, 0, 1, 0, &src_footprint, 0, 0, 0);
} }
D3D12_TEXTURE_COPY_LOCATION dst_loc = ZI;
D3D12_TEXTURE_COPY_LOCATION src_loc = ZI; D3D12_TEXTURE_COPY_LOCATION src_loc = ZI;
D3D12_TEXTURE_COPY_LOCATION dst_loc = ZI;
{
src_loc.pResource = src->d3d_resource;
src_loc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
src_loc.PlacedFootprint = src_footprint;
}
{ {
dst_loc.pResource = dst->d3d_resource; dst_loc.pResource = dst->d3d_resource;
dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dst_loc.SubresourceIndex = 0; dst_loc.SubresourceIndex = 0;
} }
{
src_loc.pResource = src->d3d_resource;
src_loc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
src_loc.PlacedFootprint = footprint;
}
G_D12_Cmd *cmd = G_D12_PushCmd(cl); G_D12_Cmd *cmd = G_D12_PushCmd(cl);
cmd->kind = G_D12_CmdKind_CopyTexels; cmd->kind = G_D12_CmdKind_CopyTexels;
@ -2386,23 +2386,23 @@ void G_CopyTextureToTexture(G_CommandListHandle cl_handle, G_ResourceHandle dst_
{ {
G_D12_SharedState *g = &G_D12_shared_state; G_D12_SharedState *g = &G_D12_shared_state;
G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle);
G_D12_Resource *dst = G_D12_ResourceFromHandle(dst_handle);
G_D12_Resource *src = G_D12_ResourceFromHandle(src_handle); G_D12_Resource *src = G_D12_ResourceFromHandle(src_handle);
Assert(dst->is_texture); G_D12_Resource *dst = G_D12_ResourceFromHandle(dst_handle);
Assert(src->is_texture); Assert(src->is_texture);
Assert(dst->is_texture);
D3D12_TEXTURE_COPY_LOCATION dst_loc = ZI;
D3D12_TEXTURE_COPY_LOCATION src_loc = ZI; D3D12_TEXTURE_COPY_LOCATION src_loc = ZI;
{ D3D12_TEXTURE_COPY_LOCATION dst_loc = ZI;
dst_loc.pResource = dst->d3d_resource;
dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dst_loc.SubresourceIndex = 0;
}
{ {
src_loc.pResource = dst->d3d_resource; src_loc.pResource = dst->d3d_resource;
src_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; src_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
src_loc.SubresourceIndex = 0; src_loc.SubresourceIndex = 0;
} }
{
dst_loc.pResource = dst->d3d_resource;
dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dst_loc.SubresourceIndex = 0;
}
G_D12_Cmd *cmd = G_D12_PushCmd(cl); G_D12_Cmd *cmd = G_D12_PushCmd(cl);
cmd->kind = G_D12_CmdKind_CopyTexels; cmd->kind = G_D12_CmdKind_CopyTexels;
@ -2900,7 +2900,7 @@ void G_D12_CollectionWorkerEntryPoint(WaveLaneCtx *lane)
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
u8 *at = start; u8 *at = start;
{ {
for (u32 print_num = 1; print_num <= prints_count; ++print_num) for (u32 print_idx = 0; print_idx < prints_count; ++print_idx)
{ {
u32 chars_count = 0; u32 chars_count = 0;
u32 args_count = 0; u32 args_count = 0;

View File

@ -249,7 +249,7 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
/* TODO: Don't rely on ui report for draw size since it introduces one frame of delay when resizing */ /* TODO: Don't rely on ui report for draw size since it introduces one frame of delay when resizing */
UI_Report vis_rep = UI_ReportFromKey(vis_box); UI_Report vis_rep = UI_ReportFromKey(vis_box);
draw_size = RoundVec2ToVec2I32(DimsFromRng2(vis_rep.screen_rect)); draw_size = RoundVec2ToI32(DimsFromRng2(vis_rep.screen_rect));
} }
draw_size.x = MaxI32(draw_size.x, 1); draw_size.x = MaxI32(draw_size.x, 1);
draw_size.y = MaxI32(draw_size.y, 1); draw_size.y = MaxI32(draw_size.y, 1);

View File

@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Glyph types //~ Glyph types
Struct(TTF_GlyphDesc) Struct(TTF_GlyphResult)
{ {
ResourceKey ttf; ResourceKey ttf;
u32 codepoint; u32 codepoint;
@ -13,15 +13,18 @@ Struct(TTF_GlyphDesc)
f32 font_ascent; f32 font_ascent;
f32 font_descent; f32 font_descent;
f32 font_cap; f32 font_cap;
/* Rasterization output */
Vec2I32 image_dims;
u32 *image_pixels;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Bootstrap //~ @hookdecl Bootstrap
void TTF_Bootstrap(void); void TTF_Bootstrap(void);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Decode //~ @hookdecl Rasterize
TTF_GlyphDesc TTF_GlyphDescFromCodepoint(u32 codepoint, ResourceKey ttf, f32 font_size); TTF_GlyphResult TTF_RasterizeGlyphFromCodepoint(Arena *arena, u32 codepoint, ResourceKey ttf, f32 font_size);
void TTF_RasterizeGlyph(u32 *dst, Vec2I32 dst_size, Rng2I32 dst_slice, TTF_GlyphDesc glyph_desc);

View File

@ -24,23 +24,21 @@ void TTF_Bootstrap(void)
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookimpl Decode //~ @hookimpl Rasterize
TTF_GlyphDesc TTF_GlyphDescFromCodepoint(u32 codepoint, ResourceKey ttf, f32 font_size) TTF_GlyphResult TTF_RasterizeGlyphFromCodepoint(Arena *arena, u32 codepoint, ResourceKey ttf, f32 font_size)
{ {
String encoded = DataFromResource(ttf); COLORREF bg_color = 0xFF000000;
COLORREF fg_color = 0xFFFFFFFF;
/* TODO: Handle errors */
HRESULT hr = 0;
TTF_GlyphDesc result = ZI;
result.font_size = font_size;
result.ttf = ttf;
result.codepoint = codepoint;
f32 em_size = font_size * (3.0 / 4.0); f32 em_size = font_size * (3.0 / 4.0);
f32 pixel_per_em = em_size * (TTF_DW_Dpi / 72.0f); f32 pixel_per_em = em_size * (TTF_DW_Dpi / 72.0f);
/* TODO: handle errors */
HRESULT hr = 0;
String encoded = DataFromResource(ttf);
/* File */ /* File */
IDWriteFontFile *font_file = 0; IDWriteFontFile *font_file = 0;
{ {
@ -61,88 +59,39 @@ TTF_GlyphDesc TTF_GlyphDescFromCodepoint(u32 codepoint, ResourceKey ttf, f32 fon
hr = IDWriteFactory5_CreateFontFace(TTF_DW.factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &font_file, 0, DWRITE_FONT_SIMULATIONS_NONE, &font_face); hr = IDWriteFactory5_CreateFontFace(TTF_DW.factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &font_file, 0, DWRITE_FONT_SIMULATIONS_NONE, &font_face);
} }
/* Glyph idx */
u16 glyph_idx = 0;
{
hr = IDWriteFontFace_GetGlyphIndices(font_face, &codepoint, 1, &glyph_idx);
}
/* Font metrics */ /* Font metrics */
DWRITE_FONT_METRICS font_metrics = ZI; DWRITE_FONT_METRICS font_metrics = ZI;
{ {
IDWriteFontFace_GetMetrics(font_face, &font_metrics); IDWriteFontFace_GetMetrics(font_face, &font_metrics);
} }
f32 pixel_per_design_unit = pixel_per_em / ((f32)font_metrics.designUnitsPerEm); f32 pixel_per_design_unit = pixel_per_em / ((f32)font_metrics.designUnitsPerEm);
result.font_ascent = font_metrics.ascent * pixel_per_design_unit; f32 font_ascent = font_metrics.ascent * pixel_per_design_unit;
result.font_descent = font_metrics.descent * pixel_per_design_unit; f32 font_descent = font_metrics.descent * pixel_per_design_unit;
result.font_cap = font_metrics.capHeight * pixel_per_design_unit; f32 font_cap = font_metrics.capHeight * pixel_per_design_unit;
/* Glyph idx */
u16 glyph_idx = 0;
{
hr = IDWriteFontFace_GetGlyphIndices(font_face, &codepoint, 1, &glyph_idx);
}
/* Glyph metrics */ /* Glyph metrics */
{
DWRITE_GLYPH_METRICS m = ZI; DWRITE_GLYPH_METRICS m = ZI;
{ {
hr = IDWriteFontFace_GetDesignGlyphMetrics(font_face, &glyph_idx, 1, &m, 0); hr = IDWriteFontFace_GetDesignGlyphMetrics(font_face, &glyph_idx, 1, &m, 0);
} }
Rng2 bounds = ZI; f32 advance = (f32)m.advanceWidth * pixel_per_design_unit;
{
bounds.p0.x = (f32)m.leftSideBearing;
bounds.p1.x = (f32)m.advanceWidth - (f32)m.rightSideBearing;
bounds.p0.y = (f32)m.verticalOriginY - (f32)m.advanceHeight + m.bottomSideBearing;
bounds.p1.y = (f32)m.verticalOriginY - (f32)m.topSideBearing;
}
result.bounds.p0.x = bounds.p0.x * pixel_per_design_unit;
result.bounds.p0.y = bounds.p0.y * pixel_per_design_unit;
result.bounds.p1.x = bounds.p1.x * pixel_per_design_unit;
result.bounds.p1.y = bounds.p1.y * pixel_per_design_unit;
result.advance = (f32)m.advanceWidth * pixel_per_design_unit;
}
return result;
}
void TTF_RasterizeGlyph(u32 *dst, Vec2I32 dst_size, Rng2I32 dst_slice, TTF_GlyphDesc glyph_desc)
{
COLORREF bg_color = 0xFF000000;
COLORREF fg_color = 0xFFFFFFFF;
f32 em_size = glyph_desc.font_size * (3.0 / 4.0);
f32 pixel_per_em = em_size * (TTF_DW_Dpi / 72.0f);
/* TODO: handle errors */
HRESULT hr = 0;
String encoded = DataFromResource(glyph_desc.ttf);
/* File */
IDWriteFontFile *font_file = 0;
{
/* Create in memory loader */
IDWriteInMemoryFontFileLoader *loader = 0;
hr = IDWriteFactory5_CreateInMemoryFontFileLoader(TTF_DW.factory, &loader);
hr = IDWriteFactory5_RegisterFontFileLoader(TTF_DW.factory, (IDWriteFontFileLoader *)loader);
IDWriteFontSetBuilder1 *builder = 0;
hr = IDWriteFactory5_CreateFontSetBuilder1(TTF_DW.factory, &builder);
hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(loader, (IDWriteFactory *)TTF_DW.factory, encoded.text, (u32)encoded.len, 0, &font_file);
hr = IDWriteFontSetBuilder1_AddFontFile(builder, font_file);
}
/* Face */
IDWriteFontFace *font_face = 0;
{
hr = IDWriteFactory5_CreateFontFace(TTF_DW.factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &font_file, 0, DWRITE_FONT_SIMULATIONS_NONE, &font_face);
}
/* Glyph idx */
u16 glyph_idx = 0;
{
hr = IDWriteFontFace_GetGlyphIndices(font_face, &glyph_desc.codepoint, 1, &glyph_idx);
}
@ -159,8 +108,10 @@ void TTF_RasterizeGlyph(u32 *dst, Vec2I32 dst_size, Rng2I32 dst_slice, TTF_Glyph
/* FIXME: Dynamic render target */ /* FIXME: Dynamic render target */
i32 render_target_w = 256; i32 render_target_w = 256;
i32 render_target_h = 256; i32 render_target_h = 256;
i32 render_target_baseline_x = (render_target_w / 2) - DimsFromRng2I32(dst_slice).x;
i32 render_target_baseline_y = (render_target_h / 2) - DimsFromRng2I32(dst_slice).y; /* Best-guess a position in the middle of the render target based on metrics */
i32 render_target_baseline_x = (render_target_w / 2) - (advance / 2);
i32 render_target_baseline_y = (render_target_h / 2) - (font_cap / 2);
/* Create render target */ /* Create render target */
IDWriteBitmapRenderTarget *render_target = 0; IDWriteBitmapRenderTarget *render_target = 0;
@ -222,7 +173,7 @@ void TTF_RasterizeGlyph(u32 *dst, Vec2I32 dst_size, Rng2I32 dst_slice, TTF_Glyph
} }
/* Render glyph to target */ /* Render glyph to target */
Rng2I32 src_slice = ZI; Rng2I32 rt_slice = ZI;
{ {
DWRITE_GLYPH_RUN glyph_run = ZI; DWRITE_GLYPH_RUN glyph_run = ZI;
{ {
@ -242,563 +193,54 @@ void TTF_RasterizeGlyph(u32 *dst, Vec2I32 dst_size, Rng2I32 dst_slice, TTF_Glyph
fg_color, fg_color,
&bounding_box &bounding_box
); );
src_slice.p0.x = bounding_box.left; rt_slice.p0.x = bounding_box.left;
src_slice.p0.y = bounding_box.top; rt_slice.p0.y = bounding_box.top;
src_slice.p1.x = bounding_box.right; rt_slice.p1.x = bounding_box.right;
src_slice.p1.y = bounding_box.bottom; rt_slice.p1.y = bounding_box.bottom;
} }
rt_slice.p0.x = MaxI32(rt_slice.p0.x, 0);
rt_slice.p0.y = MaxI32(rt_slice.p0.y, 0);
rt_slice.p1.x = MinI32(rt_slice.p1.x, render_target_w);
rt_slice.p1.y = MinI32(rt_slice.p1.y, render_target_h);
Vec2I32 src_slice_dims = DimsFromRng2I32(src_slice); Vec2I32 dst_dims = DimsFromRng2I32(rt_slice);
Vec2I32 dst_slice_dims = DimsFromRng2I32(dst_slice); u32 *dst_pixels = PushStructsNoZero(arena, u32, dst_dims.x * dst_dims.y);
/* FIXME: Handle gracefully */ /* Copy from target to result */
Assert(src_slice_dims.x <= dst_slice_dims.x);
Assert(src_slice_dims.y <= dst_slice_dims.y);
/* FIXME: Account for render target overrun */
/* Copy result from target */
{ {
u64 src_pitch = (u64)dib.dsBm.bmWidthBytes / 4; u64 src_pitch = (u64)dib.dsBm.bmWidthBytes / 4;
u32 *src_pixels = (u32 *)dib.dsBm.bmBits; u32 *src_pixels = (u32 *)dib.dsBm.bmBits;
for (i32 y = 0; y < src_slice_dims.y; ++y) for (i32 y = 0; y < dst_dims.y; ++y)
{ {
u64 src_y = src_slice.p0.y + y; u64 src_y = rt_slice.p0.y + y;
u64 dst_y = dst_slice.p0.y + y; u64 dst_y = y;
for (i32 x = 0; x < src_slice_dims.x; ++x) for (i32 x = 0; x < dst_dims.x; ++x)
{ {
u64 src_x = src_slice.p0.x + x; u64 src_x = rt_slice.p0.x + x;
u64 dst_x = dst_slice.p0.x + x; u64 dst_x = x;
u32 *src_pixel = src_pixels + (src_x + (src_y * src_pitch)); u32 *src_pixel = src_pixels + (src_x + (src_y * src_pitch));
u32 *dst_pixel = dst + (dst_x + (dst_y * dst_size.x)); u32 *dst_pixel = dst_pixels + (dst_x + (dst_y * dst_dims.x));
*dst_pixel = 0x00FFFFFF | ((*src_pixel & 0xFF) << 24); *dst_pixel = 0x00FFFFFF | ((*src_pixel & 0xFF) << 24);
} }
} }
} }
TTF_GlyphResult result = ZI;
{
result.ttf = ttf;
result.codepoint = codepoint;
result.advance = advance;
result.bounds.p0 = VEC2(0, 0);
result.bounds.p1 = Vec2FromVec(dst_dims);
result.font_size = font_size;
result.font_ascent = font_ascent;
result.font_descent = font_descent;
result.font_cap = font_cap;
result.image_dims = dst_dims;
// //- Create face result.image_pixels = dst_pixels;
// IDWriteFontFace *font_face = 0; }
// error = IDWriteFactory5_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &font_file, 0, DWRITE_FONT_SIMULATIONS_NONE, &font_face); return result;
// //- Setup rendering params
// IDWriteRenderingParams *default_rendering_params = 0;
// error = IDWriteFactory5_CreateRenderingParams(factory, &default_rendering_params);
// IDWriteRenderingParams *rendering_params = 0;
// FLOAT gamma = IDWriteRenderingParams_GetGamma(default_rendering_params);
// FLOAT enhanced_contrast = IDWriteRenderingParams_GetEnhancedContrast(default_rendering_params);
// FLOAT clear_type_level = IDWriteRenderingParams_GetClearTypeLevel(default_rendering_params);
// error = IDWriteFactory5_CreateCustomRenderingParams(factory, gamma,
// enhanced_contrast,
// clear_type_level,
// DWRITE_PIXEL_GEOMETRY_FLAT,
// DWRITE_RENDERING_MODE_DEFAULT,
// &rendering_params);
// //- Setup interop
// IDWriteGdiInterop *dwrite_gdi_interop = 0;
// error = IDWriteFactory5_GetGdiInterop(factory, &dwrite_gdi_interop);
// //- Get metrics
// DWRITE_FONT_METRICS metrics = ZI;
// IDWriteFontFace_GetMetrics(font_face, &metrics);
// u16 glyph_count = IDWriteFontFace_GetGlyphCount(font_face);
// f32 pixel_per_em = em_size * (TTF_DW_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);
// //- Setup render target
// IDWriteBitmapRenderTarget *render_target = 0;
// /* FIXME: errors when em_size too high */
// error = IDWriteGdiInterop_CreateBitmapRenderTarget(dwrite_gdi_interop, 0, (UINT32)raster_target_w, (UINT32)raster_target_h, &render_target);
// IDWriteBitmapRenderTarget_SetPixelsPerDip(render_target, 1.0);
// /* Clear the render target */
// HDC dc = 0;
// {
// dc = IDWriteBitmapRenderTarget_GetMemoryDC(render_target);
// 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);
// }
// //- Setup atlas
// /* Acquire font memory */
// TTF_Glyph *glyphs = (TTF_Glyph *)PushStructs(arena, TTF_Glyph, glyph_count);
// /* Acquire (starting) atlas memory
// * NOTE: This is unnecessary since atlas memory will grow anyway. Could
// * just start w/ atlas height 0.
// */
// u64 atlas_w = 1024;
// u64 atlas_h = 1;
// u32 *atlas_memory = PushStructs(arena, u32, atlas_w * atlas_h);
// i32 ascent = 0;
// i32 descent = 0;
// i32 cap = 0;
// //- Fill 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 render target
// DWRITE_GLYPH_RUN glyph_run = ZI;
// glyph_run.fontFace = font_face;
// glyph_run.fontEmSize = pixel_per_em;
// glyph_run.glyphCount = 1;
// glyph_run.glyphIndices = &i;
// RECT bounding_box = ZI;
// error = IDWriteBitmapRenderTarget_DrawGlyphRun(render_target,
// 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 = ZI;
// error = IDWriteFontFace_GetDesignGlyphMetrics(font_face, &i, 1, &glyph_metrics, 0);
// ascent = metrics.ascent * pixel_per_design_unit;
// descent = metrics.descent * pixel_per_design_unit;
// cap = metrics.capHeight * pixel_per_design_unit;
// f32 off_x = (f32)bounding_box.left - raster_target_x;
// f32 off_y = (f32)bounding_box.top - raster_target_y;
// i32 tex_w = bounding_box.right - bounding_box.left;
// i32 tex_h = bounding_box.bottom - bounding_box.top;
// f32 advance = CeilF32ToI32((f32)glyph_metrics.advanceWidth * pixel_per_design_unit);
// TTF_Glyph *glyph = &glyphs[i];
// glyph->baseline_offset = VEC2(off_x, off_y);
// glyph->advance = advance;
// /* Get the bitmap */
// HBITMAP bitmap = (HBITMAP)GetCurrentObject(dc, OBJ_BITMAP);
// DIBSECTION dib = ZI;
// 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) */
// PushStructs(arena, u32, diff * atlas_w);
// atlas_h += diff;
// }
// /* Set bounding box metrics (now that we know atlas x & y) */
// glyph->atlas_p0 = VEC2I32(out_offset_x, out_offset_y);
// glyph->atlas_p1 = VEC2I32(out_offset_x + tex_w, out_offset_y + tex_h);
// //- Fill atlas
// u64 in_pitch = (u64)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 = (u64)bounding_box.top + y;
// for (i32 x = 0; x < tex_w; ++x)
// {
// u64 out_x = out_offset_x + x;
// u64 in_x = (u64)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 = 0x00FFFFFF | ((*in_pixel & 0xFF) << 24);
// }
// }
// out_offset_x += tex_w;
// /* Grow row height */
// if ((u32)tex_h > row_height)
// {
// row_height = (u32)tex_h;
// }
// //- Clear 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
// u16 *cache_indices = 0;
// if (cache_codes_count > 0)
// {
// cache_indices = PushStructs(arena, u16, cache_codes_count);
// IDWriteFontFace_GetGlyphIndices(font_face, cache_codes, cache_codes_count, cache_indices);
// }
// //- Release
// /* FIXME: Check for leaks */
// IDWriteGdiInterop_Release(dwrite_gdi_interop);
// IDWriteRenderingParams_Release(rendering_params);
// IDWriteRenderingParams_Release(default_rendering_params);
// // NOTE FROM ALLEN: We don't release font face because we intend to keep the font face around after the baking process
// // IDWriteFontFace_Release(font_face);
// IDWriteFontFile_Release(font_file);
// //loader->Release();
// IDWriteFactory5_Release(factory);
// /* Return */
// TTF_Decoded result = ZI;
// result.glyphs = glyphs;
// result.glyphs_count = glyph_count;
// result.cache_indices = cache_indices;
// result.image_width = (u32)atlas_w;
// result.image_height = (u32)atlas_h;
// result.image_pixels = (u32 *)atlas_memory;
// result.ascent = ascent;
// result.descent = descent;
// result.cap = cap;
// return result;
} }
// /* Based on Allen Webster's dwrite rasterizer example -
// * https://github.com/4th-dimention/examps */
// extern TTF_DW_Ctx TTF_DW = ZI;
// ////////////////////////////////////////////////////////////
// //~ @hookimpl Bootstrap
// void TTF_Bootstrap(void)
// {
// TTF_DW_SharedState *g = &TTF_DW_shared_state;
// 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) */
// HRESULT error = DWriteCreateFactory(
// DWRITE_FACTORY_TYPE_SHARED,
// &IID_IDWriteFactory5,
// (void **)&g->factory
// );
// if (!SUCCEEDED(error))
// {
// Panic(Lit("Error creating DWrite factory"));
// (*(volatile int *)0) = 0;
// }
// }
// ////////////////////////////////////////////////////////////
// //~ @hookimpl Decode
// TTF_Decoded TTF_Decode(Arena *arena, String encoded, f32 em_size, u32 *cache_codes, u32 cache_codes_count)
// {
// TTF_DW_SharedState *g = &TTF_DW_shared_state;
// COLORREF bg_color = 0xFF000000;
// COLORREF fg_color = 0xFFFFFFFF;
// IDWriteFactory5 *factory = g->factory;
// /* TODO: handle errors */
// HRESULT error = 0;
// /* File */
// IDWriteFontFile *font_file = 0;
// {
// /* Create in memory loader */
// IDWriteInMemoryFontFileLoader *loader = 0;
// error = IDWriteFactory5_CreateInMemoryFontFileLoader(factory, &loader);
// error = IDWriteFactory5_RegisterFontFileLoader(factory, (IDWriteFontFileLoader *)loader);
// IDWriteFontSetBuilder1 *builder = 0;
// error = IDWriteFactory5_CreateFontSetBuilder1(factory, &builder);
// error = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(loader, (IDWriteFactory *)factory, encoded.text, (u32)encoded.len, 0, &font_file);
// error = IDWriteFontSetBuilder1_AddFontFile(builder, font_file);
// }
// //- Create face
// IDWriteFontFace *font_face = 0;
// error = IDWriteFactory5_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &font_file, 0, DWRITE_FONT_SIMULATIONS_NONE, &font_face);
// //- Setup rendering params
// IDWriteRenderingParams *default_rendering_params = 0;
// error = IDWriteFactory5_CreateRenderingParams(factory, &default_rendering_params);
// IDWriteRenderingParams *rendering_params = 0;
// FLOAT gamma = IDWriteRenderingParams_GetGamma(default_rendering_params);
// FLOAT enhanced_contrast = IDWriteRenderingParams_GetEnhancedContrast(default_rendering_params);
// FLOAT clear_type_level = IDWriteRenderingParams_GetClearTypeLevel(default_rendering_params);
// error = IDWriteFactory5_CreateCustomRenderingParams(factory, gamma,
// enhanced_contrast,
// clear_type_level,
// DWRITE_PIXEL_GEOMETRY_FLAT,
// DWRITE_RENDERING_MODE_DEFAULT,
// &rendering_params);
// //- Setup interop
// IDWriteGdiInterop *dwrite_gdi_interop = 0;
// error = IDWriteFactory5_GetGdiInterop(factory, &dwrite_gdi_interop);
// //- Get metrics
// DWRITE_FONT_METRICS metrics = ZI;
// IDWriteFontFace_GetMetrics(font_face, &metrics);
// u16 glyph_count = IDWriteFontFace_GetGlyphCount(font_face);
// f32 pixel_per_em = em_size * (TTF_DW_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);
// //- Setup render target
// IDWriteBitmapRenderTarget *render_target = 0;
// /* FIXME: errors when em_size too high */
// error = IDWriteGdiInterop_CreateBitmapRenderTarget(dwrite_gdi_interop, 0, (UINT32)raster_target_w, (UINT32)raster_target_h, &render_target);
// IDWriteBitmapRenderTarget_SetPixelsPerDip(render_target, 1.0);
// /* Clear the render target */
// HDC dc = 0;
// {
// dc = IDWriteBitmapRenderTarget_GetMemoryDC(render_target);
// 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);
// }
// //- Setup atlas
// /* Acquire font memory */
// TTF_Glyph *glyphs = (TTF_Glyph *)PushStructs(arena, TTF_Glyph, glyph_count);
// /* Acquire (starting) atlas memory
// * NOTE: This is unnecessary since atlas memory will grow anyway. Could
// * just start w/ atlas height 0.
// */
// u64 atlas_w = 1024;
// u64 atlas_h = 1;
// u32 *atlas_memory = PushStructs(arena, u32, atlas_w * atlas_h);
// i32 ascent = 0;
// i32 descent = 0;
// i32 cap = 0;
// //- Fill 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 render target
// DWRITE_GLYPH_RUN glyph_run = ZI;
// glyph_run.fontFace = font_face;
// glyph_run.fontEmSize = pixel_per_em;
// glyph_run.glyphCount = 1;
// glyph_run.glyphIndices = &i;
// RECT bounding_box = ZI;
// error = IDWriteBitmapRenderTarget_DrawGlyphRun(render_target,
// 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 = ZI;
// error = IDWriteFontFace_GetDesignGlyphMetrics(font_face, &i, 1, &glyph_metrics, 0);
// ascent = metrics.ascent * pixel_per_design_unit;
// descent = metrics.descent * pixel_per_design_unit;
// cap = metrics.capHeight * pixel_per_design_unit;
// f32 off_x = (f32)bounding_box.left - raster_target_x;
// f32 off_y = (f32)bounding_box.top - raster_target_y;
// i32 tex_w = bounding_box.right - bounding_box.left;
// i32 tex_h = bounding_box.bottom - bounding_box.top;
// f32 advance = CeilF32ToI32((f32)glyph_metrics.advanceWidth * pixel_per_design_unit);
// TTF_Glyph *glyph = &glyphs[i];
// glyph->baseline_offset = VEC2(off_x, off_y);
// glyph->advance = advance;
// /* Get the bitmap */
// HBITMAP bitmap = (HBITMAP)GetCurrentObject(dc, OBJ_BITMAP);
// DIBSECTION dib = ZI;
// 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) */
// PushStructs(arena, u32, diff * atlas_w);
// atlas_h += diff;
// }
// /* Set bounding box metrics (now that we know atlas x & y) */
// glyph->atlas_p0 = VEC2I32(out_offset_x, out_offset_y);
// glyph->atlas_p1 = VEC2I32(out_offset_x + tex_w, out_offset_y + tex_h);
// //- Fill atlas
// u64 in_pitch = (u64)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 = (u64)bounding_box.top + y;
// for (i32 x = 0; x < tex_w; ++x)
// {
// u64 out_x = out_offset_x + x;
// u64 in_x = (u64)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 = 0x00FFFFFF | ((*in_pixel & 0xFF) << 24);
// }
// }
// out_offset_x += tex_w;
// /* Grow row height */
// if ((u32)tex_h > row_height)
// {
// row_height = (u32)tex_h;
// }
// //- Clear 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
// u16 *cache_indices = 0;
// if (cache_codes_count > 0)
// {
// cache_indices = PushStructs(arena, u16, cache_codes_count);
// IDWriteFontFace_GetGlyphIndices(font_face, cache_codes, cache_codes_count, cache_indices);
// }
// //- Release
// /* FIXME: Check for leaks */
// IDWriteGdiInterop_Release(dwrite_gdi_interop);
// IDWriteRenderingParams_Release(rendering_params);
// IDWriteRenderingParams_Release(default_rendering_params);
// // NOTE FROM ALLEN: We don't release font face because we intend to keep the font face around after the baking process
// // IDWriteFontFace_Release(font_face);
// IDWriteFontFile_Release(font_file);
// //loader->Release();
// IDWriteFactory5_Release(factory);
// /* Return */
// TTF_Decoded result = ZI;
// result.glyphs = glyphs;
// result.glyphs_count = glyph_count;
// result.cache_indices = cache_indices;
// result.image_width = (u32)atlas_w;
// result.image_height = (u32)atlas_h;
// result.image_pixels = (u32 *)atlas_memory;
// result.ascent = ascent;
// result.descent = descent;
// result.cap = cap;
// return result;
// }

View File

@ -1350,11 +1350,13 @@ void UI_EndFrame(UI_Frame *frame)
if (glyph_dims.x != 0 || glyph_dims.y != 0) if (glyph_dims.x != 0 || glyph_dims.y != 0)
{ {
UI_DRect *rect = PushStruct(frame->rects_arena, UI_DRect); UI_DRect *rect = PushStruct(frame->rects_arena, UI_DRect);
rect->bounds = AddRng2Vec2(rr.bounds, baseline);
rect->debug_lin = LinearFromSrgb(box->desc.debug_color); rect->debug_lin = LinearFromSrgb(box->desc.debug_color);
rect->tint_lin = LinearFromSrgb(box->desc.tint); rect->tint_lin = LinearFromSrgb(box->desc.tint);
rect->tex = rr.tex; rect->tex = rr.tex;
rect->tex_slice_uv = rr.tex_uv; rect->tex_slice_uv = rr.tex_slice_uv;
rect->bounds = rr.bounds;
rect->bounds = AddRng2Vec2(rect->bounds, baseline);
rect->bounds = AddRng2Vec2(rect->bounds, VEC2(rr.baseline_pos, 0));
} }
} }
} }