zig-zag collapsed profiler zone visualization

This commit is contained in:
jacob 2026-04-01 23:48:29 -05:00
parent a33b7346fa
commit 1c85ff19dd
8 changed files with 301 additions and 236 deletions

View File

@ -400,15 +400,17 @@
#define Rgba(r, g, b, a) VEC4((r), (g), (b), (a))
#define Rgb(r, g, b) VEC4((r), (g), (b), 1)
#define Color_White Rgba32(0xFFFFFFFF)
#define Color_Black Rgba32(0xFF000000)
#define Color_Red Rgba32(0xFF0000FF)
#define Color_Green Rgba32(0xFF00FF00)
#define Color_Blue Rgba32(0xFFFF0000)
#define Color_Yellow Rgba32(0xFF00FFFF)
#define Color_Orange Rgba32(0xFF00A5FF)
#define Color_Purple Rgba32(0xFFFF00FF)
#define Color_Cyan Rgba32(0xFFFFFF00)
#define Color_Transparent Rgba32(0)
#define Color_White Rgba32(0xFFFFFFFF)
#define Color_Black Rgba32(0xFF000000)
#define Color_Red Rgba32(0xFF0000FF)
#define Color_Green Rgba32(0xFF00FF00)
#define Color_Blue Rgba32(0xFFFF0000)
#define Color_Yellow Rgba32(0xFF00FFFF)
#define Color_Orange Rgba32(0xFF00A5FF)
#define Color_Purple Rgba32(0xFFFF00FF)
#define Color_Cyan Rgba32(0xFFFFFF00)
////////////////////////////////////////////////////////////
//~ Type helper macros

View File

@ -132,7 +132,7 @@ Struct(G_IndexBufferDesc)
#endif
////////////////////////////////////////////////////////////
//~ Debug printf
//~ Shader printf
Enum(G_FmtArgKind)
{
@ -190,7 +190,7 @@ Struct(G_FmtArg)
Struct(G_TempPrintBuffer)
{
// NOTE: The larger the array size, the longer the compilation time
// NOTE: Large array sizes can increase shader compilation time
u32 byte_chunks[64];
u32 bytes_count;
u32 chars_count;

View File

@ -4402,8 +4402,6 @@ void V_TickForever(WaveLaneCtx *lane)
b32 scrollbar_visible = new_thumb_height < track_height;
{
f32 ease_rate = TweakFloat("Debug palette ease rate", 20, 1, 100) * frame->dt;
f32 ease_in_target = TweakFloat("Debug palette ease-in target", 1.3, 0, 2);
@ -5495,24 +5493,6 @@ void V_TickForever(WaveLaneCtx *lane)
}
@ -5758,10 +5738,16 @@ void V_TickForever(WaveLaneCtx *lane)
//- Visible zones
//- Generate visible zones
Struct(VisZone)
{
VisZone *parent;
VisZone *next;
VisZone *next_bfs;
V_Zone *zone;
u32 depth;
u64 id;
String name;
@ -5788,18 +5774,9 @@ void V_TickForever(WaveLaneCtx *lane)
VisTrack *first_vis_track = 0;
VisTrack *last_vis_track = 0;
//- Compute visible zones
f32 zone_collapse_threshold_px = 10;
f32 min_zone_width_px = 1;
ProfZoneDF("Compute visible zones")
f32 min_zone_width_px = 5;
ProfZoneDF("Generate visible zones")
{
for (V_ZoneTrack *zone_track = V.first_zone_track; zone_track; zone_track = zone_track->next)
{
@ -5810,61 +5787,31 @@ void V_TickForever(WaveLaneCtx *lane)
SllQueuePush(first_vis_track, last_vis_track, vis_track);
vis_track->id = zone_track->id;
Struct(BfsZone) { BfsZone *next; V_Zone *zone; };
BfsZone *first_bfs_zone = 0;
BfsZone *last_bfs_zone = 0;
VisZone *first_bfs_vis_zone = 0;
VisZone *last_bfs_vis_zone = 0;
// Push root vis zone node to bfs
{
BfsZone *root_bfs = PushStruct(frame->arena, BfsZone);
VisZone *root_bfs = PushStruct(frame->arena, VisZone);
root_bfs->zone = zone_track->root_zone;
SllQueuePush(first_bfs_zone, last_bfs_zone, root_bfs);
root_bfs->start_px = -Inf;
root_bfs->end_px = Inf;
root_bfs->start_ns = I64Min;
root_bfs->end_ns = I64Max;
root_bfs->id = zone_track->root_zone->id;
SllQueuePushN(first_bfs_vis_zone, last_bfs_vis_zone, root_bfs, next_bfs);
}
VisZone *prev_vis_zone = 0;
V_Zone *prev_zone_parent = 0;
for (BfsZone *bfs_zone = first_bfs_zone; bfs_zone; bfs_zone = first_bfs_zone)
for (VisZone *parent_vis = first_bfs_vis_zone; parent_vis; parent_vis = first_bfs_vis_zone)
{
SllQueuePop(first_bfs_zone, last_bfs_zone);
V_Zone *zone = bfs_zone->zone;
SllQueuePopN(first_bfs_vis_zone, last_bfs_vis_zone, next_bfs);
V_Zone *parent = parent_vis->zone;
i64 zone_start_ns = zone->start_ns;
i64 zone_end_ns = MinI64(zone->end_ns, frame->time_ns);
i64 zone_elapsed_ns = zone_end_ns - zone_start_ns;
i64 visual_zone_start_ns = MaxI64(zone_start_ns, profiler->view_ns);
i64 visual_zone_end_ns = MinI64(zone_end_ns, profiler->view_ns + view_range_len_ns);
f64 visual_zone_start_px = visual_zone_start_ns / profiler->ns_per_px;
if (prev_vis_zone && prev_zone_parent == zone->parent)
// if (prev_vis_zone)
{
// visual_zone_start_px = MaxF64(visual_zone_start_px, prev_vis_zone->end_px + 1);
// f64 px = prev_vis_zone->end_px;
// prev_vis_zone->end_px = CeilF64(px);
// visual_zone_start_px = MaxF64(visual_zone_start_px, CeilF64(prev_vis_zone->end_px));
f64 px = prev_vis_zone->end_px;
prev_vis_zone->end_px = FloorF64(px);
visual_zone_start_px = CeilF64(px);
}
// f64 visual_zone_end_px = MaxF64(visual_zone_end_ns / profiler->ns_per_px, visual_zone_start_px + min_zone_width_px);
f64 visual_zone_end_px = visual_zone_end_ns / profiler->ns_per_px;
// f64 visual_zone_end_px = visual_zone_end_ns / profiler->ns_per_px - 1;
// visual_zone_start_px = FloorF64(visual_zone_start_px);
// visual_zone_end_px = CeilF64(visual_zone_end_px);
b32 is_root_zone = zone == zone_track->root_zone;
b32 should_collapse_zone = (zone_elapsed_ns / profiler->ns_per_px) <= zone_collapse_threshold_px && !is_root_zone;
// Push children to bfs queue
if (!should_collapse_zone && visual_zone_end_ns >= view_start_ns && visual_zone_start_ns <= view_end_ns)
// Process child zones
{
VisZone *left_vis = 0;
b32 reached_end_of_view = 0;
for (V_ZoneChunk *chunk = zone->first_chunk; chunk && !reached_end_of_view; chunk = chunk->next)
for (V_ZoneChunk *chunk = parent->first_chunk; chunk && !reached_end_of_view; chunk = chunk->next)
{
i64 chunk_start_ns = chunk->zones[0].start_ns;
i64 chunk_end_ns = MinI64(chunk->zones[chunk->count - 1].end_ns, frame->time_ns);
@ -5876,75 +5823,100 @@ void V_TickForever(WaveLaneCtx *lane)
// TODO: Binary search to find start
for (u64 chunk_zone_idx = 0; chunk_zone_idx < chunk->count && !reached_end_of_view; ++chunk_zone_idx)
{
V_Zone *child = &chunk->zones[chunk_zone_idx];
if (child->start_ns > view_end_ns)
V_Zone *zone = &chunk->zones[chunk_zone_idx];
if (zone->start_ns > view_end_ns)
{
reached_end_of_view = 1;
}
else
{
BfsZone *child_bfs = PushStruct(frame->arena, BfsZone);
child_bfs->zone = child;
SllQueuePush(first_bfs_zone, last_bfs_zone, child_bfs);
i64 zone_start_ns = zone->start_ns;
i64 zone_end_ns = MinI64(zone->end_ns, frame->time_ns);
i64 zone_elapsed_ns = zone_end_ns - zone_start_ns;
i64 visual_zone_start_ns = MaxI64(zone_start_ns, profiler->view_ns);
i64 visual_zone_end_ns = MinI64(zone_end_ns, profiler->view_ns + view_range_len_ns);
f64 visual_zone_start_px = visual_zone_start_ns / profiler->ns_per_px;
f64 visual_zone_end_px = visual_zone_end_ns / profiler->ns_per_px;
{
visual_zone_end_px = MaxF64(visual_zone_end_px, visual_zone_start_px + min_zone_width_px);
{
f32 overshoot = MaxF32(visual_zone_end_px - parent_vis->end_px, 0);
visual_zone_start_px -= overshoot;
visual_zone_end_px -= overshoot;
}
visual_zone_start_px = MaxF64(visual_zone_start_px, parent_vis->start_px);
if (left_vis)
{
visual_zone_start_px = MaxF64(visual_zone_start_px, left_vis->start_px);
}
}
b32 should_collapse_zone = (visual_zone_end_px - visual_zone_start_px) <= zone_collapse_threshold_px;
// Push vis zone
{
String zone_name = zone->name;
u64 zone_id = zone->id;
Vec4 zone_color = zone->color;
// b32 should_collapse_zone = visual_zone_len_px <= zone_collapse_threshold_px;
// b32 should_collapse_zone = 0;
// if (visual_zone_start_ns > view_end_ns)
// {
// reached_end_of_view = 1;
// }
if (visual_zone_end_ns >= view_start_ns && visual_zone_start_ns <= view_end_ns)
{
VisZone *vis_zone = 0;
if (
should_collapse_zone &&
left_vis &&
left_vis->collapsed_count > 0 &&
((zone_start_ns - left_vis->end_ns) / profiler->ns_per_px) < zone_collapse_threshold_px
)
{
vis_zone = left_vis;
}
else
{
vis_zone = PushStruct(frame->arena, VisZone);
vis_zone->zone = zone;
vis_zone->parent = parent_vis;
vis_zone->start_ns = zone_start_ns;
vis_zone->start_px = visual_zone_start_px;
vis_zone->name = zone_name;
vis_zone->id = zone_id;
}
SllQueuePush(vis_track->first_zone, vis_track->last_zone, vis_zone);
vis_zone->end_px = visual_zone_end_px;
vis_zone->end_ns = zone_end_ns;
vis_zone->color = zone_color;
vis_zone->depth = zone->depth;
vis_track->rows_count = MaxU32(vis_track->rows_count, vis_zone->depth);
if (should_collapse_zone)
{
vis_zone->collapsed_count += zone->total_descendents_count + 1;
}
left_vis = vis_zone;
if (!should_collapse_zone)
{
SllQueuePushN(first_bfs_vis_zone, last_bfs_vis_zone, vis_zone, next_bfs);
}
}
}
}
}
}
}
}
// Push vis zone
if (!is_root_zone)
{
String zone_name = zone->name;
u64 zone_id = zone->id;
Vec4 zone_color = zone->color;
// b32 should_collapse_zone = visual_zone_len_px <= zone_collapse_threshold_px;
// b32 should_collapse_zone = 0;
// if (visual_zone_start_ns > view_end_ns)
// {
// reached_end_of_view = 1;
// }
if (visual_zone_end_ns >= view_start_ns && visual_zone_start_ns <= view_end_ns)
{
VisZone *vis_zone = 0;
if (
should_collapse_zone &&
prev_vis_zone &&
prev_vis_zone->collapsed_count > 0 &&
prev_zone_parent == zone->parent &&
((zone_start_ns - prev_vis_zone->end_ns) / profiler->ns_per_px) < zone_collapse_threshold_px
)
{
vis_zone = prev_vis_zone;
}
else
{
vis_zone = PushStruct(frame->arena, VisZone);
vis_zone->start_ns = zone_start_ns;
vis_zone->start_px = visual_zone_start_px;
vis_zone->name = zone_name;
vis_zone->id = zone_id;
}
SllQueuePush(vis_track->first_zone, vis_track->last_zone, vis_zone);
vis_zone->end_px = visual_zone_end_px;
vis_zone->end_ns = zone_end_ns;
vis_zone->color = zone_color;
vis_zone->depth = zone->depth;
vis_track->rows_count = MaxU32(vis_track->rows_count, vis_zone->depth);
if (should_collapse_zone)
{
vis_zone->collapsed_count += zone->total_descendents_count + 1;
}
prev_vis_zone = vis_zone;
prev_zone_parent = zone->parent;
}
}
}
}
}
@ -5970,6 +5942,9 @@ void V_TickForever(WaveLaneCtx *lane)
main_color_unsampled.g *= 0.85;
main_color_unsampled.b *= 0.85;
Vec4 collapsed_line_color = SrgbFromHsv(64, 1, 0.5);
Vec4 collapsed_text_color = SrgbFromHsv(64, 1, 0.75);
// main_color_sampled.g += 0.05;
UI_SetNext(Parent, vis_ui_box);
@ -6091,6 +6066,7 @@ void V_TickForever(WaveLaneCtx *lane)
f64 zone_offset_px = zone->start_px - view_start_px;
f64 zone_len_px = zone->end_px - zone->start_px;
Vec2 zone_pos = VEC2(zone_offset_px, 0);
UI_Size zone_width = UI_Px(zone_len_px, 1);
@ -6099,34 +6075,99 @@ void V_TickForever(WaveLaneCtx *lane)
zone_color_bd = MulVec4(zone_color_bd, 0.65);
zone_color_bd.a = 1;
zone_color_bd = LerpSrgb(zone_color_bd, Color_White, zone_hovered);
Vec4 zone_text_color = UI_Top(TextColor);
zone_text_color.a *= 0.75;
Vec4 zone_line_color = Zi;
// b32 is_collapsed = zone->is_collapsed;
b32 is_collapsed = zone->collapsed_count > 1;
UI_Size collapsed_line_size = UI_Fnt(0.1, 1);
b32 is_collapsed = zone->collapsed_count > 0;
// b32 is_collapsed = zone->collapsed_count > 0 || zone_len_px <= min_zone_width_px;
// UI_Size collapsed_line_size = UI_Px(2, 1);
UI_Size collapsed_line_size = UI_Px(1.5, 1);
// Vec4 collapsed_text_color = theme.col.positive;
Vec4 collapsed_line_color = theme.col.negative;
// Vec4 collapsed_line_color = theme.col.negative;
// Vec4 collapsed_line_color = SrgbFromHsv(TweakFloat("RAAAAAAAAAH H", 100, 0, 360), TweakFloat("RAAAAAAAAAH S", 0.50, 0, 1), TweakFloat("RAAAAAAAAAH V", 1.00, 0, 1));
// Vec4 collapsed_line_color = Color_Black;
// Vec4 collapsed_line_color = theme.col.hint;
Vec4 collapsed_text_color = theme.col.positive;
// Vec4 collapsed_line_color = collapsed_text_color;
collapsed_text_color = LerpSrgb(collapsed_text_color, Color_White, zone_hovered);
collapsed_line_color = LerpSrgb(collapsed_line_color, Color_White, zone_hovered);
// Vec4 collapsed_text_color = theme.col.positive;
// Vec4 collapsed_text_color = SrgbFromHsv(TweakFloat("RAAAAAAAAAH H", 100, 0, 360), TweakFloat("RAAAAAAAAAH S", 0.50, 0, 1), TweakFloat("RAAAAAAAAAH V", 1.00, 0, 1));
// Vec4 collapsed_line_color = SrgbFromHsv(32, 1, 0.5);
// Vec4 collapsed_text_color = SrgbFromHsv(32, 1, 1);
// Vec4 collapsed_line_color = SrgbFromHsv(64, 1, 0.5);
// Vec4 collapsed_text_color = SrgbFromHsv(64, 1, 0.75);
// collapsed_text_color = LerpSrgb(collapsed_text_color, Color_White, zone_hovered);
// collapsed_line_color = LerpSrgb(collapsed_line_color, Color_White, zone_hovered);
String zone_text = zone->name;
if (is_collapsed)
{
zone_text = StringF(frame->arena, "%F", FmtUint(zone->collapsed_count));
zone_text = Zstr;
if (zone->collapsed_count > 1)
{
zone_text = StringF(frame->arena, "%F", FmtUint(zone->collapsed_count));
}
zone_text_color = collapsed_text_color;
zone_line_color = collapsed_line_color;
// zone_color = VEC4(0, 0, 0, 0);
// zone_color = VEC4(1, 0, 1, 1);
// zone_color = VEC4(0.15, 0.15, 0.15, 0.5);
zone_color = VEC4(0.20, 0.20, 0.20, 0.5);
// zone_color = VEC4(0.20, 0.20, 0.20, 0.5);
zone_color = VEC4(0.25, 0.25, 0.25, 0.5);
// if (zone->collapsed_count > 1)
// {
// zone_color = VEC4(0.25, 0.25, 0.25, 0.5);
// }
// else
// {
// zone_color = Color_White;
// }
// zone_color = VEC4(0.4, 0.4, 0.4, 0.5);
zone_color_bd = VEC4(0, 0, 0, 0);
// zone_color = LerpSrgb(zone_color, Color_Transparent, zone_hovered);
}
zone_color_bd = LerpSrgb(zone_color_bd, Color_White, zone_hovered * !is_collapsed);
zone_text_color = LerpSrgb(zone_text_color, Color_White, zone_hovered);
zone_line_color = LerpSrgb(zone_line_color, Color_White, zone_hovered);
f32 collapsed_zones_per_px = zone->collapsed_count / zone_len_px;
// f32 zag_intensity = 50 / collapsed_zones_per_px;
// zag_intensity = MaxF32(zag_intensity, 5);
// f32 top_zag_information_density = 10;
f32 top_zag_information_density = zone_collapse_threshold_px;
f32 zag_intensity = SmoothstepF32(0, top_zag_information_density, collapsed_zones_per_px);
// f32 zag_intensity = TweakFloat("RAAAAAAAAAAAAAH", 1, 0, 1);
f32 period_max = 20;
f32 period_min = 5;
f32 zag_period = LerpF32(period_max, period_min, zag_intensity);
f32 amplitude_max = UI_Top(FontSize) * 0.15;
f32 amplitude_min = UI_Top(FontSize) * 0.05;
f32 zag_amplitude = LerpF32(amplitude_max, amplitude_min, zag_intensity);
UI_SetNext(Width, zone_width);
UI_SetNext(Height, UI_Grow(1, 0));
UI_SetNext(BackgroundColor, zone_color);
@ -6134,41 +6175,48 @@ void V_TickForever(WaveLaneCtx *lane)
UI_SetNext(BorderSize, 1);
UI_SetNext(FloatingPos, zone_pos);
UI_SetNext(ChildAlignment, UI_Region_Center);
UI_SetNext(Flags, UI_BoxFlag_Floating | UI_BoxFlag_DontClampFloatingX | UI_BoxFlag_DontClampFloatingY | UI_BoxFlag_CaptureMouse | UI_BoxFlag_Scissor);
UI_SetNext(
Flags,
UI_BoxFlag_Floating |
UI_BoxFlag_DontClampFloatingX |
UI_BoxFlag_DontClampFloatingY |
UI_BoxFlag_CaptureMouse |
UI_BoxFlag_Scissor
);
UI_SetNext(Parent, zone_row_box);
UI_SetDF(OrFlags, UI_Top(OrFlags) | (UI_BoxFlag_DontTruncateText * !!(is_collapsed)))
UI_SetDF(OmitFlags, UI_Top(OmitFlags) | (UI_BoxFlag_Scissor * !!(is_collapsed)))
// UI_SetDF(OmitFlags, UI_Top(OmitFlags) | (UI_BoxFlag_Scissor * !!(is_collapsed)))
// UI_SetDF(ZagPeriod, UI_Top(FontSize) * 1)
// UI_SetDF(ZagPeriod, (collapsed_zones_per_px * UI_Top(FontSize)) * 0.1)
// UI_SetDF(ZagPeriod, collapsed_zones_per_px / (UI_Top(FontSize) * 1))
UI_SetDF(ZagPeriod, zag_period)
UI_SetDF(ZagThickness, 1.5)
UI_SetDF(ZagRoundness, 0)
UI_SetDF(ZagAmplitude, zag_amplitude)
UI_SetDF(Parent, UI_BuildRowEx(zone_box))
{
// Left collapsed lines
if (is_collapsed)
{
// Vertical line
{
UI_SetDF(Opacity, 1.0 - zone_hovered)
UI_SetNext(BackgroundColor, collapsed_line_color);
UI_SetNext(Width, collapsed_line_size);
UI_SetNext(Height, UI_Grow(1, 0));
UI_BuildBox();
}
// // Vertical line
// {
// UI_SetDF(Opacity, 1.0 - zone_hovered)
// UI_SetNext(BackgroundColor, collapsed_line_color);
// UI_SetNext(Width, collapsed_line_size);
// UI_SetNext(Height, UI_Grow(1, 0));
// UI_BuildBox();
// }
// Horizontal line
UI_SetDF(Parent, UI_BuildColumn())
// Zag
{
UI_BuildSpacer(UI_Grow(1, 0), Axis_Y);
UI_SetNext(Width, UI_Grow(1, 0));
UI_SetNext(Height, collapsed_line_size);
// UI_SetNext(Anchor, UI_Region_Center);
UI_SetNext(BackgroundColor, collapsed_line_color);
UI_SetNext(ZagColor, zone_line_color);
UI_BuildBox();
UI_BuildSpacer(UI_Grow(1, 0), Axis_Y);
}
}
// Zone name
if (zone_len_px > zone_collapse_threshold_px * 3)
// if (zone_len_px > zone_collapse_threshold_px * 3)
{
if (is_collapsed)
{
@ -6189,29 +6237,22 @@ void V_TickForever(WaveLaneCtx *lane)
// Right collapsed lines
if (is_collapsed)
{
// Horizontal line
// UI_SetNext(Flags, UI_BoxFlag_Floating);
// UI_SetDF(Opacity, 0.25)
UI_SetDF(Parent, UI_BuildColumn())
// Zag
{
UI_BuildSpacer(UI_Grow(1, 0), Axis_Y);
UI_SetNext(Width, UI_Grow(1, 0));
UI_SetNext(Height, collapsed_line_size);
// UI_SetNext(Anchor, UI_Region_Center);
UI_SetNext(BackgroundColor, collapsed_line_color);
UI_BuildBox();
UI_BuildSpacer(UI_Grow(1, 0), Axis_Y);
}
// Vertical line
{
UI_SetNext(BackgroundColor, collapsed_line_color);
UI_SetNext(Width, collapsed_line_size);
UI_SetNext(Height, UI_Grow(1, 0));
UI_SetNext(ZagColor, zone_line_color);
UI_BuildBox();
}
// // Vertical line
// {
// UI_SetDF(Opacity, 1.0 - zone_hovered)
// UI_SetNext(BackgroundColor, collapsed_line_color);
// UI_SetNext(Width, collapsed_line_size);
// UI_SetNext(Height, UI_Grow(1, 0));
// UI_SetNext(Anchor, UI_Region_Right);
// UI_BuildBox();
// }
}
}
}
@ -6347,10 +6388,9 @@ void V_TickForever(WaveLaneCtx *lane)
UI_SetDF(Parent, UI_BuildRow())
{
UI_SetNext(TextColor, theme.col.hint);
// UI_BuildLabelF("Collapsed zones");
UI_BuildLabelF("Multiple zones");
UI_BuildLabelF("Zones too small to display");
UI_SetNext(TextColor, theme.col.positive);
UI_SetNext(TextColor, collapsed_text_color);
UI_BuildLabelF(" (%F)", FmtUint(zone->collapsed_count));
}
}
@ -6408,39 +6448,6 @@ void V_TickForever(WaveLaneCtx *lane)
//////////////////////////////
//- Build notifications

View File

@ -489,6 +489,11 @@ UI_Key UI_BuildBoxEx(UI_Key semantic_key)
n->cmd.box.sprite_span = UI_Top(SpriteSpan);
n->cmd.box.sprite_seq = UI_Top(SpriteSeq);
n->cmd.box.misc = UI_Top(Misc);
n->cmd.box.zag_color = UI_Top(ZagColor);
n->cmd.box.zag_period = UI_Top(ZagPeriod);
n->cmd.box.zag_amplitude = UI_Top(ZagAmplitude);
n->cmd.box.zag_thickness = UI_Top(ZagThickness);
n->cmd.box.zag_roundness = UI_Top(ZagRoundness);
}
++frame->cmds_count;
SllQueuePush(frame->first_cmd_node, frame->last_cmd_node, n);
@ -1831,10 +1836,10 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
final_tint_lin.a *= box->solved_opacity;
Vec4 final_border_color_lin = LinearFromSrgb(box->desc.border_color);
final_border_color_lin.a *= box->solved_opacity;
Vec4 final_zag_lin = LinearFromSrgb(box->desc.zag_color);
Vec4 final_text_color_lin = LinearFromSrgb(box->desc.text_color);
final_text_color_lin.a *= box->desc.opacity;
final_text_color_lin = MulVec4Vec4(final_text_color_lin, final_tint_lin);
f32 alpha_cull_threshold = 0.0025;
@ -1851,7 +1856,8 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
!SPR_IsSheetKeyNil(box->desc.sprite_sheet) ||
(AnyBit(box->desc.flags, UI_BoxFlag_DrawText) && raw_run.ready) ||
final_tint_lin.a * box->desc.background_color.a >= alpha_cull_threshold ||
final_tint_lin.a * box->desc.border_color.a >= alpha_cull_threshold
final_tint_lin.a * box->desc.border_color.a >= alpha_cull_threshold ||
(box->desc.zag_thickness > 0 && final_tint_lin.a * final_zag_lin.a >= alpha_cull_threshold)
);
should_upload_box = should_upload_box && (!IsRng2Empty(IntersectRng2(box->screen_rect, box->solved_scissor)));
should_upload_text = should_upload_text && should_upload_box && final_text_color_lin.a > alpha_cull_threshold;
@ -1879,6 +1885,11 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
rect->tr_rounding = box->rounding_tr;
rect->br_rounding = box->rounding_br;
rect->bl_rounding = box->rounding_bl;
rect->zag_lin = final_zag_lin;
rect->zag_period = box->desc.zag_period;
rect->zag_amplitude = box->desc.zag_amplitude;
rect->zag_thickness = box->desc.zag_thickness;
rect->zag_roundness = box->desc.zag_roundness;
if (!G_IsRefNil(box->raw_texture))
{
rect->tex = box->raw_texture;

View File

@ -152,6 +152,11 @@ Enum(UI_DebugBreakFlag)
X(BackgroundTexture, G_TextureRef) \
X(BackgroundTextureSliceUv, Rng2) \
X(Misc, f64) \
X(ZagColor, Vec4) \
X(ZagPeriod, f32) \
X(ZagAmplitude, f32) \
X(ZagThickness, f32) \
X(ZagRoundness, f32) \
/* --------------------------------------------- */ \
/* --------------- Virtual styles -------------- */ \
/* --------------------------------------------- */ \
@ -290,6 +295,11 @@ Struct(UI_BoxDesc)
SPR_SpanKey sprite_span;
i64 sprite_seq;
f64 misc;
Vec4 zag_color;
f32 zag_period;
f32 zag_amplitude;
f32 zag_thickness;
f32 zag_roundness;
};
Struct(UI_Cmd)

View File

@ -20,6 +20,7 @@ VertexShader(UI_DRectVS, UI_DRectPSInput)
result.base_background_premul = Premul(rect.background_lin);
result.base_border_premul = Premul(rect.border_lin);
result.tint_premul = Premul(rect.tint_lin);
result.zag_premul = Premul(rect.zag_lin);
result.debug_premul = Premul(rect.debug_lin);
result.rect_uv = rect_uv;
result.tex_uv = tex_uv;
@ -77,6 +78,33 @@ PixelShader(UI_DRectPS, UI_DRectPSOutput, UI_DRectPSInput input)
background_premul = tex.SampleLevel(sampler, input.tex_uv, 0);
background_premul.rgb *= background_premul.a;
}
//- Blend zig-zag color
if (rect.zag_thickness > 0 && input.zag_premul.a != 0)
{
f32 zag_strength = 0;
{
f32 period = rect.zag_period;
f32 amplitude = rect.zag_amplitude;
f32 thickness = rect.zag_thickness;
f32 roundness = rect.zag_roundness;
{
f32 center_y = (p1.y - p0.y) * 0.5f;
f32 z = 0;
{
f32 x = p.x / period;
f32 tri_wave = abs(frac(x) * 2 - 1) * 2 - 1;
f32 sin_wave = sin(x * Tau);
z = lerp(tri_wave, sin_wave, roundness);
}
f32 y = center_y + z * amplitude;
f32 d = abs((p.y - p0.y) - y);
f32 smoothness = 1;
zag_strength = 1.0 - smoothstep(thickness - smoothness, thickness + smoothness, d);
}
}
background_premul = lerp(background_premul, input.zag_premul, zag_strength);
}
}
//- Compute border dist

View File

@ -7,6 +7,7 @@ Struct(UI_DRectPSInput)
Vec4 Semantic(base_background_premul);
Vec4 Semantic(base_border_premul);
Vec4 Semantic(tint_premul);
Vec4 Semantic(zag_premul);
Vec4 Semantic(debug_premul);
Vec2 Semantic(rect_uv);
Vec2 Semantic(tex_uv);

View File

@ -25,6 +25,12 @@ Struct(UI_GpuRect)
f32 tr_rounding;
f32 br_rounding;
f32 bl_rounding;
Vec4 zag_lin;
f32 zag_period;
f32 zag_amplitude;
f32 zag_thickness;
f32 zag_roundness;
};
////////////////////////////////////////////////////////////