diff --git a/src/pp/pp.c b/src/pp/pp.c index a2c30735..d1432456 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -68,9 +68,13 @@ void PushGameUiStyle(void) // UI_Push(FontSize, 24); UI_Push(FontSize, 12); - UI_Push(TextPadding, 3); - // UI_Push(Border, 1); - // UI_Push(BorderColor, Rgba32F(1, 0, 1, 0.4)); + UI_Push(Rounding, 0.3f); + + 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 @@ -463,9 +467,9 @@ void UpdateUser(P_Window *window) //- Begin UI UI_BeginBuild(); - PushGameUiStyle(); UI_Box *pp_root_box = UI_BuildBox(0, UI_NilKey); UI_Push(Parent, pp_root_box); + PushGameUiStyle(); //- Init render data buffers if (!g->material_instances_arena) @@ -2015,96 +2019,98 @@ void UpdateUser(P_Window *window) __profn("Draw debug info"); UI_SetNext(LayoutAxis, Axis_Y); + UI_SetNext(BackgroundColor, 0); + UI_SetNext(BorderColor, 0); UI_Box *dbg_box = UI_BuildBox(0, UI_NilKey); UI_PushCheckpoint(); { UI_Push(Parent, dbg_box); UI_Push(Width, 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_BuildSeparator(); + UI_BuildDivider(); 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_BuildSeparator(); - // UI_BuildSeparator(); + UI_BuildDivider(); + UI_BuildDivider(); 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_BuildSeparator(); + UI_BuildDivider(); 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_BuildSeparator(); + UI_BuildDivider(); 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_BuildSeparator(); - // UI_BuildSeparator(); + UI_BuildDivider(); + UI_BuildDivider(); UI_BuildLabelF("local player: [%F]", FmtUid(local_player->id.uid)); - // UI_BuildSeparator(); - // UI_BuildSeparator(); + UI_BuildDivider(); + UI_BuildDivider(); Vec2 world_cursor = g->world_cursor; 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); 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); 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); UI_BuildLabelF("cursor tile chunk: %F, %F", FmtSint(tile_chunk_cursor.x), FmtSint(tile_chunk_cursor.y)); - // UI_BuildSeparator(); - // UI_BuildSeparator(); + UI_BuildDivider(); + UI_BuildDivider(); 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_BuildSeparator(); + UI_BuildDivider(); 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_BuildSeparator(); - // UI_BuildSeparator(); + UI_BuildDivider(); + UI_BuildDivider(); 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_BuildSeparator(); + UI_BuildDivider(); UI_BuildLabelF("Arenas allocated: %F", FmtUint(GetGstat(GSTAT_NUM_ARENAS))); - // UI_BuildSeparator(); - // UI_BuildSeparator(); + UI_BuildDivider(); + UI_BuildDivider(); 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(\n")); //UI_BuildLabelF(\n")); #if RtcIsEnabled - // UI_BuildSeparator(); - // UI_BuildSeparator(); + UI_BuildDivider(); + UI_BuildDivider(); UI_BuildLabelF("Debug steps: %F", FmtUint(GetGstat(GSTAT_DEBUG_STEPS))); //UI_BuildLabelF(\n")); diff --git a/src/ui/ui.c b/src/ui/ui.c index db12483c..5326dc69 100644 --- a/src/ui/ui.c +++ b/src/ui/ui.c @@ -201,6 +201,7 @@ UI_Box *UI_BuildBox(UI_BoxFlag flags, UI_Key key) box->font_resource = UI_UseTop(Font); box->font_size = UI_UseTop(FontSize); box->text_padding = UI_UseTop(TextPadding); + box->rounding = UI_UseTop(Rounding); /* Prefetch font */ if (box->flags & UI_BoxFlag_DrawText) @@ -493,16 +494,7 @@ GPU_Resource *UI_EndBuild(Rect render_viewport) rect->background_srgb = box->background_color; rect->border_srgb = box->border_color; rect->border = box->border; - - /* FIXME: Remove this */ -#if 1 - if (pre_index > 2) - { - rect->border_srgb = Rgba32F(0, 1, 1, 0.4); - rect->border = 1; - } -#endif - + rect->rounding = box->rounding; if (box->background_texture != 0) { rect->tex = GPU_Texture2DRidFromResource(box->background_texture); @@ -594,7 +586,7 @@ GPU_Resource *UI_EndBuild(Rect render_viewport) UI_RectSig sig = ZI; sig.viewport_size = RoundVec2ToVec2I32(render_viewport.size); sig.sampler = GPU_SamplerStateRidFromResource(GPU_GetCommonPointSampler()); - sig.instances = GPU_StructuredBufferRidFromResource(draw_rects_buffer); + sig.rects = GPU_StructuredBufferRidFromResource(draw_rects_buffer); GPU_Rasterize(cl, &sig, UI_RectVS, UI_RectPS, diff --git a/src/ui/ui.h b/src/ui/ui.h index 88ba2003..6db4a2ed 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -27,6 +27,53 @@ Struct(UI_Size) 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 @@ -71,6 +118,7 @@ Struct(UI_Box) u32 border_color; f32 border; f32 text_padding; + f32 rounding; Resource font_resource; f32 font_size; @@ -91,52 +139,6 @@ Struct(UI_BoxBin) 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 diff --git a/src/ui/ui_draw.gpu b/src/ui/ui_draw.gpu index 973fbd38..a862e52b 100644 --- a/src/ui/ui_draw.gpu +++ b/src/ui/ui_draw.gpu @@ -8,11 +8,11 @@ Struct(UI_RectPS_Input) { Semantic(Vec4, sv_position); + Semantic(nointerpolation u32, rect_idx); Semantic(Vec4, background_lin); Semantic(Vec4, border_lin); Semantic(Vec2, rect_uv); Semantic(Vec2, tex_uv); - Semantic(nointerpolation u32, instance_idx); }; 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)) { ConstantBuffer sig = UI_rect_sig; - StructuredBuffer instances = UniformResourceFromRid(sig.instances); - UI_RectInstance instance = instances[sv_instanceid]; + StructuredBuffer rects = UniformResourceFromRid(sig.rects); + UI_RectInstance rect = rects[sv_instanceid]; 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); + Vec2 tex_uv = lerp(rect.tex_uv0, rect.tex_uv1, rect_uv); + Vec2 screen_vert = lerp(rect.p0, rect.p1, rect_uv); UI_RectPS_Input result; result.sv_position = Vec4(NdcFromViewport(sig.viewport_size, screen_vert).xy, 0, 1); - result.background_lin = LinearFromSrgbU32(instance.background_srgb); - result.border_lin = LinearFromSrgbU32(instance.border_srgb); - result.instance_idx = sv_instanceid; + result.background_lin = LinearFromSrgbU32(rect.background_srgb); + result.border_lin = LinearFromSrgbU32(rect.border_srgb); + result.rect_idx = sv_instanceid; result.rect_uv = rect_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) { ConstantBuffer sig = UI_rect_sig; - StructuredBuffer instances = UniformResourceFromRid(sig.instances); - UI_RectInstance instance = instances[input.instance_idx]; + StructuredBuffer rects = UniformResourceFromRid(sig.rects); + UI_RectInstance rect = rects[input.rect_idx]; Vec4 result = 0; Vec2 p = input.sv_position.xy; - Vec2 p0 = instance.p0; - Vec2 p1 = instance.p1; + Vec2 p0 = rect.p0; + Vec2 p1 = rect.p1; Vec2 rect_uv = input.rect_uv; /* Background */ - if (instance.flags & UI_RectFlag_DrawTexture) + if (rect.flags & UI_RectFlag_DrawTexture) { SamplerState sampler = UniformSamplerFromRid(sig.sampler); - Texture2D tex = NonUniformResourceFromRid(instance.tex); + Texture2D tex = NonUniformResourceFromRid(rect.tex); result = tex.Sample(sampler, input.tex_uv); } else @@ -69,19 +69,51 @@ UI_RectPS_Output PSDef(UI_RectPS, UI_RectPS_Input input) result = input.background_lin; } - /* Border */ - Vec2 to_border = Vec2(0, 0); - 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); + Vec2 size = Vec2(p1.x - p0.x, p1.y - p0.y); + Vec2 half_size = size * 0.5; - 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; } - f32 border_thickness = instance.border; - UI_RectPS_Output output; output.sv_target0 = result; return output; diff --git a/src/ui/ui_draw.h b/src/ui/ui_draw.h index 517b12de..58315bd7 100644 --- a/src/ui/ui_draw.h +++ b/src/ui/ui_draw.h @@ -5,7 +5,7 @@ Struct(UI_RectSig) { /* ----------------------------------------------------- */ Vec2I32 viewport_size; /* 02 consts */ - StructuredBufferRid instances; /* 01 consts */ + StructuredBufferRid rects; /* 01 consts */ SamplerStateRid sampler; /* 01 consts */ /* ----------------------------------------------------- */ }; @@ -28,6 +28,7 @@ Struct(UI_RectInstance) Vec2 tex_uv0; Vec2 tex_uv1; Texture2DRid tex; + f32 rounding; }; //////////////////////////////////////////////////////////// diff --git a/src/ui/ui_extra.c b/src/ui/ui_extra.c index 6baf686c..793eea29 100644 --- a/src/ui/ui_extra.c +++ b/src/ui/ui_extra.c @@ -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); return box; diff --git a/src/ui/ui_extra.h b/src/ui/ui_extra.h index 62bc2749..5eb5fc90 100644 --- a/src/ui/ui_extra.h +++ b/src/ui/ui_extra.h @@ -6,6 +6,6 @@ UI_Box *UI_BuildLabel(String text); UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...); //////////////////////////////////////////////////////////// -//~ Separator widget +//~ Divider widget -UI_Box *UI_BuildSeparator(void); +UI_Box *UI_BuildDivider(void);