ui sprite rendering

This commit is contained in:
jacob 2026-02-04 13:55:38 -06:00
parent 5f8e701ac1
commit f9c69779ea
9 changed files with 223 additions and 39 deletions

BIN
src/pp/pp_res/tile/Empty.ase (Stored with Git LFS) Normal file

Binary file not shown.

BIN
src/pp/pp_res/tile/Wall.ase (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -14,9 +14,9 @@
#define P_TilesXList(X) \
X(Empty) \
X(Wall) \
X(Tile) \
X(Carpet) \
X(Wall) \
/* -------------------- */
//- Tiles kinds enum

View File

@ -2749,6 +2749,15 @@ void V_TickForever(WaveLaneCtx *lane)
++panel->windows_count;
++V.windows_count;
}
{
V_Window *window = PushStruct(perm, V_Window);
window->panel = panel;
window->key = UI_RandKey(); // TODO: Don't use random keys
window->is_spawn_window = 1;
DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
++panel->windows_count;
++V.windows_count;
}
panel->active_window_idx = 1;
}
@ -3068,6 +3077,10 @@ void V_TickForever(WaveLaneCtx *lane)
{
tab_name = Lit("Tiles");
}
else if (window->is_spawn_window)
{
tab_name = Lit("Spawn");
}
else
{
tab_name = Lit("Unknown");
@ -3224,12 +3237,59 @@ void V_TickForever(WaveLaneCtx *lane)
UI_PushCP(UI_BuildColumn());
{
UI_Push(Tag, window->key.v);
//////////////////////////////
//- Build tile window
// if (window->is_tile_window)
// {
// for (P_TileKind tile_kind = 0; tile_kind < P_TileKind_COUNT; ++tile_kind)
// {
// String name = P_NameFromTileKind(tile_kind);
// UI_Key key = UI_KeyF("Tile %F", FmtString(name));
// UI_BoxReport rep = UI_ReportsFromKey(key).draw;
// if (rep.m1.downs)
// {
// frame->equipped_tile = tile_kind;
// }
// Vec4 bg_color = Zi;
// bg_color = LerpSrgb(bg_color, theme.col.button_hot, rep.hot);
// bg_color = LerpSrgb(bg_color, theme.col.button_active, rep.active);
// b32 is_selected = tile_kind == frame->equipped_tile;
// Vec4 border_color = Zi;
// border_color = LerpSrgb(border_color, theme.col.button_selected, rep.misc);
// border_color = LerpSrgb(border_color, theme.col.button_active, rep.hot);
// UI_SetNext(BackgroundColor, bg_color);
// UI_SetNext(BorderColor, border_color);
// UI_SetNext(BorderSize, 1);
// UI_SetNext(Width, UI_GROW(1, 0));
// UI_SetNext(Height, UI_SHRINK(0, 0));
// UI_SetNext(Misc, is_selected);
// UI_SetNext(Flags, UI_BoxFlag_CaptureMouse);
// UI_PushCP(UI_BuildRowEx(key));
// {
// UI_SetNext(ChildAlignment, UI_Region_Center);
// UI_SetNext(Text, name);
// UI_SetNext(Flags, UI_BoxFlag_DrawText);
// UI_SetNext(Width, UI_SHRINK(4, 0));
// UI_SetNext(Height, UI_SHRINK(2, 0));
// UI_BuildRow();
// }
// UI_PopCP(UI_TopCP());
// }
// }
if (window->is_tile_window)
{
for (P_TileKind tile_kind = 0; tile_kind < P_TileKind_COUNT; ++tile_kind)
{
String name = P_NameFromTileKind(tile_kind);
UI_Key key = UI_KeyF("Tile %F", FmtString(name));
String tile_name = P_NameFromTileKind(tile_kind);
UI_Key key = UI_KeyF("Tile %F", FmtString(tile_name));
UI_BoxReport rep = UI_ReportsFromKey(key).draw;
if (rep.m1.downs)
@ -3254,18 +3314,41 @@ void V_TickForever(WaveLaneCtx *lane)
UI_SetNext(Height, UI_SHRINK(0, 0));
UI_SetNext(Misc, is_selected);
UI_SetNext(Flags, UI_BoxFlag_CaptureMouse);
UI_SetNext(ChildAlignment, UI_Region_Left);
UI_PushCP(UI_BuildRowEx(key));
{
UI_SetNext(ChildAlignment, UI_Region_Center);
UI_SetNext(Text, name);
UI_SetNext(Flags, UI_BoxFlag_DrawText);
UI_SetNext(Width, UI_SHRINK(4, 0));
UI_SetNext(Height, UI_SHRINK(2, 0));
UI_BuildRow();
// Tile sprite
{
String sheet_name = StringF(frame->arena, "tile/%F.ase", FmtString(tile_name));
ResourceKey sheet_resource = ResourceKeyFromStore(&P_Resources, sheet_name);
SPR_SheetKey sheet = SPR_SheetKeyFromResource(sheet_resource);
UI_SetNext(ChildAlignment, UI_Region_Center);
UI_SetNext(Width, UI_SHRINK(4, 0));
UI_SetNext(Height, UI_SHRINK(4, 0));
UI_SetNext(SpriteSheet, sheet);
UI_BuildRow();
}
// Tile name
{
UI_SetNext(ChildAlignment, UI_Region_Center);
UI_SetNext(Text, tile_name);
UI_SetNext(Flags, UI_BoxFlag_DrawText);
UI_SetNext(Width, UI_SHRINK(4, 0));
UI_SetNext(Height, UI_SHRINK(2, 0));
UI_BuildRow();
}
}
UI_PopCP(UI_TopCP());
}
}
//////////////////////////////
//- Build spawn window
if (window->is_spawn_window)
{
}
}
UI_PopCP(UI_TopCP());
}
@ -3395,7 +3478,7 @@ void V_TickForever(WaveLaneCtx *lane)
UI_Push(ChildLayoutAxis, Axis_Y);
UI_Push(FloatingPos, palette->pos);
UI_SetNext(Anchor, UI_Region_Center);
UI_SetNext(Flags, UI_BoxFlag_Floating | UI_BoxFlag_CaptureMouse);
UI_SetNext(Flags, UI_BoxFlag_Floating | (UI_BoxFlag_CaptureMouse * !!palette->is_showing));
UI_PushCP(UI_BuildBoxEx(palette->key));
{
// Title bar
@ -3407,7 +3490,7 @@ void V_TickForever(WaveLaneCtx *lane)
UI_Push(ChildLayoutAxis, Axis_X);
UI_Push(Width, UI_GROW(1, 0));
UI_Push(Height, UI_FNT(2, 1));
UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_CaptureMouse);
UI_SetNext(Flags, UI_BoxFlag_DrawText | (UI_BoxFlag_CaptureMouse * !!palette->is_showing));
UI_PushCP(UI_BuildBoxEx(titlebar_key));
{
UI_Push(Width, UI_GROW(1, 0));

View File

@ -202,6 +202,7 @@ Struct(V_Window)
UI_Key key;
b32 is_tile_window;
b32 is_spawn_window;
};
////////////////////////////////////////////////////////////

View File

@ -27,6 +27,16 @@ SPR_SpanKey SPR_SpanKeyFromName(String name)
return result;
}
b32 SPR_IsSheetKeyNil(SPR_SheetKey key)
{
return key.r.v == 0;
}
b32 SPR_IsSpanKeyNil(SPR_SpanKey key)
{
return key.v == 0;
}
String SPR_NameFromRayKind(SPR_RayKind kind)
{
PERSIST Readonly String names[SPR_RayKind_COUNT] = {

View File

@ -185,6 +185,9 @@ void SPR_Bootstrap(void);
SPR_SheetKey SPR_SheetKeyFromResource(ResourceKey resource);
SPR_SpanKey SPR_SpanKeyFromName(String name);
b32 SPR_IsSheetKeyNil(SPR_SheetKey key);
b32 SPR_IsSpanKeyNil(SPR_SpanKey key);
String SPR_NameFromRayKind(SPR_RayKind kind);
SPR_LayerKind SPR_LayerKindFromName(String name);

View File

@ -503,6 +503,9 @@ UI_Key UI_BuildBoxEx(UI_Key semantic_key)
n->cmd.box.icon = UI_Top(Icon);
n->cmd.box.anchor = UI_Top(Anchor);
n->cmd.box.floating_pos = UI_Top(FloatingPos);
n->cmd.box.sprite_sheet = UI_Top(SpriteSheet);
n->cmd.box.sprite_span = UI_Top(SpriteSpan);
n->cmd.box.sprite_seq = UI_Top(SpriteSeq);
n->cmd.box.misc = UI_Top(Misc);
}
++frame->cmds_count;
@ -865,7 +868,7 @@ Vec2 UI_CursorPos(void)
}
////////////////////////////////////////////////////////////
//~ Text layout helpers
//~ Layout helpers
GC_Run UI_ScaleRun(Arena *arena, GC_Run unscaled_run, Vec2 scale)
{
@ -1005,7 +1008,16 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
{
codepoints = String32FromString(scratch.arena, box->desc.text);
}
box->glyph_run = GC_RunFromString32(frame->arena, codepoints, box->desc.font, box->desc.font_size);
if (AnyBit(box->desc.flags, UI_BoxFlag_DrawText) && codepoints.len > 0)
{
box->glyph_run = GC_RunFromString32(frame->arena, codepoints, box->desc.font, box->desc.font_size);
}
if (!SPR_IsSheetKeyNil(box->desc.sprite_sheet))
{
box->sprite = SPR_SpriteFromSheet(box->desc.sprite_sheet, box->desc.sprite_span, box->desc.sprite_seq);
}
}
box->last_build_tick = frame->tick;
} break;
@ -1134,23 +1146,30 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
UI_Box *box = boxes_pre[pre_index];
for (Axis axis = 0; axis < Axis_COUNTXY; ++axis)
{
UI_Size sem_dims = box->desc.pref_semantic_dims[axis];
if (sem_dims.kind == UI_SizeKind_Pixel)
UI_Size size = box->desc.pref_semantic_dims[axis];
if (size.kind == UI_SizeKind_Pixel)
{
box->solved_dims.v[axis] = sem_dims.v;
box->solved_dims.v[axis] = size.v;
}
else if (sem_dims.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText))
else if (size.kind == UI_SizeKind_Shrink)
{
f32 text_size = 0;
if (axis == Axis_X)
if (AnyBit(box->desc.flags, UI_BoxFlag_DrawText))
{
text_size = box->glyph_run.baseline_length;
f32 text_size = 0;
if (axis == Axis_X)
{
text_size = box->glyph_run.baseline_length;
}
else
{
text_size = box->glyph_run.font_ascent + box->glyph_run.font_descent;
}
box->solved_dims.v[axis] = text_size + (size.v * 2);
}
else
else if (!SPR_IsSheetKeyNil(box->desc.sprite_sheet))
{
text_size = box->glyph_run.font_ascent + box->glyph_run.font_descent;
box->solved_dims.v[axis] = box->sprite.tex_rect.p1.v[axis] - box->sprite.tex_rect.p0.v[axis] + (size.v * 2);
}
box->solved_dims.v[axis] = text_size + (sem_dims.v * 2);
}
}
}
@ -1162,22 +1181,29 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
if (box->parent)
{
Axis axis = box->parent->desc.child_layout_axis;
UI_Size sem_dims = box->desc.pref_semantic_dims[axis];
if (sem_dims.kind == UI_SizeKind_Grow)
UI_Size size = box->desc.pref_semantic_dims[axis];
if (size.kind == UI_SizeKind_Grow)
{
f32 match_size = 0;
b32 found_match = 0;
for (UI_Box *ancestor = box->parent; ancestor != 0 && !found_match; ancestor = ancestor->parent)
{
UI_Size ancestor_size = ancestor->desc.pref_semantic_dims[axis];
if (ancestor_size.kind == UI_SizeKind_Pixel || (ancestor_size.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText)))
if (
ancestor_size.kind == UI_SizeKind_Pixel || (
ancestor_size.kind == UI_SizeKind_Shrink && (
AnyBit(box->desc.flags, UI_BoxFlag_DrawText) ||
!SPR_IsSheetKeyNil(box->desc.sprite_sheet)
)
)
)
{
// Match independent ancestor
match_size = ancestor->solved_dims.v[axis];
found_match = 1;
}
}
box->solved_dims.v[axis] = match_size * sem_dims.v;
box->solved_dims.v[axis] = match_size * size.v;
}
}
}
@ -1188,8 +1214,8 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
UI_Box *box = boxes_post[post_index];
for (Axis axis = 0; axis < Axis_COUNTXY; ++axis)
{
UI_Size sem_dims = box->desc.pref_semantic_dims[axis];
if (sem_dims.kind == UI_SizeKind_Shrink && !AnyBit(box->desc.flags, UI_BoxFlag_DrawText))
UI_Size size = box->desc.pref_semantic_dims[axis];
if (size.kind == UI_SizeKind_Shrink && !(AnyBit(box->desc.flags, UI_BoxFlag_DrawText) || !SPR_IsSheetKeyNil(box->desc.sprite_sheet)))
{
f32 accum = 0;
for (UI_Box *child = box->first; child; child = child->next)
@ -1207,7 +1233,7 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
}
}
}
box->solved_dims.v[axis] = CeilF32(accum + (sem_dims.v * 2));
box->solved_dims.v[axis] = CeilF32(accum + (size.v * 2));
}
}
}
@ -1219,10 +1245,10 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
if (box->parent)
{
Axis axis = !box->parent->desc.child_layout_axis;
UI_Size sem_dims = box->desc.pref_semantic_dims[axis];
if (sem_dims.kind == UI_SizeKind_Grow)
UI_Size size = box->desc.pref_semantic_dims[axis];
if (size.kind == UI_SizeKind_Grow)
{
box->solved_dims.v[axis] = box->parent->solved_dims.v[axis] * sem_dims.v;
box->solved_dims.v[axis] = box->parent->solved_dims.v[axis] * size.v;
}
}
}
@ -1508,7 +1534,6 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index)
{
UI_Box *box = boxes_pre[pre_index];
UI_RegionPair child_alignment = UI_PairFromRegion(box->desc.child_alignment);
b32 is_visible = 1;
is_visible = is_visible && (box->desc.tint.w >= 0.0025);
@ -1518,6 +1543,10 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
{
Vec4 debug_lin = is_visible ? LinearFromSrgb(box->desc.debug_color) : LinearFromSrgb(box->desc.invisible_debug_color);
Vec4 tint_lin = LinearFromSrgb(box->desc.tint);
Vec2 box_dims = DimsFromRng2(box->screen_rect);
UI_RegionPair child_alignment = UI_PairFromRegion(box->desc.child_alignment);
UI_AxisRegion x_alignment = child_alignment.v[Axis_X];
UI_AxisRegion y_alignment = child_alignment.v[Axis_Y];
// Box rect
{
@ -1536,6 +1565,55 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
rect->tex_slice_uv = box->raw_texture_slice_uv;
}
// Sprite rect
if (!SPR_IsSheetKeyNil(box->desc.sprite_sheet))
{
UI_GpuRect *rect = PushStruct(frame->rects_arena, UI_GpuRect);
rect->debug_lin = debug_lin;
rect->tint_lin = tint_lin;
rect->tex = box->sprite.tex;
rect->tex_slice_uv = DivRng2Vec2(box->sprite.tex_rect, box->sprite.tex_dims);
Vec2 dims = DimsFromRng2(box->sprite.tex_rect);
Vec2 pos = Zi;
switch (x_alignment)
{
case UI_AxisRegion_Start:
{
pos.x = box->screen_rect.p0.x;
} break;
case UI_AxisRegion_End:
{
pos.x = box->screen_rect.p1.x;
pos.x -= dims.x;
} break;
case UI_AxisRegion_Center:
{
pos.x = box->screen_rect.p0.x;
pos.x += (box_dims.x - dims.x) / 2;
} break;
}
switch (y_alignment)
{
case UI_AxisRegion_Start:
{
pos.y = box->screen_rect.p0.y;
} break;
case UI_AxisRegion_End:
{
pos.y = box->screen_rect.p1.y;
pos.y -= dims.y;
} break;
case UI_AxisRegion_Center:
{
pos.y = box->screen_rect.p0.y;
pos.y += (box_dims.y - dims.y) / 2;
} break;
}
rect->bounds.p0 = pos;
rect->bounds.p1 = AddVec2(rect->bounds.p0, dims);
}
// Text rects
GC_Run raw_run_unscaled = box->glyph_run;
GC_Run raw_run = UI_ScaleRun(frame->arena, raw_run_unscaled, box->solved_scale);
@ -1590,15 +1668,11 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
final_baseline_length = raw_run.baseline_length;
}
UI_AxisRegion x_alignment = child_alignment.v[Axis_X];
UI_AxisRegion y_alignment = child_alignment.v[Axis_Y];
// Compute baseline
f32 ascent = raw_run.font_ascent;
f32 font_descent = raw_run.font_descent;
f32 cap = raw_run.font_cap;
f32 baseline_height = ascent + font_descent;
Vec2 box_dims = DimsFromRng2(box->screen_rect);
Vec2 baseline = Zi;
switch (x_alignment)
{

View File

@ -121,6 +121,9 @@ Enum(UI_BoxFlag)
X(TextColor, Vec4) \
X(Text, String) \
X(Icon, UI_Icon) \
X(SpriteSheet, SPR_SheetKey) \
X(SpriteSpan, SPR_SpanKey) \
X(SpriteSeq, i64) \
X(BackgroundTexture, G_Texture2DRef) \
X(BackgroundTextureSliceUv, Rng2) \
X(Misc, f64) \
@ -255,6 +258,9 @@ Struct(UI_BoxDesc)
UI_Region child_alignment;
UI_Region anchor;
Vec2 floating_pos;
SPR_SheetKey sprite_sheet;
SPR_SpanKey sprite_span;
i64 sprite_seq;
f64 misc;
};
@ -308,6 +314,7 @@ Struct(UI_Box)
G_Texture2DRef raw_texture;
Rng2 raw_texture_slice_uv;
GC_Run glyph_run;
SPR_Sprite sprite;
//- Pre-layout data
u64 pre_index;
@ -527,7 +534,7 @@ Arena *UI_FrameArena(void);
Vec2 UI_CursorPos(void);
////////////////////////////////////////////////////////////
//~ Text layout helpers
//~ Layout helpers
GC_Run UI_ScaleRun(Arena *arena, GC_Run unscaled_run, Vec2 scale);