ui rounding

This commit is contained in:
jacob 2025-10-23 11:15:10 -05:00
parent 3c97718760
commit 26e2875126
7 changed files with 152 additions and 119 deletions

View File

@ -68,9 +68,13 @@ void PushGameUiStyle(void)
// UI_Push(FontSize, 24); // UI_Push(FontSize, 24);
UI_Push(FontSize, 12); UI_Push(FontSize, 12);
UI_Push(TextPadding, 3); UI_Push(Rounding, 0.3f);
// UI_Push(Border, 1);
// UI_Push(BorderColor, Rgba32F(1, 0, 1, 0.4)); UI_Push(TextPadding, 4);
UI_Push(Border, 3);
UI_Push(BackgroundColor, Rgba32F(0.3, 0.5, 0.3, 0.3));
UI_Push(BorderColor, Rgba32F(0.1, 0.4, 0.3, 0.4));
} }
//- Draw xform //- Draw xform
@ -463,9 +467,9 @@ void UpdateUser(P_Window *window)
//- Begin UI //- Begin UI
UI_BeginBuild(); UI_BeginBuild();
PushGameUiStyle();
UI_Box *pp_root_box = UI_BuildBox(0, UI_NilKey); UI_Box *pp_root_box = UI_BuildBox(0, UI_NilKey);
UI_Push(Parent, pp_root_box); UI_Push(Parent, pp_root_box);
PushGameUiStyle();
//- Init render data buffers //- Init render data buffers
if (!g->material_instances_arena) if (!g->material_instances_arena)
@ -2015,96 +2019,98 @@ void UpdateUser(P_Window *window)
__profn("Draw debug info"); __profn("Draw debug info");
UI_SetNext(LayoutAxis, Axis_Y); UI_SetNext(LayoutAxis, Axis_Y);
UI_SetNext(BackgroundColor, 0);
UI_SetNext(BorderColor, 0);
UI_Box *dbg_box = UI_BuildBox(0, UI_NilKey); UI_Box *dbg_box = UI_BuildBox(0, UI_NilKey);
UI_PushCheckpoint(); UI_PushCheckpoint();
{ {
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.6, 0.3, 0.5)); // UI_Push(BackgroundColor, Rgba32F(0.3, 0.6, 0.3, 0.5));
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_BuildDivider();
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_BuildDivider();
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_BuildDivider();
// UI_BuildSeparator(); UI_BuildDivider();
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_BuildDivider();
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_BuildDivider();
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_BuildDivider();
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_BuildDivider();
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_BuildDivider();
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_BuildDivider();
// UI_BuildSeparator(); UI_BuildDivider();
UI_BuildLabelF("local player: [%F]", FmtUid(local_player->id.uid)); UI_BuildLabelF("local player: [%F]", FmtUid(local_player->id.uid));
// UI_BuildSeparator(); UI_BuildDivider();
// UI_BuildSeparator(); UI_BuildDivider();
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_BuildDivider();
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_BuildDivider();
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_BuildDivider();
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_BuildDivider();
// UI_BuildSeparator(); UI_BuildDivider();
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_BuildDivider();
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_BuildDivider();
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_BuildDivider();
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_BuildDivider();
// UI_BuildSeparator(); UI_BuildDivider();
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_BuildDivider();
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_BuildDivider();
UI_BuildLabelF("Arenas allocated: %F", FmtUint(GetGstat(GSTAT_NUM_ARENAS))); UI_BuildLabelF("Arenas allocated: %F", FmtUint(GetGstat(GSTAT_NUM_ARENAS)));
// UI_BuildSeparator(); UI_BuildDivider();
// UI_BuildSeparator(); UI_BuildDivider();
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_BuildDivider();
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_BuildDivider();
// UI_BuildSeparator(); UI_BuildDivider();
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"));

View File

@ -201,6 +201,7 @@ UI_Box *UI_BuildBox(UI_BoxFlag flags, UI_Key key)
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); box->text_padding = UI_UseTop(TextPadding);
box->rounding = UI_UseTop(Rounding);
/* Prefetch font */ /* Prefetch font */
if (box->flags & UI_BoxFlag_DrawText) if (box->flags & UI_BoxFlag_DrawText)
@ -493,16 +494,7 @@ GPU_Resource *UI_EndBuild(Rect render_viewport)
rect->background_srgb = box->background_color; rect->background_srgb = box->background_color;
rect->border_srgb = box->border_color; rect->border_srgb = box->border_color;
rect->border = box->border; rect->border = box->border;
rect->rounding = box->rounding;
/* FIXME: Remove this */
#if 1
if (pre_index > 2)
{
rect->border_srgb = Rgba32F(0, 1, 1, 0.4);
rect->border = 1;
}
#endif
if (box->background_texture != 0) if (box->background_texture != 0)
{ {
rect->tex = GPU_Texture2DRidFromResource(box->background_texture); rect->tex = GPU_Texture2DRidFromResource(box->background_texture);
@ -594,7 +586,7 @@ GPU_Resource *UI_EndBuild(Rect render_viewport)
UI_RectSig sig = ZI; UI_RectSig sig = ZI;
sig.viewport_size = RoundVec2ToVec2I32(render_viewport.size); sig.viewport_size = RoundVec2ToVec2I32(render_viewport.size);
sig.sampler = GPU_SamplerStateRidFromResource(GPU_GetCommonPointSampler()); sig.sampler = GPU_SamplerStateRidFromResource(GPU_GetCommonPointSampler());
sig.instances = GPU_StructuredBufferRidFromResource(draw_rects_buffer); sig.rects = GPU_StructuredBufferRidFromResource(draw_rects_buffer);
GPU_Rasterize(cl, GPU_Rasterize(cl,
&sig, &sig,
UI_RectVS, UI_RectPS, UI_RectVS, UI_RectPS,

View File

@ -27,6 +27,53 @@ Struct(UI_Size)
f32 strictness; f32 strictness;
}; };
////////////////////////////////////////////////////////////
//~ Style types
#define UI_StyleKindsXMacro(x) \
x(Tag, u64) \
x(Parent, struct UI_Box *) \
x(LayoutAxis, Axis) \
x(Width, UI_Size) \
x(Height, UI_Size) \
x(BackgroundColor, u32) \
x(BorderColor, u32) \
x(Border, f32) \
x(Font, Resource) \
x(FontSize, u32) \
x(TextPadding, f32) \
x(Rounding, f32) \
/* ------------------------------------------- */
Enum(UI_StyleKind)
{
#define X(name, type) UI_StyleKind_##name,
UI_StyleKind_None,
UI_StyleKindsXMacro(X)
UI_StyleKind_Count,
#undef X
};
Struct(UI_Style)
{
UI_StyleKind kind;
/* Union of all style fields */
union
{
#define X(name, type) type name;
UI_StyleKindsXMacro(X)
#undef X
};
};
Struct(UI_StyleNode)
{
UI_StyleNode *next;
b32 pop_when_used;
u64 checkpoint;
UI_Style style;
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Box types //~ Box types
@ -71,6 +118,7 @@ Struct(UI_Box)
u32 border_color; u32 border_color;
f32 border; f32 border;
f32 text_padding; f32 text_padding;
f32 rounding;
Resource font_resource; Resource font_resource;
f32 font_size; f32 font_size;
@ -91,52 +139,6 @@ Struct(UI_BoxBin)
UI_Box *last; UI_Box *last;
}; };
////////////////////////////////////////////////////////////
//~ Style types
#define UI_StyleKindsXMacro(x) \
x(Tag, u64) \
x(Parent, UI_Box *) \
x(LayoutAxis, Axis) \
x(Width, UI_Size) \
x(Height, UI_Size) \
x(BackgroundColor, u32) \
x(BorderColor, u32) \
x(Border, f32) \
x(Font, Resource) \
x(FontSize, u32) \
x(TextPadding, f32) \
/* ---------------------------------------- */
Enum(UI_StyleKind)
{
#define X(name, type) UI_StyleKind_##name,
UI_StyleKind_None,
UI_StyleKindsXMacro(X)
UI_StyleKind_Count,
#undef X
};
Struct(UI_Style)
{
UI_StyleKind kind;
/* Union of all style fields */
union
{
#define X(name, type) type name;
UI_StyleKindsXMacro(X)
#undef X
};
};
Struct(UI_StyleNode)
{
UI_StyleNode *next;
b32 pop_when_used;
u64 checkpoint;
UI_Style style;
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Checkpoint types //~ Checkpoint types

View File

@ -8,11 +8,11 @@ Struct(UI_RectPS_Input)
{ {
Semantic(Vec4, sv_position); Semantic(Vec4, sv_position);
Semantic(nointerpolation u32, rect_idx);
Semantic(Vec4, background_lin); Semantic(Vec4, background_lin);
Semantic(Vec4, border_lin); Semantic(Vec4, border_lin);
Semantic(Vec2, rect_uv); Semantic(Vec2, rect_uv);
Semantic(Vec2, tex_uv); Semantic(Vec2, tex_uv);
Semantic(nointerpolation u32, instance_idx);
}; };
Struct(UI_RectPS_Output) Struct(UI_RectPS_Output)
@ -25,18 +25,18 @@ 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;
StructuredBuffer<UI_RectInstance> instances = UniformResourceFromRid(sig.instances); StructuredBuffer<UI_RectInstance> rects = UniformResourceFromRid(sig.rects);
UI_RectInstance instance = instances[sv_instanceid]; UI_RectInstance rect = rects[sv_instanceid];
Vec2 rect_uv = RectUvFromVertexId(sv_vertexid); Vec2 rect_uv = RectUvFromVertexId(sv_vertexid);
Vec2 tex_uv = lerp(instance.tex_uv0, instance.tex_uv1, rect_uv); Vec2 tex_uv = lerp(rect.tex_uv0, rect.tex_uv1, rect_uv);
Vec2 screen_vert = lerp(instance.p0, instance.p1, rect_uv); Vec2 screen_vert = lerp(rect.p0, rect.p1, rect_uv);
UI_RectPS_Input result; UI_RectPS_Input result;
result.sv_position = Vec4(NdcFromViewport(sig.viewport_size, screen_vert).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(rect.background_srgb);
result.border_lin = LinearFromSrgbU32(instance.border_srgb); result.border_lin = LinearFromSrgbU32(rect.border_srgb);
result.instance_idx = sv_instanceid; result.rect_idx = sv_instanceid;
result.rect_uv = rect_uv; result.rect_uv = rect_uv;
result.tex_uv = tex_uv; result.tex_uv = tex_uv;
@ -48,20 +48,20 @@ UI_RectPS_Input VSDef(UI_RectVS, Semantic(u32, sv_instanceid), Semantic(u32, sv_
UI_RectPS_Output PSDef(UI_RectPS, UI_RectPS_Input input) 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> rects = UniformResourceFromRid(sig.rects);
UI_RectInstance instance = instances[input.instance_idx]; UI_RectInstance rect = rects[input.rect_idx];
Vec4 result = 0; Vec4 result = 0;
Vec2 p = input.sv_position.xy; Vec2 p = input.sv_position.xy;
Vec2 p0 = instance.p0; Vec2 p0 = rect.p0;
Vec2 p1 = instance.p1; Vec2 p1 = rect.p1;
Vec2 rect_uv = input.rect_uv; Vec2 rect_uv = input.rect_uv;
/* Background */ /* Background */
if (instance.flags & UI_RectFlag_DrawTexture) if (rect.flags & UI_RectFlag_DrawTexture)
{ {
SamplerState sampler = UniformSamplerFromRid(sig.sampler); SamplerState sampler = UniformSamplerFromRid(sig.sampler);
Texture2D<Vec4> tex = NonUniformResourceFromRid(instance.tex); Texture2D<Vec4> tex = NonUniformResourceFromRid(rect.tex);
result = tex.Sample(sampler, input.tex_uv); result = tex.Sample(sampler, input.tex_uv);
} }
else else
@ -69,19 +69,51 @@ UI_RectPS_Output PSDef(UI_RectPS, UI_RectPS_Input input)
result = input.background_lin; result = input.background_lin;
} }
/* Border */ Vec2 size = Vec2(p1.x - p0.x, p1.y - p0.y);
Vec2 to_border = Vec2(0, 0); Vec2 half_size = size * 0.5;
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) /* Calculate distance to edge (negative means out of bounds) */
f32 edge_dist;
{
/* TODO: Read per-corner rounding here */
f32 radius = min(half_size.x, half_size.y) * rect.rounding;
Vec2 tl = Vec2(p0.x + radius, p0.y + radius);
Vec2 tr = Vec2(p1.x - radius, p0.y + radius);
Vec2 br = Vec2(p1.x - radius, p1.y - radius);
Vec2 bl = Vec2(p0.x + radius, p1.y - radius);
if (p.x < tl.x && p.y < tl.y)
{
edge_dist = radius - length(tl - p);
}
else if (p.x > tr.x && p.y < tr.y)
{
edge_dist = radius - length(tr - p);
}
else if (p.x > br.x && p.y > br.y)
{
edge_dist = radius - length(br - p);
}
else if (p.x < bl.x && p.y > bl.y)
{
edge_dist = radius - length(bl - p);
}
else
{
edge_dist = min(min(p.x - p0.x, p1.x - p.x), min(p.y - p0.y, p1.y - p.y));
}
}
/* Border */
if (edge_dist < 0)
{
result = 0;
}
else if (edge_dist < rect.border)
{ {
result = input.border_lin; result = input.border_lin;
} }
f32 border_thickness = instance.border;
UI_RectPS_Output output; UI_RectPS_Output output;
output.sv_target0 = result; output.sv_target0 = result;
return output; return output;

View File

@ -5,7 +5,7 @@ Struct(UI_RectSig)
{ {
/* ----------------------------------------------------- */ /* ----------------------------------------------------- */
Vec2I32 viewport_size; /* 02 consts */ Vec2I32 viewport_size; /* 02 consts */
StructuredBufferRid instances; /* 01 consts */ StructuredBufferRid rects; /* 01 consts */
SamplerStateRid sampler; /* 01 consts */ SamplerStateRid sampler; /* 01 consts */
/* ----------------------------------------------------- */ /* ----------------------------------------------------- */
}; };
@ -28,6 +28,7 @@ Struct(UI_RectInstance)
Vec2 tex_uv0; Vec2 tex_uv0;
Vec2 tex_uv1; Vec2 tex_uv1;
Texture2DRid tex; Texture2DRid tex;
f32 rounding;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -25,9 +25,9 @@ UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...)
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Separator widget //~ Divider widget
UI_Box *UI_BuildSeparator(void) UI_Box *UI_BuildDivider(void)
{ {
UI_Box *box = UI_BuildBox(0, UI_NilKey); UI_Box *box = UI_BuildBox(0, UI_NilKey);
return box; return box;

View File

@ -6,6 +6,6 @@ UI_Box *UI_BuildLabel(String text);
UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...); UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Separator widget //~ Divider widget
UI_Box *UI_BuildSeparator(void); UI_Box *UI_BuildDivider(void);