298 lines
10 KiB
C
298 lines
10 KiB
C
/* TODO: Use default font texture handle */
|
|
Readonly GC_RunRect GC_NilRunRect = {
|
|
0
|
|
};
|
|
|
|
Readonly GC_Run GC_NilRun = {
|
|
.count = 1,
|
|
.rects = &GC_NilRunRect
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Key helpers
|
|
|
|
GC_FontKey GC_FontKeyFromResource(ResourceKey resource)
|
|
{
|
|
GC_FontKey result = ZI;
|
|
result.v = resource.v;
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Run
|
|
|
|
GC_Run *GC_RunFromString(Arena *arena, GC_FontKey key, String str)
|
|
{
|
|
/* TODO */
|
|
GC_Run *result = 0;
|
|
|
|
GC_RunRect *rr = PushStruct(arena, GC_RunRect);
|
|
rr->advance = 1;
|
|
result->rects = rr;
|
|
result->count = 1;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ////////////////////////////////////////////////////////////
|
|
// //~ 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 operations
|
|
|
|
// /* 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 operations
|
|
|
|
// 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;
|
|
// }
|