add support for scissoring views, fix text culling issues
This commit is contained in:
parent
9950647cf9
commit
bf1e8aaac2
Binary file not shown.
Binary file not shown.
@ -1 +1 @@
|
||||
Subproject commit b3639d9c884c09fb98b750ba613118d633470312
|
||||
Subproject commit 11cf96b799c6ccee3c4f569e89c263d11c4d5ff8
|
||||
@ -192,12 +192,12 @@ Cycle(EditorCtx* ctx, Inputs* inputs)
|
||||
Push!("bg_col", true)(ui_ctx, white);
|
||||
Push!("text_col", true)(ui_ctx, black[0]);
|
||||
Push!("padding", true)(ui_ctx, Vec2(8.0));
|
||||
UIItem* text2 = MakeItem("A different line of text for testing purposes##text", UIF.DrawBackground|UIF.DrawText|UIF.TextWrap);
|
||||
UIItem* text2 = MakeItem("A different line of text for testing purposes##text2", UIF.DrawBackground|UIF.DrawText|UIF.TextWrap);
|
||||
|
||||
Pop!("parent")(ui_ctx);
|
||||
Pop!("parent")(ui_ctx);
|
||||
|
||||
Push!("size_info", true)(ui_ctx, MakeUISizeX(ST.Pixels, 2.0));
|
||||
Push!("size_info", true)(ui_ctx, MakeUISizeX(ST.Pixels, 100.0));
|
||||
Push!("bg_col", true)(ui_ctx, black);
|
||||
UIItem* sep = MakeItem("###sep", UIF.Draggable|UIF.DrawBackground|UIF.ResizeAdjacent);
|
||||
|
||||
|
||||
154
src/editor/ui.d
154
src/editor/ui.d
@ -66,6 +66,7 @@ Vec2 g_padding_default = Vec2(0.0);
|
||||
f32 g_text_scale_default = 1.0;
|
||||
Vec2 g_scroll_target_default = Vec2(0.0);
|
||||
Vec2 g_scroll_clamp_default = Vec2(0.0);
|
||||
Vec2 g_view_offset_default = Vec2(0.0);
|
||||
alias g_parent_default = g_UI_NIL;
|
||||
|
||||
const UI_COUNT = 5000;
|
||||
@ -115,9 +116,12 @@ enum UIFlags
|
||||
RightAlignText = 1<<14,
|
||||
CenterAlignText = 1<<15, // todo
|
||||
TextWrap = 1<<16,
|
||||
PortalView = 1<<17, // Stencil mask this area, no bounds checking children within (for views to drag and view elements)
|
||||
PortalViewX = 1<<17, // Stencil mask this area, no bounds checking children within (for views to drag and view elements)
|
||||
PortalViewY = 1<<18,
|
||||
|
||||
Clamp = UIFlags.ClampX | UIFlags.ClampY,
|
||||
PortalView = UIFlags.PortalViewX | UIFlags.PortalViewY,
|
||||
Scroll = UIFlags.ScrollX | UIFlags.ScrollY,
|
||||
}
|
||||
alias UIF = UIFlags;
|
||||
|
||||
@ -242,8 +246,8 @@ struct UICtx
|
||||
mixin UICtxParameter!(Vec4, "text_hl_col");
|
||||
mixin UICtxParameter!(Vec2[2], "scroll_clamp");
|
||||
mixin UICtxParameter!(Vec2, "scroll_target");
|
||||
mixin UICtxParameter!(Vec2, "fixed_pos");
|
||||
mixin UICtxParameter!(Vec2, "padding");
|
||||
mixin UICtxParameter!(Vec2, "view_offset");
|
||||
mixin UICtxParameter!(UIItem*, "parent");
|
||||
mixin UICtxParameter!(Axis2D, "layout_axis");
|
||||
mixin UICtxParameter!(f32, "corner_radius");
|
||||
@ -316,6 +320,8 @@ struct UIItem
|
||||
Vec2 scroll_offset;
|
||||
|
||||
mixin UIItemParameters!();
|
||||
|
||||
bool rendered;
|
||||
}
|
||||
|
||||
enum SizeType
|
||||
@ -342,6 +348,7 @@ struct UIBuffer
|
||||
Vertex[] vtx;
|
||||
u32[] idx;
|
||||
u32 count;
|
||||
u32 vtx_offset;
|
||||
}
|
||||
|
||||
struct GlyphBounds
|
||||
@ -493,7 +500,7 @@ InitUICtx(PlatformWindow* window)
|
||||
ctx.desc_set = AllocDescSet(&ctx.rd, ctx.desc_set_layout);
|
||||
ctx.pipeline_layout = CreatePipelineLayout(&ctx.rd, ctx.desc_set_layout, Mat4.sizeof);
|
||||
|
||||
Attribute[14] attributes = [
|
||||
Attribute[13] attributes = [
|
||||
{ binding: 0, location: 0, format: FMT.RGBA_F32, offset: Vertex.cols.offsetof + Vec4.sizeof * 0 },
|
||||
{ binding: 0, location: 1, format: FMT.RGBA_F32, offset: Vertex.cols.offsetof + Vec4.sizeof * 1 },
|
||||
{ binding: 0, location: 2, format: FMT.RGBA_F32, offset: Vertex.cols.offsetof + Vec4.sizeof * 2 },
|
||||
@ -506,8 +513,7 @@ InitUICtx(PlatformWindow* window)
|
||||
{ binding: 0, location: 9, format: FMT.R_F32, offset: Vertex.corner_radius.offsetof },
|
||||
{ binding: 0, location: 10, format: FMT.R_F32, offset: Vertex.edge_softness.offsetof },
|
||||
{ binding: 0, location: 11, format: FMT.R_F32, offset: Vertex.raised.offsetof },
|
||||
{ binding: 0, location: 12, format: FMT.R_F32, offset: Vertex.z_index.offsetof },
|
||||
{ binding: 0, location: 13, format: FMT.R_U32, offset: Vertex.texture.offsetof },
|
||||
{ binding: 0, location: 12, format: FMT.R_U32, offset: Vertex.texture.offsetof },
|
||||
];
|
||||
|
||||
GfxPipelineInfo ui_info = {
|
||||
@ -683,6 +689,7 @@ InitSingleLine:
|
||||
|
||||
item.last_frame = ctx.frame;
|
||||
item.padding += item.border_thickness;
|
||||
item.rendered = false;
|
||||
|
||||
return item;
|
||||
}
|
||||
@ -748,6 +755,22 @@ PushUIEvent(UICtx* ctx, UIInput input)
|
||||
DLLPush(&ctx.events, ev, null);
|
||||
}
|
||||
|
||||
void
|
||||
DrawUI(UICtx* ctx)
|
||||
{
|
||||
version(ENABLE_RENDERER)
|
||||
{
|
||||
UIBuffer* b = ctx.buffers.ptr + ctx.f_idx;
|
||||
if(b.vtx_offset != b.count)
|
||||
{
|
||||
u32 count = b.count - b.vtx_offset;
|
||||
BindBuffers(&ctx.rd, &b.m_idx, &b.m_vtx);
|
||||
DrawIndexed(&ctx.rd, 6, count, 0, 0, b.vtx_offset);
|
||||
b.vtx_offset += count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BeginUI(Inputs* inputs)
|
||||
{
|
||||
@ -843,6 +866,7 @@ BeginUI(Inputs* inputs)
|
||||
|
||||
memset(ctx.buffers[ctx.f_idx].vtx.ptr, 0, Vertex.sizeof * ctx.buffers[ctx.f_idx].count);
|
||||
ctx.buffers[ctx.f_idx].count = 0;
|
||||
ctx.buffers[ctx.f_idx].vtx_offset = 0;
|
||||
|
||||
// Root Item
|
||||
UISize[2] sizes = [UISize(ST.Pixels, ctx.res.x), UISize(ST.Pixels, ctx.res.y)];
|
||||
@ -989,6 +1013,30 @@ EndUI()
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(excess > 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))
|
||||
@ -1074,11 +1143,24 @@ EndUI()
|
||||
}
|
||||
|
||||
void
|
||||
RenderItems(UIItem* root)
|
||||
RenderItem(UICtx* ctx, UIItem* item)
|
||||
{
|
||||
UICtx* ctx = GetCtx();
|
||||
for(UIItem* item = root; !Nil(item); item = Recurse!(true)(item, g_UI_NIL))
|
||||
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
|
||||
@ -1125,6 +1207,8 @@ RenderItems(UIItem* root)
|
||||
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];
|
||||
@ -1136,6 +1220,38 @@ RenderItems(UIItem* root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
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);
|
||||
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user