text layouting
This commit is contained in:
parent
ee1f720fa1
commit
56fd5e19ff
@ -257,7 +257,7 @@ i64 LerpI64(i64 val0, i64 val1, f64 t);
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Vec2 operations
|
//~ Vec2 operations
|
||||||
|
|
||||||
#define Vec2FromVec2I32(v) VEC2((v).x, (v).y)
|
#define Vec2FromVec(v) VEC2((v).x, (v).y)
|
||||||
|
|
||||||
b32 IsVec2Zero(Vec2 a);
|
b32 IsVec2Zero(Vec2 a);
|
||||||
b32 EqVec2(Vec2 a, Vec2 b);
|
b32 EqVec2(Vec2 a, Vec2 b);
|
||||||
|
|||||||
@ -52,6 +52,20 @@ Vec4 LinearFromSrgbU32(u32 srgb32)
|
|||||||
return LinearFromSrgbVec4(Vec4NormFromU32(srgb32));
|
return LinearFromSrgbVec4(Vec4NormFromU32(srgb32));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//~ Vertex ID helpers
|
||||||
|
|
||||||
|
Vec2 RectUvFromVertexId(u32 id)
|
||||||
|
{
|
||||||
|
static const Vec2 uvs[4] = {
|
||||||
|
Vec2(0, 0),
|
||||||
|
Vec2(1, 0),
|
||||||
|
Vec2(1, 1),
|
||||||
|
Vec2(0, 1)
|
||||||
|
};
|
||||||
|
return uvs[id];
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Ndc helpers
|
//~ Ndc helpers
|
||||||
|
|
||||||
|
|||||||
@ -130,6 +130,8 @@ JobDef(F_Load, sig, _)
|
|||||||
font->image_height = decoded.image_height;
|
font->image_height = decoded.image_height;
|
||||||
font->glyphs_count = decoded.glyphs_count;
|
font->glyphs_count = decoded.glyphs_count;
|
||||||
font->point_size = point_size;
|
font->point_size = point_size;
|
||||||
|
font->ascent = decoded.ascent;
|
||||||
|
font->descent = decoded.descent;
|
||||||
|
|
||||||
/* FIXME: Load baked font instead of panicking */
|
/* FIXME: Load baked font instead of panicking */
|
||||||
if (font->glyphs_count <= 0)
|
if (font->glyphs_count <= 0)
|
||||||
@ -140,7 +142,8 @@ JobDef(F_Load, sig, _)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Copy glyphs from decode decoded */
|
/* Copy glyphs from decode decoded */
|
||||||
StaticAssert(sizeof(*font->glyphs) == sizeof(*decoded.glyphs)); /* Font glyph size must match TTF glyph size for memcpy */
|
/* 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);
|
CopyBytes(font->glyphs, decoded.glyphs, sizeof(*font->glyphs) * decoded.glyphs_count);
|
||||||
|
|
||||||
/* Build lookup table */
|
/* Build lookup table */
|
||||||
@ -237,19 +240,86 @@ F_Glyph F_GlyphFromCodepoint(F_Font *font, u32 codepoint)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
F_GlyphRun F_GlyphRunFromString(Arena *arena, F_Font *font, String str)
|
F_Run F_RunFromString(Arena *arena, F_Font *font, String str)
|
||||||
{
|
{
|
||||||
F_GlyphRun result = ZI;
|
F_Run result = ZI;
|
||||||
result.glyphs = PushDry(arena, F_Glyph);
|
result.rects = PushDry(arena, F_RunRect);
|
||||||
|
|
||||||
for (CodepointIter it = InitCodepointIter(str); NextCodepoint(&it);)
|
for (CodepointIter it = InitCodepointIter(str); NextCodepoint(&it);)
|
||||||
{
|
{
|
||||||
u32 codepoint = it.codepoint;
|
u32 codepoint = it.codepoint;
|
||||||
u16 index = font->lookup[codepoint];
|
u16 index = font->lookup[codepoint];
|
||||||
F_Glyph glyph = font->glyphs[index];
|
F_Glyph glyph = font->glyphs[index];
|
||||||
*PushStructNoZero(arena, F_Glyph) = glyph;
|
F_RunRect *rect = PushStruct(arena, F_RunRect);
|
||||||
++result.count;
|
++result.count;
|
||||||
result.width += glyph.advance;
|
|
||||||
result.height = MaxF32(result.height, glyph.height);
|
rect->atlas_p0 = glyph.atlas_p0;
|
||||||
|
rect->atlas_p1 = glyph.atlas_p1;
|
||||||
|
Vec2I32 size = SubVec2I32(glyph.atlas_p1, glyph.atlas_p0);
|
||||||
|
|
||||||
|
rect->baseline_start_offset = glyph.baseline_offset;
|
||||||
|
rect->baseline_start_offset.x += result.baseline_length;
|
||||||
|
|
||||||
|
result.p0.x = MinF32(result.p0.x, rect->baseline_start_offset.x); /* Left run bounds */
|
||||||
|
result.p1.x = MaxF32(result.p1.x, rect->baseline_start_offset.x + size.x); /* Right run bounds */
|
||||||
|
result.p0.y = MinF32(result.p0.y, rect->baseline_start_offset.y); /* Top run bounds */
|
||||||
|
result.p1.y = MaxF32(result.p1.y, rect->baseline_start_offset.y + size.y); /* Bottom run bounds */
|
||||||
|
|
||||||
|
result.baseline_length += glyph.advance;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
F_Run result = ZI;
|
||||||
|
result.rects = PushDry(arena, F_RunRect);
|
||||||
|
|
||||||
|
f32 left = 0;
|
||||||
|
f32 right = 0;
|
||||||
|
f32 width = 0;
|
||||||
|
f32 top = 0;
|
||||||
|
f32 bottom = 0;
|
||||||
|
|
||||||
|
f32 baseline_cursor = 0;
|
||||||
|
f32 baseline_depth = 0;
|
||||||
|
for (CodepointIter it = InitCodepointIter(str); NextCodepoint(&it);)
|
||||||
|
{
|
||||||
|
u32 codepoint = it.codepoint;
|
||||||
|
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);
|
||||||
|
|
||||||
|
f32 offset_x = glyph.baseline_offset.x;
|
||||||
|
f32 offset_y = glyph.baseline_offset.y;
|
||||||
|
|
||||||
|
rect->pos.x = baseline_cursor + offset_x;
|
||||||
|
|
||||||
|
/* NOTE: Actual Y position gets calculated in second pass after baseline depth is determined */
|
||||||
|
rect->pos.y = offset_y;
|
||||||
|
baseline_depth = MaxF32(baseline_depth, -offset_y);
|
||||||
|
|
||||||
|
left = MinF32(left, rect->pos.x);
|
||||||
|
top = MinF32(top, offset_y);
|
||||||
|
right = MaxF32(right, rect->pos.x + size.x);
|
||||||
|
bottom = MaxF32(bottom, rect->pos.y + size.y);
|
||||||
|
|
||||||
|
baseline_cursor += glyph.advance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjust rect Y positions so they're relative to top of run */
|
||||||
|
for (u32 i = 0; i < result.count; ++i)
|
||||||
|
{
|
||||||
|
F_RunRect *rect = &result.rects[i];
|
||||||
|
rect->pos.y += baseline_depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.size = VEC2(right - left, bottom - top);
|
||||||
|
result.baseline_depth = baseline_depth;
|
||||||
|
return result;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,20 +5,10 @@
|
|||||||
|
|
||||||
Struct(F_Glyph)
|
Struct(F_Glyph)
|
||||||
{
|
{
|
||||||
f32 off_x;
|
|
||||||
f32 off_y;
|
|
||||||
f32 width;
|
|
||||||
f32 height;
|
|
||||||
i32 advance;
|
i32 advance;
|
||||||
Rect atlas_rect;
|
Vec2 baseline_offset;
|
||||||
};
|
Vec2I32 atlas_p0;
|
||||||
|
Vec2I32 atlas_p1;
|
||||||
Struct(F_GlyphRun)
|
|
||||||
{
|
|
||||||
f32 width;
|
|
||||||
f32 height;
|
|
||||||
u64 count;
|
|
||||||
F_Glyph *glyphs;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(F_Font)
|
Struct(F_Font)
|
||||||
@ -26,10 +16,33 @@ Struct(F_Font)
|
|||||||
GPU_Resource *texture;
|
GPU_Resource *texture;
|
||||||
u32 image_width;
|
u32 image_width;
|
||||||
u32 image_height;
|
u32 image_height;
|
||||||
f32 point_size;
|
|
||||||
u16 glyphs_count;
|
u16 glyphs_count;
|
||||||
F_Glyph *glyphs;
|
F_Glyph *glyphs;
|
||||||
u16 *lookup;
|
u16 *lookup;
|
||||||
|
|
||||||
|
/* Metrics */
|
||||||
|
f32 point_size;
|
||||||
|
f32 ascent;
|
||||||
|
f32 descent;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//~ Run types
|
||||||
|
|
||||||
|
Struct(F_RunRect)
|
||||||
|
{
|
||||||
|
Vec2 baseline_start_offset; /* Vector from start of baseline to top left of rect */
|
||||||
|
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 */
|
||||||
|
f32 baseline_length;
|
||||||
|
u32 count;
|
||||||
|
F_RunRect *rects;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
@ -45,7 +58,7 @@ F_Font *F_LoadFontAsync(Resource resource, f32 point_size);
|
|||||||
F_Font *F_LoadFontWait(Resource resource, f32 point_size);
|
F_Font *F_LoadFontWait(Resource resource, f32 point_size);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Font data operations
|
//~ Run operations
|
||||||
|
|
||||||
F_Glyph F_GlyphFromCodepoint(F_Font *font, u32 codepoint);
|
F_Glyph F_GlyphFromCodepoint(F_Font *font, u32 codepoint);
|
||||||
F_GlyphRun F_GlyphRunFromString(Arena *arena, F_Font *font, String str);
|
F_Run F_RunFromString(Arena *arena, F_Font *font, String str);
|
||||||
|
|||||||
87
src/pp/pp.c
87
src/pp/pp.c
@ -59,7 +59,19 @@ ExitFuncDef(ShutdownUser)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Debug draw
|
//~ Ui helpers
|
||||||
|
|
||||||
|
//- Ui style
|
||||||
|
void PushGameUiStyle(void)
|
||||||
|
{
|
||||||
|
// UI_Push(FontSize, 48);
|
||||||
|
UI_Push(FontSize, 24);
|
||||||
|
// UI_Push(FontSize, 12);
|
||||||
|
|
||||||
|
UI_Push(TextPadding, 12);
|
||||||
|
// UI_Push(Border, 1);
|
||||||
|
// UI_Push(BorderColor, Rgba32F(1, 0, 1, 0.4));
|
||||||
|
}
|
||||||
|
|
||||||
//- Draw xform
|
//- Draw xform
|
||||||
void DrawDebugXform(Xform xf, u32 color_x, u32 color_y)
|
void DrawDebugXform(Xform xf, u32 color_x, u32 color_y)
|
||||||
@ -451,6 +463,7 @@ void UpdateUser(P_Window *window)
|
|||||||
|
|
||||||
//- Begin UI
|
//- Begin UI
|
||||||
UI_BeginBuild();
|
UI_BeginBuild();
|
||||||
|
PushGameUiStyle();
|
||||||
UI_Box *pp_root_box = UI_BuildBox(UI_BoxFlag_DrawImage, UI_NilKey);
|
UI_Box *pp_root_box = UI_BuildBox(UI_BoxFlag_DrawImage, UI_NilKey);
|
||||||
UI_Push(Parent, pp_root_box);
|
UI_Push(Parent, pp_root_box);
|
||||||
|
|
||||||
@ -1224,8 +1237,8 @@ void UpdateUser(P_Window *window)
|
|||||||
mat->xf = sprite_xform;
|
mat->xf = sprite_xform;
|
||||||
mat->tex = GPU_Texture2DRidFromResource(texture->gpu_texture);
|
mat->tex = GPU_Texture2DRidFromResource(texture->gpu_texture);
|
||||||
mat->tint_srgb = tint;
|
mat->tint_srgb = tint;
|
||||||
mat->uv0 = frame.clip.p0;
|
mat->tex_uv0 = frame.clip.p0;
|
||||||
mat->uv1 = frame.clip.p1;
|
mat->tex_uv1 = frame.clip.p1;
|
||||||
mat->is_light = is_light;
|
mat->is_light = is_light;
|
||||||
mat->light_emittance_srgb = emittance;
|
mat->light_emittance_srgb = emittance;
|
||||||
}
|
}
|
||||||
@ -1999,8 +2012,6 @@ void UpdateUser(P_Window *window)
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Debug draw
|
//- Debug draw
|
||||||
|
|
||||||
|
|
||||||
//~ Draw global debug info
|
|
||||||
/* FIXME: Enable this */
|
/* FIXME: Enable this */
|
||||||
#if 1
|
#if 1
|
||||||
#if 1
|
#if 1
|
||||||
@ -2015,90 +2026,93 @@ void UpdateUser(P_Window *window)
|
|||||||
UI_Push(Parent, dbg_box);
|
UI_Push(Parent, dbg_box);
|
||||||
UI_Push(Width, UI_TextSize(0));
|
UI_Push(Width, UI_TextSize(0));
|
||||||
UI_Push(Height, UI_TextSize(0));
|
UI_Push(Height, UI_TextSize(0));
|
||||||
UI_Push(BackgroundColor, Rgba32F(0.3, 0.3, 0.3, 1));
|
UI_Push(BackgroundColor, Rgba32F(0.3, 0.6, 0.3, 0.5));
|
||||||
|
|
||||||
|
UI_BuildLabelF("ytest string");
|
||||||
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
UI_BuildLabelF("blended world entities: %F/%F", FmtUint(g->ss_blended->num_ents_allocated), FmtUint(g->ss_blended->num_ents_reserved));
|
UI_BuildLabelF("blended world entities: %F/%F", FmtUint(g->ss_blended->num_ents_allocated), FmtUint(g->ss_blended->num_ents_reserved));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
UI_BuildLabelF("blended world tick: %F", FmtUint(g->ss_blended->tick));
|
UI_BuildLabelF("blended world tick: %F", FmtUint(g->ss_blended->tick));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
UI_BuildLabelF("blended world time: %F", FmtFloat(SecondsFromNs(g->ss_blended->sim_time_ns)));
|
UI_BuildLabelF("blended world time: %F", FmtFloat(SecondsFromNs(g->ss_blended->sim_time_ns)));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
UI_BuildLabelF("average local sim publish dt: %F", FmtFloat(SecondsFromNs(g->average_local_to_user_snapshot_publish_dt_ns)));
|
UI_BuildLabelF("average local sim publish dt: %F", FmtFloat(SecondsFromNs(g->average_local_to_user_snapshot_publish_dt_ns)));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
UI_BuildLabelF("local sim last known tick: %F", FmtUint(g->local_sim_last_known_tick));
|
UI_BuildLabelF("local sim last known tick: %F", FmtUint(g->local_sim_last_known_tick));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
UI_BuildLabelF("local sim last known time: %F", FmtFloat(SecondsFromNs(g->local_sim_last_known_time_ns)));
|
UI_BuildLabelF("local sim last known time: %F", FmtFloat(SecondsFromNs(g->local_sim_last_known_time_ns)));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
UI_BuildLabelF("local sim predicted time: %F", FmtFloat(SecondsFromNs(g->local_sim_predicted_time_ns)));
|
UI_BuildLabelF("local sim predicted time: %F", FmtFloat(SecondsFromNs(g->local_sim_predicted_time_ns)));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
UI_BuildLabelF("render time target: %F", FmtFloat(SecondsFromNs(g->render_time_target_ns)));
|
UI_BuildLabelF("render time target: %F", FmtFloat(SecondsFromNs(g->render_time_target_ns)));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
UI_BuildLabelF("render time: %F", FmtFloat(SecondsFromNs(g->render_time_ns)));
|
UI_BuildLabelF("render time: %F", FmtFloat(SecondsFromNs(g->render_time_ns)));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
UI_BuildLabelF("local player: [%F]", FmtUid(local_player->id.uid));
|
UI_BuildLabelF("local player: [%F]", FmtUid(local_player->id.uid));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
Vec2 world_cursor = g->world_cursor;
|
Vec2 world_cursor = g->world_cursor;
|
||||||
UI_BuildLabelF("cursor world: %F, %F", FmtFloat(world_cursor.x), FmtFloat(world_cursor.y));
|
UI_BuildLabelF("cursor world: %F, %F", FmtFloat(world_cursor.x), FmtFloat(world_cursor.y));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
Vec2I32 world_tile_cursor = WorldTileIndexFromPos(world_cursor);
|
Vec2I32 world_tile_cursor = WorldTileIndexFromPos(world_cursor);
|
||||||
UI_BuildLabelF("cursor world tile: %F, %F", FmtSint(world_tile_cursor.x), FmtSint(world_tile_cursor.y));
|
UI_BuildLabelF("cursor world tile: %F, %F", FmtSint(world_tile_cursor.x), FmtSint(world_tile_cursor.y));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
Vec2I32 local_tile_cursor = LocalTileIndexFromWorldTileIndex(world_tile_cursor);
|
Vec2I32 local_tile_cursor = LocalTileIndexFromWorldTileIndex(world_tile_cursor);
|
||||||
UI_BuildLabelF("cursor local tile: %F, %F", FmtSint(local_tile_cursor.x), FmtSint(local_tile_cursor.y));
|
UI_BuildLabelF("cursor local tile: %F, %F", FmtSint(local_tile_cursor.x), FmtSint(local_tile_cursor.y));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
Vec2I32 tile_chunk_cursor = TileChunkIndexFromWorldTileIndex(world_tile_cursor);
|
Vec2I32 tile_chunk_cursor = TileChunkIndexFromWorldTileIndex(world_tile_cursor);
|
||||||
UI_BuildLabelF("cursor tile chunk: %F, %F", FmtSint(tile_chunk_cursor.x), FmtSint(tile_chunk_cursor.y));
|
UI_BuildLabelF("cursor tile chunk: %F, %F", FmtSint(tile_chunk_cursor.x), FmtSint(tile_chunk_cursor.y));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
UI_BuildLabelF("Network read: %F mbit/s", FmtFloat((f64)g->net_bytes_read.last_second * 8 / 1000 / 1000));
|
UI_BuildLabelF("Network read: %F mbit/s", FmtFloat((f64)g->net_bytes_read.last_second * 8 / 1000 / 1000));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
UI_BuildLabelF("Network write: %F mbit/s", FmtFloat((f64)g->net_bytes_sent.last_second * 8 / 1000 / 1000));
|
UI_BuildLabelF("Network write: %F mbit/s", FmtFloat((f64)g->net_bytes_sent.last_second * 8 / 1000 / 1000));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
UI_BuildLabelF("Ping (real): %F ms", FmtFloat(SecondsFromNs(local_player->player_last_rtt_ns) * 1000));
|
UI_BuildLabelF("Ping (real): %F ms", FmtFloat(SecondsFromNs(local_player->player_last_rtt_ns) * 1000));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
UI_BuildLabelF("Ping (average): %F ms", FmtFloat(local_player->player_average_rtt_seconds * 1000));
|
UI_BuildLabelF("Ping (average): %F ms", FmtFloat(local_player->player_average_rtt_seconds * 1000));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
UI_BuildLabelF("Memory committed: %F MiB", FmtFloat((f64)GetGstat(GSTAT_MEMORY_COMMITTED) / 1024 / 1024));
|
UI_BuildLabelF("Memory committed: %F MiB", FmtFloat((f64)GetGstat(GSTAT_MEMORY_COMMITTED) / 1024 / 1024));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
UI_BuildLabelF("Virtual memory reserved: %F TiB", FmtFloat((f64)GetGstat(GSTAT_MEMORY_RESERVED) / 1024 / 1024 / 1024 / 1024));
|
UI_BuildLabelF("Virtual memory reserved: %F TiB", FmtFloat((f64)GetGstat(GSTAT_MEMORY_RESERVED) / 1024 / 1024 / 1024 / 1024));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
UI_BuildLabelF("Arenas allocated: %F", FmtUint(GetGstat(GSTAT_NUM_ARENAS)));
|
UI_BuildLabelF("Arenas allocated: %F", FmtUint(GetGstat(GSTAT_NUM_ARENAS)));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
|
|
||||||
UI_BuildLabelF("Video memory (GPU): %F MiB", FmtFloat((f64)vram.local_used / 1024 / 1024));
|
UI_BuildLabelF("Video memory (GPU): %F MiB", FmtFloat((f64)vram.local_used / 1024 / 1024));
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
UI_BuildLabelF("Video memory (shared): %F MiB", FmtFloat((f64)vram.non_local_used / 1024 / 1024));
|
UI_BuildLabelF("Video memory (shared): %F MiB", FmtFloat((f64)vram.non_local_used / 1024 / 1024));
|
||||||
//UI_BuildLabelF(\n"));
|
//UI_BuildLabelF(\n"));
|
||||||
//UI_BuildLabelF(\n"));
|
//UI_BuildLabelF(\n"));
|
||||||
|
|
||||||
#if RtcIsEnabled
|
#if RtcIsEnabled
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
UI_BuildSeparator();
|
// UI_BuildSeparator();
|
||||||
UI_BuildLabelF("Debug steps: %F", FmtUint(GetGstat(GSTAT_DEBUG_STEPS)));
|
UI_BuildLabelF("Debug steps: %F", FmtUint(GetGstat(GSTAT_DEBUG_STEPS)));
|
||||||
//UI_BuildLabelF(\n"));
|
//UI_BuildLabelF(\n"));
|
||||||
|
|
||||||
@ -2552,6 +2566,7 @@ void UpdateUser(P_Window *window)
|
|||||||
|
|
||||||
/* Render UI */
|
/* Render UI */
|
||||||
UI_SetDisplayImage(pp_root_box, g->ui_target);
|
UI_SetDisplayImage(pp_root_box, g->ui_target);
|
||||||
|
// UI_SetDisplayImage(pp_root_box, F_LoadFontWait(UI_GetDefaultFontResource(), 12.0)->texture);
|
||||||
GPU_Resource *ui_render = UI_EndBuild(ui_viewport);
|
GPU_Resource *ui_render = UI_EndBuild(ui_viewport);
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
|||||||
@ -282,8 +282,9 @@ void StartupUser(void);
|
|||||||
ExitFuncDef(ShutdownUser);
|
ExitFuncDef(ShutdownUser);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Debug draw operations
|
//~ Ui helpers
|
||||||
|
|
||||||
|
void PushGameUiStyle(void);
|
||||||
void DrawDebugXform(Xform xf, u32 color_x, u32 color_y);
|
void DrawDebugXform(Xform xf, u32 color_x, u32 color_y);
|
||||||
void DrawDebugMovement(Entity *ent);
|
void DrawDebugMovement(Entity *ent);
|
||||||
String DebugStringFromEntity(Arena *arena, Entity *ent);
|
String DebugStringFromEntity(Arena *arena, Entity *ent);
|
||||||
|
|||||||
@ -13,7 +13,7 @@ Struct(MaterialPS_Input)
|
|||||||
Semantic(Vec4, sv_position);
|
Semantic(Vec4, sv_position);
|
||||||
Semantic(nointerpolation Texture2DRid, tex);
|
Semantic(nointerpolation Texture2DRid, tex);
|
||||||
Semantic(nointerpolation u32, grid_id);
|
Semantic(nointerpolation u32, grid_id);
|
||||||
Semantic(Vec2, uv);
|
Semantic(Vec2, tex_uv);
|
||||||
Semantic(Vec4, tint_lin);
|
Semantic(Vec4, tint_lin);
|
||||||
Semantic(Vec4, emittance_lin);
|
Semantic(Vec4, emittance_lin);
|
||||||
};
|
};
|
||||||
@ -29,24 +29,18 @@ Struct(MaterialPS_Output)
|
|||||||
MaterialPS_Input VSDef(MaterialVS, Semantic(u32, sv_instanceid), Semantic(u32, sv_vertexid))
|
MaterialPS_Input VSDef(MaterialVS, Semantic(u32, sv_instanceid), Semantic(u32, sv_vertexid))
|
||||||
{
|
{
|
||||||
ConstantBuffer<MaterialSig> sig = mat_sig;
|
ConstantBuffer<MaterialSig> sig = mat_sig;
|
||||||
static const Vec2 unit_quad_verts[4] = {
|
|
||||||
Vec2(-0.5f, -0.5f),
|
|
||||||
Vec2(0.5f, -0.5f),
|
|
||||||
Vec2(0.5f, 0.5f),
|
|
||||||
Vec2(-0.5f, 0.5f)
|
|
||||||
};
|
|
||||||
|
|
||||||
StructuredBuffer<MaterialInstance> instances = UniformResourceFromRid(sig.instances);
|
StructuredBuffer<MaterialInstance> instances = UniformResourceFromRid(sig.instances);
|
||||||
Vec2 vert = unit_quad_verts[sv_vertexid];
|
|
||||||
MaterialInstance instance = instances[sv_instanceid];
|
MaterialInstance instance = instances[sv_instanceid];
|
||||||
|
|
||||||
Vec2 world_pos = mul(instance.xf, Vec3(vert, 1)).xy;
|
Vec2 mat_uv = RectUvFromVertexId(sv_vertexid);
|
||||||
|
Vec2 mat_uv_centered = mat_uv - 0.5f;
|
||||||
|
Vec2 world_pos = mul(instance.xf, Vec3(mat_uv_centered, 1)).xy;
|
||||||
|
|
||||||
MaterialPS_Input result;
|
MaterialPS_Input result;
|
||||||
result.sv_position = mul(sig.projection, Vec4(world_pos, 0, 1));
|
result.sv_position = mul(sig.projection, Vec4(world_pos, 0, 1));
|
||||||
result.tex = instance.tex;
|
result.tex = instance.tex;
|
||||||
result.grid_id = instance.grid_id;
|
result.grid_id = instance.grid_id;
|
||||||
result.uv = instance.uv0 + ((vert + 0.5) * (instance.uv1 - instance.uv0));
|
result.tex_uv = lerp(instance.tex_uv0, instance.tex_uv1, mat_uv);
|
||||||
result.tint_lin = LinearFromSrgbU32(instance.tint_srgb);
|
result.tint_lin = LinearFromSrgbU32(instance.tint_srgb);
|
||||||
result.emittance_lin = LinearFromSrgbVec4(Vec4(instance.light_emittance_srgb, instance.is_light));
|
result.emittance_lin = LinearFromSrgbVec4(Vec4(instance.light_emittance_srgb, instance.is_light));
|
||||||
return result;
|
return result;
|
||||||
@ -66,7 +60,7 @@ MaterialPS_Output PSDef(MaterialPS, MaterialPS_Input input)
|
|||||||
{
|
{
|
||||||
SamplerState sampler = UniformSamplerFromRid(sig.sampler);
|
SamplerState sampler = UniformSamplerFromRid(sig.sampler);
|
||||||
Texture2D<Vec4> tex = NonUniformResourceFromRid(input.tex);
|
Texture2D<Vec4> tex = NonUniformResourceFromRid(input.tex);
|
||||||
albedo *= tex.Sample(sampler, input.uv);
|
albedo *= tex.Sample(sampler, input.tex_uv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Grid */
|
/* Grid */
|
||||||
@ -155,15 +149,15 @@ void CSDef(FloodCS, Semantic(Vec3U32, sv_dispatchthreadid))
|
|||||||
{
|
{
|
||||||
/* Flood */
|
/* Flood */
|
||||||
Vec2I32 read_coords[9] = {
|
Vec2I32 read_coords[9] = {
|
||||||
(Vec2I32)id + Vec2I32(-step_len, -step_len), /* top left */
|
(Vec2I32)id + Vec2I32(-step_len, -step_len), /* top left */
|
||||||
(Vec2I32)id + Vec2I32(0, -step_len), /* top center */
|
(Vec2I32)id + Vec2I32(0, -step_len), /* top center */
|
||||||
(Vec2I32)id + Vec2I32(+step_len, -step_len), /* top right */
|
(Vec2I32)id + Vec2I32(+step_len, -step_len), /* top right */
|
||||||
(Vec2I32)id + Vec2I32(-step_len, 0), /* center left */
|
(Vec2I32)id + Vec2I32(-step_len, 0), /* center left */
|
||||||
(Vec2I32)id + Vec2I32(0, 0), /* center center */
|
(Vec2I32)id + Vec2I32(0, 0), /* center center */
|
||||||
(Vec2I32)id + Vec2I32(+step_len, 0), /* center right */
|
(Vec2I32)id + Vec2I32(+step_len, 0), /* center right */
|
||||||
(Vec2I32)id + Vec2I32(-step_len, +step_len), /* bottom left */
|
(Vec2I32)id + Vec2I32(-step_len, +step_len), /* bottom left */
|
||||||
(Vec2I32)id + Vec2I32(0, +step_len), /* bottom center */
|
(Vec2I32)id + Vec2I32(0, +step_len), /* bottom center */
|
||||||
(Vec2I32)id + Vec2I32(+step_len, +step_len) /* bottom right */
|
(Vec2I32)id + Vec2I32(+step_len, +step_len), /* bottom right */
|
||||||
};
|
};
|
||||||
Vec2U32 closest_seed = Vec2U32(0xFFFF, 0xFFFF);
|
Vec2U32 closest_seed = Vec2U32(0xFFFF, 0xFFFF);
|
||||||
u32 closest_seed_len_sq = 0xFFFFFFFF;
|
u32 closest_seed_len_sq = 0xFFFFFFFF;
|
||||||
@ -300,7 +294,7 @@ void CSDef(ShadeCS, Semantic(Vec3U32, sv_dispatchthreadid))
|
|||||||
Struct(UiBlitPS_Input)
|
Struct(UiBlitPS_Input)
|
||||||
{
|
{
|
||||||
Semantic(Vec4, sv_position);
|
Semantic(Vec4, sv_position);
|
||||||
Semantic(Vec2, uv);
|
Semantic(Vec2, tex_uv);
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(UiBlitPS_Output)
|
Struct(UiBlitPS_Output)
|
||||||
@ -322,17 +316,12 @@ Vec3 ToneMap(Vec3 v)
|
|||||||
UiBlitPS_Input VSDef(UiBlitVS, Semantic(u32, sv_vertexid))
|
UiBlitPS_Input VSDef(UiBlitVS, Semantic(u32, sv_vertexid))
|
||||||
{
|
{
|
||||||
ConstantBuffer<UiBlitSig> sig = ui_blit_sig;
|
ConstantBuffer<UiBlitSig> sig = ui_blit_sig;
|
||||||
static const Vec2 unit_quad_verts[4] = {
|
Vec2 tex_uv = RectUvFromVertexId(sv_vertexid);
|
||||||
Vec2(-0.5f, -0.5f),
|
Vec2 tex_uv_centered = tex_uv - 0.5;
|
||||||
Vec2(0.5f, -0.5f),
|
|
||||||
Vec2(0.5f, 0.5f),
|
|
||||||
Vec2(-0.5f, 0.5f)
|
|
||||||
};
|
|
||||||
Vec2 vert = unit_quad_verts[sv_vertexid];
|
|
||||||
|
|
||||||
UiBlitPS_Input result;
|
UiBlitPS_Input result;
|
||||||
result.sv_position = mul(sig.projection, Vec4(vert, 0, 1));
|
result.sv_position = mul(sig.projection, Vec4(tex_uv_centered, 0, 1));
|
||||||
result.uv = vert + 0.5;
|
result.tex_uv = tex_uv;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,7 +334,7 @@ UiBlitPS_Output PSDef(UiBlitPS, UiBlitPS_Input input)
|
|||||||
|
|
||||||
UiBlitPS_Output result;
|
UiBlitPS_Output result;
|
||||||
Texture2D<Vec4> tex = UniformResourceFromRid(sig.src);
|
Texture2D<Vec4> tex = UniformResourceFromRid(sig.src);
|
||||||
Vec4 color = tex.Sample(sampler, input.uv);
|
Vec4 color = tex.Sample(sampler, input.tex_uv);
|
||||||
|
|
||||||
/* Apply tone map */
|
/* Apply tone map */
|
||||||
if (sig.flags & UiBlitFlag_ToneMap)
|
if (sig.flags & UiBlitFlag_ToneMap)
|
||||||
@ -372,7 +361,7 @@ Struct(UiRectPS_Input)
|
|||||||
{
|
{
|
||||||
Semantic(Vec4, sv_position);
|
Semantic(Vec4, sv_position);
|
||||||
Semantic(nointerpolation Texture2DRid, tex);
|
Semantic(nointerpolation Texture2DRid, tex);
|
||||||
Semantic(Vec2, uv);
|
Semantic(Vec2, tex_uv);
|
||||||
Semantic(Vec4, tint_srgb);
|
Semantic(Vec4, tint_srgb);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -386,22 +375,17 @@ Struct(UiRectPS_Output)
|
|||||||
UiRectPS_Input VSDef(UiRectVS, Semantic(u32, sv_instanceid), Semantic(u32, sv_vertexid))
|
UiRectPS_Input VSDef(UiRectVS, Semantic(u32, sv_instanceid), Semantic(u32, sv_vertexid))
|
||||||
{
|
{
|
||||||
ConstantBuffer<UiRectSig> sig = ui_rect_sig;
|
ConstantBuffer<UiRectSig> sig = ui_rect_sig;
|
||||||
static const Vec2 unit_quad_verts[4] = {
|
|
||||||
Vec2(-0.5f, -0.5f),
|
|
||||||
Vec2(0.5f, -0.5f),
|
|
||||||
Vec2(0.5f, 0.5f),
|
|
||||||
Vec2(-0.5f, 0.5f)
|
|
||||||
};
|
|
||||||
|
|
||||||
StructuredBuffer<UiRectInstance> instances = UniformResourceFromRid(sig.instances);
|
StructuredBuffer<UiRectInstance> instances = UniformResourceFromRid(sig.instances);
|
||||||
UiRectInstance instance = instances[sv_instanceid];
|
UiRectInstance instance = instances[sv_instanceid];
|
||||||
Vec2 vert = unit_quad_verts[sv_vertexid];
|
|
||||||
Vec2 world_pos = mul(instance.xf, Vec3(vert, 1)).xy;
|
Vec2 rect_uv = RectUvFromVertexId(sv_vertexid);
|
||||||
|
Vec2 rect_uv_centered = rect_uv - 0.5;
|
||||||
|
Vec2 world_pos = mul(instance.xf, Vec3(rect_uv_centered, 1)).xy;
|
||||||
|
|
||||||
UiRectPS_Input result;
|
UiRectPS_Input result;
|
||||||
result.sv_position = mul(sig.projection, Vec4(world_pos, 0, 1));
|
result.sv_position = mul(sig.projection, Vec4(world_pos, 0, 1));
|
||||||
result.tex = instance.tex;
|
result.tex = instance.tex;
|
||||||
result.uv = instance.uv0 + ((vert + 0.5) * (instance.uv1 - instance.uv0));
|
result.tex_uv = lerp(instance.tex_uv0, instance.tex_uv1, rect_uv);
|
||||||
result.tint_srgb = Vec4NormFromU32(instance.tint_srgb);
|
result.tint_srgb = Vec4NormFromU32(instance.tint_srgb);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -419,7 +403,7 @@ UiRectPS_Output PSDef(UiRectPS, UiRectPS_Input input)
|
|||||||
{
|
{
|
||||||
Texture2D<Vec4> tex = NonUniformResourceFromRid(input.tex);
|
Texture2D<Vec4> tex = NonUniformResourceFromRid(input.tex);
|
||||||
SamplerState sampler = UniformSamplerFromRid(sig.sampler);
|
SamplerState sampler = UniformSamplerFromRid(sig.sampler);
|
||||||
color *= tex.Sample(sampler, input.uv);
|
color *= tex.Sample(sampler, input.tex_uv);
|
||||||
}
|
}
|
||||||
|
|
||||||
result.sv_target0 = color;
|
result.sv_target0 = color;
|
||||||
|
|||||||
@ -19,8 +19,8 @@ Struct(MaterialInstance)
|
|||||||
Texture2DRid tex;
|
Texture2DRid tex;
|
||||||
u32 grid_id;
|
u32 grid_id;
|
||||||
Xform xf;
|
Xform xf;
|
||||||
Vec2 uv0;
|
Vec2 tex_uv0;
|
||||||
Vec2 uv1;
|
Vec2 tex_uv1;
|
||||||
u32 tint_srgb;
|
u32 tint_srgb;
|
||||||
u32 is_light;
|
u32 is_light;
|
||||||
Vec3 light_emittance_srgb;
|
Vec3 light_emittance_srgb;
|
||||||
@ -29,7 +29,7 @@ Struct(MaterialInstance)
|
|||||||
.tex = { U32Max }, \
|
.tex = { U32Max }, \
|
||||||
.grid_id = U32Max, \
|
.grid_id = U32Max, \
|
||||||
.xf = XformIdentity, \
|
.xf = XformIdentity, \
|
||||||
.uv1 = VEC2(1, 1), \
|
.tex_uv1 = VEC2(1, 1), \
|
||||||
.tint_srgb = Color_White, \
|
.tint_srgb = Color_White, \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,8 +149,8 @@ Struct(UiRectInstance)
|
|||||||
{
|
{
|
||||||
Texture2DRid tex;
|
Texture2DRid tex;
|
||||||
Xform xf;
|
Xform xf;
|
||||||
Vec2 uv0;
|
Vec2 tex_uv0;
|
||||||
Vec2 uv1;
|
Vec2 tex_uv1;
|
||||||
u32 tint_srgb;
|
u32 tint_srgb;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
Struct(TTF_Glyph)
|
Struct(TTF_Glyph)
|
||||||
{
|
{
|
||||||
f32 off_x;
|
|
||||||
f32 off_y;
|
|
||||||
f32 width;
|
|
||||||
f32 height;
|
|
||||||
i32 advance;
|
i32 advance;
|
||||||
Rect atlas_rect;
|
Vec2 baseline_offset;
|
||||||
|
Vec2I32 atlas_p0;
|
||||||
|
Vec2I32 atlas_p1;
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(TTF_Decoded)
|
Struct(TTF_Decoded)
|
||||||
@ -16,6 +14,11 @@ Struct(TTF_Decoded)
|
|||||||
u32 image_width;
|
u32 image_width;
|
||||||
u32 image_height;
|
u32 image_height;
|
||||||
u32 *image_pixels; /* Array of [width * height] pixels */
|
u32 *image_pixels; /* Array of [width * height] pixels */
|
||||||
|
|
||||||
|
/* Metrics */
|
||||||
|
f32 ascent;
|
||||||
|
f32 descent;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void TTF_Startup(void);
|
void TTF_Startup(void);
|
||||||
|
|||||||
@ -128,13 +128,16 @@ TTF_Decoded TTF_Decode(Arena *arena, String encoded, f32 point_size, u32 *cache_
|
|||||||
TTF_Glyph *glyphs = (TTF_Glyph *)PushStructs(arena, TTF_Glyph, glyph_count);
|
TTF_Glyph *glyphs = (TTF_Glyph *)PushStructs(arena, TTF_Glyph, glyph_count);
|
||||||
|
|
||||||
/* Acquire (starting) atlas memory
|
/* Acquire (starting) atlas memory
|
||||||
* NOTE: This is unecessary since atlas memory will grow anyway. Could
|
* NOTE: This is unnecessary since atlas memory will grow anyway. Could
|
||||||
* just start w/ atlas height 0.
|
* just start w/ atlas height 0.
|
||||||
*/
|
*/
|
||||||
u64 atlas_w = 1024;
|
u64 atlas_w = 1024;
|
||||||
u64 atlas_h = 1;
|
u64 atlas_h = 1;
|
||||||
u32 *atlas_memory = PushStructs(arena, u32, atlas_w * atlas_h);
|
u32 *atlas_memory = PushStructs(arena, u32, atlas_w * atlas_h);
|
||||||
|
|
||||||
|
i32 ascent = 0;
|
||||||
|
i32 descent = 0;
|
||||||
|
|
||||||
//- Fill atlas & metric data
|
//- Fill atlas & metric data
|
||||||
u32 out_offset_x = 0;
|
u32 out_offset_x = 0;
|
||||||
u32 out_offset_y = 0;
|
u32 out_offset_y = 0;
|
||||||
@ -173,6 +176,8 @@ TTF_Decoded TTF_Decode(Arena *arena, String encoded, f32 point_size, u32 *cache_
|
|||||||
//- Compute glyph metrics
|
//- Compute glyph metrics
|
||||||
DWRITE_GLYPH_METRICS glyph_metrics = ZI;
|
DWRITE_GLYPH_METRICS glyph_metrics = ZI;
|
||||||
error = IDWriteFontFace_GetDesignGlyphMetrics(font_face, &i, 1, &glyph_metrics, 0);
|
error = IDWriteFontFace_GetDesignGlyphMetrics(font_face, &i, 1, &glyph_metrics, 0);
|
||||||
|
ascent = metrics.ascent * pixel_per_design_unit;
|
||||||
|
descent = metrics.descent * pixel_per_design_unit;
|
||||||
|
|
||||||
f32 off_x = (f32)bounding_box.left - raster_target_x;
|
f32 off_x = (f32)bounding_box.left - raster_target_x;
|
||||||
f32 off_y = (f32)bounding_box.top - raster_target_y;
|
f32 off_y = (f32)bounding_box.top - raster_target_y;
|
||||||
@ -181,10 +186,7 @@ TTF_Decoded TTF_Decode(Arena *arena, String encoded, f32 point_size, u32 *cache_
|
|||||||
f32 advance = CeilF32ToI32((f32)glyph_metrics.advanceWidth * pixel_per_design_unit);
|
f32 advance = CeilF32ToI32((f32)glyph_metrics.advanceWidth * pixel_per_design_unit);
|
||||||
|
|
||||||
TTF_Glyph *glyph = &glyphs[i];
|
TTF_Glyph *glyph = &glyphs[i];
|
||||||
glyph->off_x = off_x;
|
glyph->baseline_offset = VEC2(off_x, off_y);
|
||||||
glyph->off_y = off_y;
|
|
||||||
glyph->width = (f32)tex_w;
|
|
||||||
glyph->height = (f32)tex_h;
|
|
||||||
glyph->advance = advance;
|
glyph->advance = advance;
|
||||||
|
|
||||||
/* Get the bitmap */
|
/* Get the bitmap */
|
||||||
@ -211,11 +213,8 @@ TTF_Decoded TTF_Decode(Arena *arena, String encoded, f32 point_size, u32 *cache_
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Set bounding box metrics (now that we know atlas x & y) */
|
/* Set bounding box metrics (now that we know atlas x & y) */
|
||||||
ZeroStruct(&glyph->atlas_rect);
|
glyph->atlas_p0 = VEC2I32(out_offset_x, out_offset_y);
|
||||||
glyph->atlas_rect.x = (f32)out_offset_x;
|
glyph->atlas_p1 = VEC2I32(out_offset_x + tex_w, out_offset_y + tex_h);
|
||||||
glyph->atlas_rect.y = (f32)out_offset_y;
|
|
||||||
glyph->atlas_rect.width = (f32)tex_w;
|
|
||||||
glyph->atlas_rect.height = (f32)tex_h;
|
|
||||||
|
|
||||||
//- Fill atlas
|
//- Fill atlas
|
||||||
u64 in_pitch = (u64)dib.dsBm.bmWidthBytes / 4;
|
u64 in_pitch = (u64)dib.dsBm.bmWidthBytes / 4;
|
||||||
@ -281,5 +280,7 @@ TTF_Decoded TTF_Decode(Arena *arena, String encoded, f32 point_size, u32 *cache_
|
|||||||
result.image_width = (u32)atlas_w;
|
result.image_width = (u32)atlas_w;
|
||||||
result.image_height = (u32)atlas_h;
|
result.image_height = (u32)atlas_h;
|
||||||
result.image_pixels = (u32 *)atlas_memory;
|
result.image_pixels = (u32 *)atlas_memory;
|
||||||
|
result.ascent = ascent;
|
||||||
|
result.descent = descent;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
99
src/ui/ui.c
99
src/ui/ui.c
@ -6,10 +6,18 @@ UI_SharedState UI_shared_state = ZI;
|
|||||||
void UI_Startup(void)
|
void UI_Startup(void)
|
||||||
{
|
{
|
||||||
/* Prefetch default font */
|
/* Prefetch default font */
|
||||||
Resource default_font = ResourceFromStore(&UI_Resources, Lit("font/default.ttf"));
|
Resource default_font = UI_GetDefaultFontResource();
|
||||||
F_LoadFontAsync(default_font, 12);
|
F_LoadFontAsync(default_font, 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//~ Font helpers
|
||||||
|
|
||||||
|
Resource UI_GetDefaultFontResource(void)
|
||||||
|
{
|
||||||
|
return ResourceFromStore(&UI_Resources, Lit("font/default.ttf"));
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Key helpers
|
//~ Key helpers
|
||||||
|
|
||||||
@ -188,8 +196,11 @@ UI_Box *UI_BuildBox(UI_BoxFlag flags, UI_Key key)
|
|||||||
box->pref_size[Axis_Y] = UI_UseTop(Height);
|
box->pref_size[Axis_Y] = UI_UseTop(Height);
|
||||||
box->layout_axis = UI_UseTop(LayoutAxis);
|
box->layout_axis = UI_UseTop(LayoutAxis);
|
||||||
box->background_color = UI_UseTop(BackgroundColor);
|
box->background_color = UI_UseTop(BackgroundColor);
|
||||||
|
box->border_color = UI_UseTop(BorderColor);
|
||||||
|
box->border = UI_UseTop(Border);
|
||||||
box->font_resource = UI_UseTop(Font);
|
box->font_resource = UI_UseTop(Font);
|
||||||
box->font_size = UI_UseTop(FontSize);
|
box->font_size = UI_UseTop(FontSize);
|
||||||
|
box->text_padding = UI_UseTop(TextPadding);
|
||||||
|
|
||||||
/* Prefetch font */
|
/* Prefetch font */
|
||||||
if (box->flags & UI_BoxFlag_DrawText)
|
if (box->flags & UI_BoxFlag_DrawText)
|
||||||
@ -268,7 +279,7 @@ void UI_BeginBuild(void)
|
|||||||
g->style_tops[UI_StyleKind_Parent]->style.Parent = g->root_box;
|
g->style_tops[UI_StyleKind_Parent]->style.Parent = g->root_box;
|
||||||
g->style_tops[UI_StyleKind_Width]->style.Width = UI_RatioSize(1, 0);
|
g->style_tops[UI_StyleKind_Width]->style.Width = UI_RatioSize(1, 0);
|
||||||
g->style_tops[UI_StyleKind_Height]->style.Height = UI_RatioSize(1, 0);
|
g->style_tops[UI_StyleKind_Height]->style.Height = UI_RatioSize(1, 0);
|
||||||
g->style_tops[UI_StyleKind_Font]->style.Font = ResourceFromStore(&UI_Resources, Lit("font/default.ttf"));
|
g->style_tops[UI_StyleKind_Font]->style.Font = UI_GetDefaultFontResource();
|
||||||
g->style_tops[UI_StyleKind_FontSize]->style.FontSize = 12.0f;
|
g->style_tops[UI_StyleKind_FontSize]->style.FontSize = 12.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,17 +362,25 @@ GPU_Resource *UI_EndBuild(Rect render_viewport)
|
|||||||
}
|
}
|
||||||
else if (pref_size.kind == UI_SizeKind_Text)
|
else if (pref_size.kind == UI_SizeKind_Text)
|
||||||
{
|
{
|
||||||
|
/* TODO: Distinguish between baseline alignment & visual alignment */
|
||||||
f32 text_size = 0;
|
f32 text_size = 0;
|
||||||
if (box->display_text.len > 0 && box->font)
|
if (box->display_text.len > 0 && box->font)
|
||||||
{
|
{
|
||||||
if (box->glyph_run.count == 0)
|
if (box->glyph_run.count == 0)
|
||||||
{
|
{
|
||||||
box->glyph_run = F_GlyphRunFromString(g->build_arena, box->font, box->display_text);
|
box->glyph_run = F_RunFromString(g->build_arena, box->font, box->display_text);
|
||||||
|
}
|
||||||
|
if (axis == Axis_X)
|
||||||
|
{
|
||||||
|
f32 baseline_length = box->glyph_run.baseline_length;
|
||||||
|
text_size = baseline_length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text_size = box->font->ascent + box->font->descent;
|
||||||
}
|
}
|
||||||
text_size += box->glyph_run.width * (axis == Axis_X);
|
|
||||||
text_size += box->glyph_run.height * (axis == Axis_Y);
|
|
||||||
}
|
}
|
||||||
box->solved_dims[axis] = text_size;
|
box->solved_dims[axis] = text_size + box->text_padding;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -477,13 +496,17 @@ GPU_Resource *UI_EndBuild(Rect render_viewport)
|
|||||||
rect->tex_uv0 = VEC2(0, 0);
|
rect->tex_uv0 = VEC2(0, 0);
|
||||||
rect->tex_uv1 = VEC2(1, 1);
|
rect->tex_uv1 = VEC2(1, 1);
|
||||||
rect->background_srgb = box->background_color;
|
rect->background_srgb = box->background_color;
|
||||||
|
rect->border_srgb = box->border_color;
|
||||||
|
rect->border = box->border;
|
||||||
|
|
||||||
/* FIXME: Remove this */
|
/* FIXME: Remove this */
|
||||||
u64 test_idx = rect - ((UI_RectInstance *)ArenaBase(g->draw_rects_arena));
|
#if 1
|
||||||
if (test_idx == 931)
|
if (pre_index > 2)
|
||||||
{
|
{
|
||||||
DEBUGBREAKABLE;
|
rect->border_srgb = Rgba32F(0, 1, 1, 0.4);
|
||||||
|
rect->border = 1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
if ((box->flags & UI_BoxFlag_DrawImage) && box->display_image)
|
if ((box->flags & UI_BoxFlag_DrawImage) && box->display_image)
|
||||||
@ -495,24 +518,54 @@ GPU_Resource *UI_EndBuild(Rect render_viewport)
|
|||||||
if ((box->flags & UI_BoxFlag_DrawText) && box->glyph_run.count > 0 && box->font)
|
if ((box->flags & UI_BoxFlag_DrawText) && box->glyph_run.count > 0 && box->font)
|
||||||
{
|
{
|
||||||
Texture2DRid tex_rid = GPU_Texture2DRidFromResource(box->font->texture);
|
Texture2DRid tex_rid = GPU_Texture2DRidFromResource(box->font->texture);
|
||||||
f32 inv_font_image_width = 1.0f / (f32)box->font->image_width;
|
Vec2 inv_font_image_size = VEC2(1.0f / (f32)box->font->image_width, 1.0f / (f32)box->font->image_height);
|
||||||
f32 inv_font_image_height = 1.0f / (f32)box->font->image_height;
|
|
||||||
|
|
||||||
String text = box->display_text;
|
String text = box->display_text;
|
||||||
F_GlyphRun run = box->glyph_run;
|
F_Run run = box->glyph_run;
|
||||||
f32 offset = 0;
|
|
||||||
|
f32 ascent = box->font->ascent;
|
||||||
|
f32 descent = box->font->descent;
|
||||||
|
f32 padding = box->text_padding;
|
||||||
|
f32 half_padding = padding * 0.5f;
|
||||||
|
|
||||||
|
Vec2 baseline = box->p0;
|
||||||
|
baseline = AddVec2(baseline, VEC2(half_padding, half_padding + ascent));
|
||||||
|
|
||||||
|
// offset.x += run.width / 2;
|
||||||
|
// offset.y += run.baseline_depth;
|
||||||
|
// offset.x += half_padding;
|
||||||
|
// offset.y += half_padding;
|
||||||
|
|
||||||
for (u64 i = 0; i < run.count; ++i)
|
for (u64 i = 0; i < run.count; ++i)
|
||||||
{
|
{
|
||||||
F_Glyph glyph = run.glyphs[i];
|
F_RunRect rr = run.rects[i];
|
||||||
Rect atlas_rect = glyph.atlas_rect;
|
Vec2 atlas_p0 = Vec2FromVec(rr.atlas_p0);
|
||||||
UI_RectInstance *rect = PushStruct(g->draw_rects_arena, UI_RectInstance);
|
Vec2 atlas_p1 = Vec2FromVec(rr.atlas_p1);
|
||||||
rect->flags |= UI_RectFlag_DrawTexture;
|
Vec2 glyph_size = SubVec2(atlas_p1, atlas_p0);
|
||||||
rect->p0 = AddVec2(box->p0, VEC2(offset, 0));
|
if (glyph_size.x != 0 || glyph_size.y != 0)
|
||||||
rect->p1 = AddVec2(rect->p0, VEC2(glyph.width, glyph.height));
|
{
|
||||||
rect->tex_uv0 = VEC2(atlas_rect.x * inv_font_image_width, atlas_rect.y * inv_font_image_height);
|
UI_RectInstance *rect = PushStruct(g->draw_rects_arena, UI_RectInstance);
|
||||||
rect->tex_uv1 = VEC2((atlas_rect.x + atlas_rect.width) * inv_font_image_width, (atlas_rect.y + atlas_rect.height) * inv_font_image_height);
|
rect->flags |= UI_RectFlag_DrawTexture;
|
||||||
rect->tex = tex_rid;
|
|
||||||
offset += glyph.advance;
|
/* FIXME: Shouldn't have to do this */
|
||||||
|
atlas_p0.x += 1;
|
||||||
|
atlas_p0.y += 1;
|
||||||
|
atlas_p1.x += 1;
|
||||||
|
atlas_p1.y += 1;
|
||||||
|
|
||||||
|
rect->p0 = AddVec2(baseline, rr.baseline_start_offset);
|
||||||
|
rect->p1 = AddVec2(rect->p0, glyph_size);
|
||||||
|
rect->tex_uv0 = MulVec2Vec2(atlas_p0, inv_font_image_size);
|
||||||
|
rect->tex_uv1 = MulVec2Vec2(atlas_p1, inv_font_image_size);
|
||||||
|
|
||||||
|
/* FIXME: Remove this (debugging) */
|
||||||
|
#if 0
|
||||||
|
rect->border_srgb = Rgba32F(1, 0, 1, 0.4);
|
||||||
|
rect->border = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rect->tex = tex_rid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
13
src/ui/ui.h
13
src/ui/ui.h
@ -66,12 +66,15 @@ Struct(UI_Box)
|
|||||||
|
|
||||||
UI_Size pref_size[Axis_CountXY];
|
UI_Size pref_size[Axis_CountXY];
|
||||||
u32 background_color;
|
u32 background_color;
|
||||||
|
u32 border_color;
|
||||||
|
f32 border;
|
||||||
|
f32 text_padding;
|
||||||
|
|
||||||
Resource font_resource;
|
Resource font_resource;
|
||||||
f32 font_size;
|
f32 font_size;
|
||||||
|
|
||||||
//- Layout data
|
//- Layout data
|
||||||
F_GlyphRun glyph_run;
|
F_Run glyph_run;
|
||||||
F_Font *font;
|
F_Font *font;
|
||||||
f32 solved_dims[Axis_CountXY];
|
f32 solved_dims[Axis_CountXY];
|
||||||
f32 layout_cursor;
|
f32 layout_cursor;
|
||||||
@ -96,8 +99,11 @@ Struct(UI_BoxBin)
|
|||||||
x(Width, UI_Size) \
|
x(Width, UI_Size) \
|
||||||
x(Height, UI_Size) \
|
x(Height, UI_Size) \
|
||||||
x(BackgroundColor, u32) \
|
x(BackgroundColor, u32) \
|
||||||
|
x(BorderColor, u32) \
|
||||||
|
x(Border, f32) \
|
||||||
x(Font, Resource) \
|
x(Font, Resource) \
|
||||||
x(FontSize, u32) \
|
x(FontSize, u32) \
|
||||||
|
x(TextPadding, f32) \
|
||||||
/* ----------------------------------- */
|
/* ----------------------------------- */
|
||||||
|
|
||||||
Enum(UI_StyleKind)
|
Enum(UI_StyleKind)
|
||||||
@ -178,6 +184,11 @@ Struct(UI_SharedState)
|
|||||||
|
|
||||||
void UI_Startup(void);
|
void UI_Startup(void);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//~ Font helpers
|
||||||
|
|
||||||
|
Resource UI_GetDefaultFontResource(void);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Key helpers
|
//~ Key helpers
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,8 @@ Struct(UI_RectPS_Input)
|
|||||||
|
|
||||||
Semantic(Vec4, sv_position);
|
Semantic(Vec4, sv_position);
|
||||||
Semantic(Vec4, background_lin);
|
Semantic(Vec4, background_lin);
|
||||||
|
Semantic(Vec4, border_lin);
|
||||||
|
Semantic(Vec2, rect_uv);
|
||||||
Semantic(Vec2, tex_uv);
|
Semantic(Vec2, tex_uv);
|
||||||
Semantic(nointerpolation u32, instance_idx);
|
Semantic(nointerpolation u32, instance_idx);
|
||||||
};
|
};
|
||||||
@ -22,25 +24,25 @@ Struct(UI_RectPS_Output)
|
|||||||
UI_RectPS_Input VSDef(UI_RectVS, Semantic(u32, sv_instanceid), Semantic(u32, sv_vertexid))
|
UI_RectPS_Input VSDef(UI_RectVS, Semantic(u32, sv_instanceid), Semantic(u32, sv_vertexid))
|
||||||
{
|
{
|
||||||
ConstantBuffer<UI_RectSig> sig = UI_rect_sig;
|
ConstantBuffer<UI_RectSig> sig = UI_rect_sig;
|
||||||
static const Vec2 uvs[4] = {
|
|
||||||
Vec2(0, 0),
|
|
||||||
Vec2(1, 0),
|
|
||||||
Vec2(1, 1),
|
|
||||||
Vec2(0, 1),
|
|
||||||
};
|
|
||||||
|
|
||||||
StructuredBuffer<UI_RectInstance> instances = UniformResourceFromRid(sig.instances);
|
StructuredBuffer<UI_RectInstance> instances = UniformResourceFromRid(sig.instances);
|
||||||
UI_RectInstance instance = instances[sv_instanceid];
|
UI_RectInstance instance = instances[sv_instanceid];
|
||||||
|
|
||||||
Vec2 uv = uvs[sv_vertexid];
|
#if 0
|
||||||
Vec2 tex_uv = lerp(instance.tex_uv0, instance.tex_uv1, uv);
|
Vec2 rect_uv = RectUvFromVertexId(sv_vertexid);
|
||||||
Vec2 screen_vert = lerp(instance.p0, instance.p1, uv);
|
Vec2 tex_uv = lerp(instance.tex_uv0, instance.tex_uv1, rect_uv);
|
||||||
Vec2 ndc = NdcFromViewport(sig.viewport_size, screen_vert);
|
Vec2 screen_vert = lerp(instance.p0, instance.p1, rect_uv);
|
||||||
|
#else
|
||||||
|
Vec2 rect_uv = RectUvFromVertexId(sv_vertexid);
|
||||||
|
Vec2 tex_uv = lerp(instance.tex_uv0, instance.tex_uv1, rect_uv);
|
||||||
|
Vec2 screen_vert = lerp(instance.p0, instance.p1, rect_uv);
|
||||||
|
#endif
|
||||||
|
|
||||||
UI_RectPS_Input result;
|
UI_RectPS_Input result;
|
||||||
result.sv_position = Vec4(ndc.xy, 0, 1);
|
result.sv_position = Vec4(NdcFromViewport(sig.viewport_size, screen_vert).xy, 0, 1);
|
||||||
result.background_lin = LinearFromSrgbU32(instance.background_srgb);
|
result.background_lin = LinearFromSrgbU32(instance.background_srgb);
|
||||||
|
result.border_lin = LinearFromSrgbU32(instance.border_srgb);
|
||||||
result.instance_idx = sv_instanceid;
|
result.instance_idx = sv_instanceid;
|
||||||
|
result.rect_uv = rect_uv;
|
||||||
result.tex_uv = tex_uv;
|
result.tex_uv = tex_uv;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -53,21 +55,39 @@ UI_RectPS_Output PSDef(UI_RectPS, UI_RectPS_Input input)
|
|||||||
ConstantBuffer<UI_RectSig> sig = UI_rect_sig;
|
ConstantBuffer<UI_RectSig> sig = UI_rect_sig;
|
||||||
StructuredBuffer<UI_RectInstance> instances = UniformResourceFromRid(sig.instances);
|
StructuredBuffer<UI_RectInstance> instances = UniformResourceFromRid(sig.instances);
|
||||||
UI_RectInstance instance = instances[input.instance_idx];
|
UI_RectInstance instance = instances[input.instance_idx];
|
||||||
Vec4 color;
|
|
||||||
|
Vec4 result = 0;
|
||||||
|
Vec2 p = input.sv_position.xy;
|
||||||
|
Vec2 p0 = instance.p0;
|
||||||
|
Vec2 p1 = instance.p1;
|
||||||
|
Vec2 rect_uv = input.rect_uv;
|
||||||
|
|
||||||
/* Background */
|
/* Background */
|
||||||
if (instance.flags & UI_RectFlag_DrawTexture)
|
if (instance.flags & UI_RectFlag_DrawTexture)
|
||||||
{
|
{
|
||||||
SamplerState sampler = UniformSamplerFromRid(sig.sampler);
|
SamplerState sampler = UniformSamplerFromRid(sig.sampler);
|
||||||
Texture2D<Vec4> tex = NonUniformResourceFromRid(instance.tex);
|
Texture2D<Vec4> tex = NonUniformResourceFromRid(instance.tex);
|
||||||
color = tex.Sample(sampler, input.tex_uv);
|
result = tex.Sample(sampler, input.tex_uv);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
color = input.background_lin;
|
result = input.background_lin;
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_RectPS_Output result;
|
/* Border */
|
||||||
result.sv_target0 = color;
|
Vec2 to_border = Vec2(0, 0);
|
||||||
return result;
|
to_border.x = min(p.x - p0.x, p1.x - p.x);
|
||||||
|
to_border.y = min(p.y - p0.y, p1.y - p.y);
|
||||||
|
f32 dist_to_border = min(to_border.x, to_border.y);
|
||||||
|
|
||||||
|
if (dist_to_border < instance.border)
|
||||||
|
{
|
||||||
|
result = input.border_lin;
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 border_thickness = instance.border;
|
||||||
|
|
||||||
|
UI_RectPS_Output output;
|
||||||
|
output.sv_target0 = result;
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,8 @@ Struct(UI_RectInstance)
|
|||||||
Vec2 p0;
|
Vec2 p0;
|
||||||
Vec2 p1;
|
Vec2 p1;
|
||||||
u32 background_srgb;
|
u32 background_srgb;
|
||||||
|
u32 border_srgb;
|
||||||
|
f32 border;
|
||||||
Vec2 tex_uv0;
|
Vec2 tex_uv0;
|
||||||
Vec2 tex_uv1;
|
Vec2 tex_uv1;
|
||||||
Texture2DRid tex;
|
Texture2DRid tex;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user