From bf1e8aaac2130031730a61dd92c5c48daf021a15 Mon Sep 17 00:00:00 2001 From: Matthew Date: Mon, 22 Dec 2025 15:05:54 +1100 Subject: [PATCH] add support for scissoring views, fix text culling issues --- assets/gui.frag.spv | Bin 6008 -> 5952 bytes assets/gui.vert.spv | Bin 8996 -> 8832 bytes src/VulkanRenderer | 2 +- src/editor/editor.d | 4 +- src/editor/ui.d | 290 ++++++++++++++++++++++++++------------ src/editor/views.d | 6 +- src/shaders/gui.frag.glsl | 2 - src/shaders/gui.vert.glsl | 21 ++- 8 files changed, 215 insertions(+), 110 deletions(-) diff --git a/assets/gui.frag.spv b/assets/gui.frag.spv index 339a727bf610352b695b95fd2e9fb47e60049311..c23da8be2177f7c132a9a5aa3f4209efd27bb945 100644 GIT binary patch delta 68 zcmeyNcR+7L9S5W9=6Vh;Mz&go0B38i&GR{bvQJ(kD8cBy`KX{hvm_4#2M{tav;#3S R5E}xqBoJ3@HWYPd0sxAZ4(b2^ delta 122 zcmX@0_d{<(9S5W5=6Vh;MlsH^)MO)tr2NvnlwxbHT7>{-Yc2+c&HbD|*>zhPSQ$7N z7#L!KSQm)hfS3m;0uqY{VrC#V1Y$`bj@`Ua(4JWkrll1q1kzGI`L2jGW9#OhBJNB8 DU2_+1 diff --git a/assets/gui.vert.spv b/assets/gui.vert.spv index d5ad7a19261ea61ce9c401eb463a2e08ae35a877..fb74b31caffce249b1f43744b54ad939df91ea75 100644 GIT binary patch delta 898 zcmY+CO-NKx6vywGH{(2=8F|wnInKv>(+4GEIFl%v+9WpVWaNkxSy+UX4GtP;n;^_Z z5J8LS6uB&LQH!7$h!zQLTD5AIVFb~~C>D$^T3P*%&0BQf_s%{4bKW_Zd+)-L8|hlj zvD2+wq&&)}{-{E27X=FgqqJIhnxPkkU)T5wHS#=o4NAap?Bgy+oG-!Og@5JP&p#Zu ziw`xgP6;l0x}8c>>Eec`hN`Yx+1}2YV!)Ty{4U7LN~vtGQZ7}cN_@xI9xOo-8_%E1 zPEF@#a#NGYxshEoLR8`)r8GeWAPh^Cg`Y<4JCnWu1&ev47O5|PXwDIyP=33 z#Ee?_I$;0N!jFRE)XLQj4_I$7_*ugRYUjGpm{0oKRULdY6#q{-z>A>?>fy%l1n&(S zybx~Zd+=-U%VC|HB4J8%CKC4_LLV`iJ`I11lhFXrN9rlV&m$%s<#+fFa2elY?2pE& zkGrEGI?f}}K^o*I(J>lgpE=B4)601?Ps6-qHuHPa;Cjnq-7>h}vgjn|tQ22H^wLVu zDPFOfX@rBZ6rJXg*aV&7H?cU4ayd3Uo5d@Ud-w`IgD;>B_(1{ZE4gpr6ObDF9L{1b zHiR0vlQkf9Vz%}ZYtiIBY^_|;_;&qjuqMk)yIm zIh9)xB{npWH*v5h>!VU?C2_BV9w*i&d6c&B9C!kjL4mE3BerdP0d@}dnXQJ`Z8zNK zN8+(@bFz16w0~fNV_FH-B`36eM@~k%>1@@UqKZc`9|`UexJzAGX-ru?f>+xKz<)+OZN)EcUiHfq>Bwm zeWs%mv5br+dlyZtr7;y2QYu+o_{i?GTgO{ODwh{a>!!nKvK^5eN+uYHmth^C8U*Bk zu$$AGhaMIc9#vZ%d7Kj*>&2*ZtocF<{57v{uXPZHE$2EdPDyyVczN+ru}@&H_YvZ&bm=g z2e`v%qZUpW71YWPjSw~Qd&9?uUuPF+0F|H{90FJT4(|7R=rB+DL;TZl@B@Dlb@GD0 zlcHQ4=;Idw7taRTsf%9*F7tR$=c7TB=V51qCLQNH!745?bzTZq(+Ms%BXp9FnN@U( zufadf3+6C&b4_`O&Tvn8*K}k0vOeKb 0.0009) + { + for(UIItem* c = item.last; !Nil(c); c = c.prev) + { + f32 reduced = Min(excess, c.size[axis]); + excess -= reduced; + c.size.v[axis] -= reduced; + + if(excess < 0.0009) + { + break; + } + } + + assert(excess < 0.0009); + } + } + } + else + { + for(UIItem* c = item.first; !Nil(c); c = c.next) + { + c.size.v[axis] = c.size.v[axis] > size ? size : c.size.v[axis]; } } } @@ -1017,6 +1065,28 @@ EndUI() assert(!isNaN(item.rect.p0.v[axis])); assert(!isNaN(item.rect.p1.v[axis])); + debug + { + bool portal = cast(bool)(item.parent.flags & (UIF.PortalViewX << axis)); + + if(!portal && item != ctx.root) + { + UIItem* p = item.parent; + f32 i0 = item.rect.p0.v[axis]; + f32 i1 = item.rect.p1.v[axis]; + f32 p0 = item.parent.rect.p0.v[axis] + item.parent.border_thickness; + f32 p1 = item.parent.rect.p1.v[axis] - item.parent.border_thickness; + + bool in_bounds_start = i0 >= p0; + bool in_bounds_end = i1 <= p1; + if(!in_bounds_start || !in_bounds_end) + { + Errf("[%s] failed bounds check, item bounds: [%s] parent bounds: [%s]", item.key.hash_text, [i0, i1], [p0, p1]); + } + assert(in_bounds_start && in_bounds_end); + } + } + next_pos = item.parent.layout_axis == axis ? end_pos : pos; if(!Nil(item.first)) @@ -1051,13 +1121,12 @@ EndUI() RenderItems(ctx.root); RenderItems(ctx.window_root); - version(ENABLE_RENDERER) with(ctx) + version(ENABLE_RENDERER) { - BindBuffers(&rd, &buffers[f_idx].m_idx, &buffers[f_idx].m_vtx); - DrawIndexed(&rd, 6, buffers[f_idx].count, 0); + DrawUI(ctx); - FinishRendering(&rd); - SubmitAndPresent(&rd); + FinishRendering(&ctx.rd); + SubmitAndPresent(&ctx.rd); } if(!Nil(ctx.drag_item)) @@ -1073,69 +1142,116 @@ EndUI() } } +void +RenderItem(UICtx* ctx, UIItem* item) +{ + if(item.rendered) return; + + // Doesn't really support nesting scissors, will maybe change this later. + bool scissor_x = cast(bool)(item.flags & UIF.PortalViewX); + bool scissor_y = cast(bool)(item.flags & UIF.PortalViewY); + if(scissor_x || scissor_y) + { + DrawUI(ctx); + + u32 x = cast(u32)(scissor_x ? floor(item.rect.p0.x) : ctx.res.x); + u32 y = cast(u32)(scissor_y ? floor(item.rect.p0.y) : ctx.res.y); + u32 w = cast(u32)(scissor_x ? floor(item.rect.p1.x) - x : ctx.res.x); + u32 h = cast(u32)(scissor_y ? floor(item.rect.p1.y) - y : ctx.res.y); + SetScissor(&ctx.rd, x, y, w, h); + } + + if(item.flags & UIF.DrawBackground) + { + // DrawRect + Vertex* v = GetVertex(ctx); + v.dst_start = item.rect.p0 + item.border_thickness; + v.dst_end = item.rect.p1 - item.border_thickness; + v.cols = item.bg_col; + v.corner_radius = item.corner_radius; + v.bounds = ItemBounds(item.parent); + + AddVertexCount(ctx); + } + + if(item.flags & UIF.DrawBorder) + { + Vertex* v = GetVertex(ctx); + v.dst_start = item.rect.p0; + v.dst_end = item.rect.p1; + v.cols = item.border_col; + v.corner_radius = item.corner_radius; + v.border_thickness = item.border_thickness; + v.edge_softness = item.edge_softness; + v.bounds = ItemBounds(item.parent); + + AddVertexCount(ctx); + } + + if(item.flags & UIF.DrawText || item.display_string) + { + if(item.flags & UIF.CenterAlignText) + { + // TODO + } + else + { + FontAtlas* atl = &ctx.atlas_buf.atlas; + + f32 y_pos = item.rect.p0.y + item.padding.y; + + foreach(i; 0 .. item.text_lines.length) + { + string str = item.text_lines[i]; + + f32 x_pos = item.flags & UIF.RightAlignText ? item.rect.p1.x - item.padding.x - CalcTextWidth(str) : + item.rect.p0.x + item.padding.x; + + x_pos = clamp(x_pos, item.rect.p0.x, item.rect.p1.x); + + foreach(j; 0 .. str.length) + { + u8 ch = str[j]; + Glyph* g = ch < atl.glyphs.length ? atl.glyphs.ptr + ch : null; + DrawGlyph(item, g, &x_pos, y_pos); + } + + y_pos += TEXT_SIZE; + } + } + } + + if(scissor_x || scissor_y) + { + UIItem* first = item.first; + UIItem* last = item.last; + + item.first = item.last = g_UI_NIL; + + UIItem* next = Recurse!(true)(item, g_UI_NIL); + + item.first = first; + item.last = last; + + for(UIItem* d = item.first; !Nil(d) && d != next; d = Recurse!(true)(d, g_UI_NIL)) + { + RenderItem(ctx, d); + d.rendered = true; + } + + DrawUI(ctx); + + ResetScissor(&ctx.rd); + } +} + void RenderItems(UIItem* root) { UICtx* ctx = GetCtx(); for(UIItem* item = root; !Nil(item); item = Recurse!(true)(item, g_UI_NIL)) { - if(item.flags & UIF.DrawBackground) - { - // DrawRect - Vertex* v = GetVertex(ctx); - v.dst_start = item.rect.p0 + item.border_thickness; - v.dst_end = item.rect.p1 - item.border_thickness; - v.cols = item.bg_col; - v.corner_radius = item.corner_radius; - v.bounds = ItemBounds(item.parent); - - AddVertexCount(ctx); - } - - if(item.flags & UIF.DrawBorder) - { - Vertex* v = GetVertex(ctx); - v.dst_start = item.rect.p0; - v.dst_end = item.rect.p1; - v.cols = item.border_col; - v.corner_radius = item.corner_radius; - v.border_thickness = item.border_thickness; - v.edge_softness = item.edge_softness; - v.bounds = ItemBounds(item.parent); - - AddVertexCount(ctx); - } - - if(item.flags & UIF.DrawText || item.display_string) - { - if(item.flags & UIF.CenterAlignText) - { - // TODO - } - else - { - FontAtlas* atl = &ctx.atlas_buf.atlas; - - f32 y_pos = item.rect.p0.y + item.padding.y; - - foreach(i; 0 .. item.text_lines.length) - { - string str = item.text_lines[i]; - - f32 x_pos = item.flags & UIF.RightAlignText ? item.rect.p1.x - item.padding.x - CalcTextWidth(str) : - item.rect.p0.x + item.padding.x; - - foreach(j; 0 .. str.length) - { - u8 ch = str[j]; - Glyph* g = ch < atl.glyphs.length ? atl.glyphs.ptr + ch : null; - DrawGlyph(item, g, &x_pos, y_pos); - } - - y_pos += TEXT_SIZE; - } - } - } + RenderItem(ctx, item); } } @@ -1568,17 +1684,10 @@ DrawGlyph(UIItem* item, Glyph* glyph, f32* x_pos, f32 y) v.src_end = Vec2(gb.atlas_r, gb.atlas_b); } - /* f32 end_x = *x_pos + advance; f32 width = end_x - *x_pos; - f32 bound_x = item.flags & UIF.RightAlignText ? item.rect.p0.x : item.rect.p1.x; - if(item.flags & UIF.RightAlignText && bound_x > *x_pos) - { - f32 cull_pct = (bound_x - *x_pos) / width; - v.dst_start.x += (v.dst_end.x - v.dst_start.x) * cull_pct; - v.src_start.x += (v.src_end.x - v.src_start.x) * cull_pct; - } - else if(!(item.flags & UIF.RightAlignText) && end_x > bound_x) + f32 bound_x = item.rect.p1.x; + if(end_x > bound_x) { f32 cull_pct = (end_x - bound_x) / width; v.dst_end.x -= (v.dst_end.x - v.dst_start.x) * cull_pct; @@ -1601,7 +1710,6 @@ DrawGlyph(UIItem* item, Glyph* glyph, f32* x_pos, f32 y) v.pos[i].end[axis] = v.pos[i].start.v[axis] > v.pos[i].end.v[axis] ? v.pos[i].start.v[axis] : v.pos[i].end.v[axis]; } } - */ AddVertexCount(ctx); diff --git a/src/editor/views.d b/src/editor/views.d index f42a734..40a2961 100644 --- a/src/editor/views.d +++ b/src/editor/views.d @@ -23,7 +23,7 @@ EditorView(Editor* ed) UIItem* editor = Get(ed_key); u64 frame_line_offset = ed.line_offset; - u64 frame_view_offset = editor.scroll_offset%TEXT_SIZE; + f32 frame_view_offset = editor.scroll_offset.y%TEXT_SIZE; Push!("border_col" )(ctx, Vec4Arr(Vec4(1.0))); @@ -72,8 +72,8 @@ EditorView(Editor* ed) Push!("parent" )(ctx, line_count); Push!("text_col" )(ctx, Vec4(1.0)); - u64 i = prev_offset; - for(LineBuffer* lb = GetLine(&ed.buf, i); i < prev_offset+view_lines; i += 1) + u64 i = frame_line_offset; + for(LineBuffer* lb = GetLine(&ed.buf, i); i < frame_line_offset+view_lines; i += 1) { } diff --git a/src/shaders/gui.frag.glsl b/src/shaders/gui.frag.glsl index d84a0d5..5ae2b2a 100644 --- a/src/shaders/gui.frag.glsl +++ b/src/shaders/gui.frag.glsl @@ -14,8 +14,6 @@ layout (location = 1) in struct FragDataIn { vec2 dst_center; vec2 dst_half_size; vec2 sdf_sample_pos; - vec2 bounds_p0; - vec2 bounds_p1; float corner_radius; float softness; float raised; diff --git a/src/shaders/gui.vert.glsl b/src/shaders/gui.vert.glsl index eea89ed..e4919ab 100644 --- a/src/shaders/gui.vert.glsl +++ b/src/shaders/gui.vert.glsl @@ -8,16 +8,15 @@ layout (location = 0) in vec4 in_col_1; layout (location = 1) in vec4 in_col_2; layout (location = 2) in vec4 in_col_3; layout (location = 3) in vec4 in_col_4; -layout (location = 4) in vec4 in_bounds; -layout (location = 5) in vec2 in_dst_start; -layout (location = 6) in vec2 in_dst_end; -layout (location = 7) in vec2 in_src_start; -layout (location = 8) in vec2 in_src_end; -layout (location = 9) in float border_thickness; -layout (location = 10) in float corner_radius; -layout (location = 11) in float edge_softness; -layout (location = 12) in float raised; -layout (location = 13) in uint in_has_texture; +layout (location = 4) in vec2 in_dst_start; +layout (location = 5) in vec2 in_dst_end; +layout (location = 6) in vec2 in_src_start; +layout (location = 7) in vec2 in_src_end; +layout (location = 8) in float border_thickness; +layout (location = 9) in float corner_radius; +layout (location = 10) in float edge_softness; +layout (location = 11) in float raised; +layout (location = 12) in uint in_has_texture; layout (location = 0) flat out uint out_has_texture; @@ -91,6 +90,6 @@ void main() FragData.sdf_sample_pos = (2.0f * dst_verts_pct - 1.0f) * half_size; out_has_texture = in_has_texture; - vec4 v_pos = PC.projection * vec4(pos.x, pos.y, z_index, 1); + vec4 v_pos = PC.projection * vec4(pos.x, pos.y, 0, 1); gl_Position = vec4(v_pos.x, v_pos.y, v_pos.z, 1); }