diff --git a/assets/gui.frag.spv b/assets/gui.frag.spv index c23da8b..89ae57e 100644 Binary files a/assets/gui.frag.spv and b/assets/gui.frag.spv differ diff --git a/assets/gui.vert.spv b/assets/gui.vert.spv index 3fea618..f6bf6e3 100644 Binary files a/assets/gui.vert.spv and b/assets/gui.vert.spv differ diff --git a/assets/jetbrains-mono/JetBrainsMono-Bold.ttf b/assets/jetbrains-mono/JetBrainsMono-Bold.ttf new file mode 100644 index 0000000..8c93043 Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMono-Bold.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMono-BoldItalic.ttf b/assets/jetbrains-mono/JetBrainsMono-BoldItalic.ttf new file mode 100644 index 0000000..1ddf216 Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMono-BoldItalic.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMono-ExtraBold.ttf b/assets/jetbrains-mono/JetBrainsMono-ExtraBold.ttf new file mode 100644 index 0000000..435d7a7 Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMono-ExtraBold.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMono-ExtraBoldItalic.ttf b/assets/jetbrains-mono/JetBrainsMono-ExtraBoldItalic.ttf new file mode 100644 index 0000000..79e616e Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMono-ExtraBoldItalic.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMono-ExtraLight.ttf b/assets/jetbrains-mono/JetBrainsMono-ExtraLight.ttf new file mode 100644 index 0000000..c131cbf Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMono-ExtraLight.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMono-ExtraLightItalic.ttf b/assets/jetbrains-mono/JetBrainsMono-ExtraLightItalic.ttf new file mode 100644 index 0000000..a768985 Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMono-ExtraLightItalic.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMono-Italic.ttf b/assets/jetbrains-mono/JetBrainsMono-Italic.ttf new file mode 100644 index 0000000..ccc9d6a Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMono-Italic.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMono-Light.ttf b/assets/jetbrains-mono/JetBrainsMono-Light.ttf new file mode 100644 index 0000000..15f15a2 Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMono-Light.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMono-LightItalic.ttf b/assets/jetbrains-mono/JetBrainsMono-LightItalic.ttf new file mode 100644 index 0000000..506208f Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMono-LightItalic.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMono-Medium.ttf b/assets/jetbrains-mono/JetBrainsMono-Medium.ttf new file mode 100644 index 0000000..9767115 Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMono-Medium.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMono-MediumItalic.ttf b/assets/jetbrains-mono/JetBrainsMono-MediumItalic.ttf new file mode 100644 index 0000000..415a9e3 Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMono-MediumItalic.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMono-Regular.ttf b/assets/jetbrains-mono/JetBrainsMono-Regular.ttf new file mode 100644 index 0000000..dff66cc Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMono-Regular.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMono-SemiBold.ttf b/assets/jetbrains-mono/JetBrainsMono-SemiBold.ttf new file mode 100644 index 0000000..a70e69b Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMono-SemiBold.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMono-SemiBoldItalic.ttf b/assets/jetbrains-mono/JetBrainsMono-SemiBoldItalic.ttf new file mode 100644 index 0000000..968602e Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMono-SemiBoldItalic.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMono-Thin.ttf b/assets/jetbrains-mono/JetBrainsMono-Thin.ttf new file mode 100644 index 0000000..7dbe2ac Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMono-Thin.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMono-ThinItalic.ttf b/assets/jetbrains-mono/JetBrainsMono-ThinItalic.ttf new file mode 100644 index 0000000..c6ad6c2 Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMono-ThinItalic.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMonoNL-Bold.ttf b/assets/jetbrains-mono/JetBrainsMonoNL-Bold.ttf new file mode 100644 index 0000000..f78f84f Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMonoNL-Bold.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMonoNL-BoldItalic.ttf b/assets/jetbrains-mono/JetBrainsMonoNL-BoldItalic.ttf new file mode 100644 index 0000000..9fb8c83 Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMonoNL-BoldItalic.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMonoNL-ExtraBold.ttf b/assets/jetbrains-mono/JetBrainsMonoNL-ExtraBold.ttf new file mode 100644 index 0000000..fe5be6a Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMonoNL-ExtraBold.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMonoNL-ExtraBoldItalic.ttf b/assets/jetbrains-mono/JetBrainsMonoNL-ExtraBoldItalic.ttf new file mode 100644 index 0000000..59fc980 Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMonoNL-ExtraBoldItalic.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMonoNL-ExtraLight.ttf b/assets/jetbrains-mono/JetBrainsMonoNL-ExtraLight.ttf new file mode 100644 index 0000000..6da7b75 Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMonoNL-ExtraLight.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMonoNL-ExtraLightItalic.ttf b/assets/jetbrains-mono/JetBrainsMonoNL-ExtraLightItalic.ttf new file mode 100644 index 0000000..5733efc Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMonoNL-ExtraLightItalic.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMonoNL-Italic.ttf b/assets/jetbrains-mono/JetBrainsMonoNL-Italic.ttf new file mode 100644 index 0000000..4e9c380 Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMonoNL-Italic.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMonoNL-Light.ttf b/assets/jetbrains-mono/JetBrainsMonoNL-Light.ttf new file mode 100644 index 0000000..0b79b0c Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMonoNL-Light.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMonoNL-LightItalic.ttf b/assets/jetbrains-mono/JetBrainsMonoNL-LightItalic.ttf new file mode 100644 index 0000000..b5e0842 Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMonoNL-LightItalic.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMonoNL-Medium.ttf b/assets/jetbrains-mono/JetBrainsMonoNL-Medium.ttf new file mode 100644 index 0000000..1454372 Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMonoNL-Medium.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMonoNL-MediumItalic.ttf b/assets/jetbrains-mono/JetBrainsMonoNL-MediumItalic.ttf new file mode 100644 index 0000000..8d63c6c Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMonoNL-MediumItalic.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMonoNL-Regular.ttf b/assets/jetbrains-mono/JetBrainsMonoNL-Regular.ttf new file mode 100644 index 0000000..70d2ec9 Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMonoNL-Regular.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMonoNL-SemiBold.ttf b/assets/jetbrains-mono/JetBrainsMonoNL-SemiBold.ttf new file mode 100644 index 0000000..ce60a88 Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMonoNL-SemiBold.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMonoNL-SemiBoldItalic.ttf b/assets/jetbrains-mono/JetBrainsMonoNL-SemiBoldItalic.ttf new file mode 100644 index 0000000..3b3f8f6 Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMonoNL-SemiBoldItalic.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMonoNL-Thin.ttf b/assets/jetbrains-mono/JetBrainsMonoNL-Thin.ttf new file mode 100644 index 0000000..bea837e Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMonoNL-Thin.ttf differ diff --git a/assets/jetbrains-mono/JetBrainsMonoNL-ThinItalic.ttf b/assets/jetbrains-mono/JetBrainsMonoNL-ThinItalic.ttf new file mode 100644 index 0000000..f0bfed7 Binary files /dev/null and b/assets/jetbrains-mono/JetBrainsMonoNL-ThinItalic.ttf differ diff --git a/src/VulkanRenderer b/src/VulkanRenderer index 11cf96b..c2b7544 160000 --- a/src/VulkanRenderer +++ b/src/VulkanRenderer @@ -1 +1 @@ -Subproject commit 11cf96b799c6ccee3c4f569e89c263d11c4d5ff8 +Subproject commit c2b7544979b16e1f27f419475b866a2903bd9c0a diff --git a/src/dlib b/src/dlib index bda9abf..c637de1 160000 --- a/src/dlib +++ b/src/dlib @@ -1 +1 @@ -Subproject commit bda9abf8b9c74844cb30edb32e81543cbd5ae89d +Subproject commit c637de10ffd949a07e51d6a792a6c4f49ac33ac5 diff --git a/src/editor/buffer.d b/src/editor/buffer.d index 6c4ee21..bc0e93d 100644 --- a/src/editor/buffer.d +++ b/src/editor/buffer.d @@ -1,4 +1,5 @@ import dlib; +import dlib.alloc : Reset; import core.stdc.stdio : EOF; import parsing; import parsing : SetBuffers; @@ -476,6 +477,12 @@ SliceLineBuffer(FlatBuffer* fb, Line* ls) return lbuf; } +pragma(inline) void +ResetBuffer(FlatBuffer* fb) +{ + Reset(&fb.linebufs.arena); +} + void MoveToEOL(FlatBuffer* fb) { diff --git a/src/editor/editor.d b/src/editor/editor.d index 5675a66..ae248ff 100644 --- a/src/editor/editor.d +++ b/src/editor/editor.d @@ -61,10 +61,7 @@ struct Editor I64Vec2 cursor_pos; Vec2 select_start; Vec2 select_end; - i64 line_offset; - - f32 text_size; } struct ChangeStacks @@ -155,48 +152,6 @@ Cycle(Inputs* inputs) { CommandPalette(&g_ed_ctx.cmd); } - /* - UIPanel* root = ctx.base_panel; - - root.size.x = g_ui_ctx.res.x; - root.size.y = g_ui_ctx.res.y; - root.rect.p0 = 0.0; - root.rect.p1 = 0.0; - - static foreach(axis; A2D.min .. A2D.max) - { - for(UIPanel* p = root; !Nil(p); p = Recurse(p, g_UI_NIL_PANEL)) - { - f32 pos = p.rect.p0.v[axis]; - for(UIPanel* c = p.first; !Nil(c); c = c.next) - { - c.size.v[axis] = p.axis == axis ? c.pct * p.size.v[axis] : p.size.v[axis]; - c.rect.p0.v[axis] = pos; - c.rect.p1.v[axis] = pos + c.size.v[axis]; - - if(axis == p.axis) - { - pos += c.size.v[axis]; - } - } - } - } - - for(auto p = ctx.base_panel; !Nil(p); p = Recurse(p, g_UI_NIL_PANEL)) - { - Panel(p); - } - - if(ctx.state == ES.CmdOpen) - { - if(ctx.cmd.commands.length == 0 && ctx.cmd.icount == 0) - { - GetCommands(&ctx.cmd); - } - - CommandPalette(&ctx.cmd); - } - */ EndUI(); } @@ -266,6 +221,7 @@ CreatePanel(EditorCtx* ctx, Editor* ed = null) p.layout_axis = A2D.Y; p.ed = ed; p.id = ctx.panel_id++; + p.text_size = 18; p.parent = p.first = p.last = p.next = p.prev = g_NIL_PANEL; return p; diff --git a/src/editor/ui.d b/src/editor/ui.d index 2ea532e..b1f308b 100644 --- a/src/editor/ui.d +++ b/src/editor/ui.d @@ -35,20 +35,22 @@ enum Vec4 BORDER_HL_COL = Vec4(0.035, 0.549, 0.824, 1.0); enum Vec4 TEXT_COL = Vec4(1.0); enum Vec4 TEXT_HL_COL = Vec4(0.0, 0.0, 0.0, 1.0); -const u64 VERTEX_MAX_COUNT = 10000; -const Vec2 CLICK_BUFFER = Vec2(3.0, 3.0); +const u64 VERTEX_MAX_COUNT = 10000; +const Vec2 CLICK_BUFFER = Vec2(3.0, 3.0); +const u32 FONT_SIZES = 24; +const u32 ATLAS_DIMENSION = 512; // TODO: add setting -const f32 TEXT_SIZE = 16.0; const f32 SCROLL_SPEED = 48.0; const f32 LINE_COUNT_PADDING = 4.0; __gshared UICtx g_ui_ctx; //const u8[] FONT_BYTES = import("pc-9800.ttf"); -const u8[] FONT_BYTES = import("NuberNextCondensed-DemiBold.otf"); -const u8[] VERTEX_BYTES = import("gui.vert.spv"); -const u8[] FRAGMENT_BYTES = import("gui.frag.spv"); +//const u8[] FONT_BYTES = import("NuberNextCondensed-DemiBold.otf"); +u8[] FONT_BYTES = cast(u8[])import("jetbrains-mono/JetBrainsMono-Regular.ttf"); +u8[] VERTEX_BYTES = cast(u8[])import("gui.vert.spv"); +u8[] FRAGMENT_BYTES = cast(u8[])import("gui.frag.spv"); Vec4 g_corner_radius_default = 0.0; f32 g_edge_softness_default = 0.8; @@ -62,7 +64,7 @@ Vec4 g_text_hl_col_default = TEXT_HL_COL; UISize[2] g_size_info_default = [UISize(ST.Percentage, 1.0), UISize(ST.Percentage, 1.0)]; Axis2D g_layout_axis_default = A2D.X; Vec2 g_padding_default = Vec2(0.0); -f32 g_text_scale_default = 1.0; +u32 g_text_size_default = 18; Vec2 g_scroll_target_default = Vec2(0.0); Vec2 g_scroll_clamp_default = Vec2(0.0); Vec2 g_view_offset_default = Vec2(0.0); @@ -131,6 +133,7 @@ enum UIFlags alias UIF = UIFlags; const UIFlags AUTO_FLAGS = UIF.ResizeAdjacent; +const UIFlags DRAW_FLAGS = UIF.DrawBackground|UIF.DrawBorder|UIF.DrawText|UIF.PortalView; enum UISignal { @@ -233,7 +236,8 @@ struct UICtx PlatformWindow* window; Renderer rd; - Descriptor font_atlas; + Descriptor[FONT_SIZES] font_descs; + Descriptor default_tex; Descriptor sampler; Pipeline pipeline; DescSetLayout desc_set_layout; @@ -242,16 +246,13 @@ struct UICtx Mat4 projection; Vec2 res; - u8[] font_data; FontFace font; - FontAtlasBuf atlas_buf; - f32 char_width; - f32 char_height; + FontGlyphs[FONT_SIZES] glyph_sets; + u32 glyph_sets_used; UIBuffer[FRAME_OVERLAP] buffers; u32 tab_width; - f32 text_size; Vec4[TS.max][UISH.max] syntax_colors; UIItem* window_root; @@ -278,10 +279,18 @@ struct UICtx mixin UICtxParameter!(Vec4, "corner_radius"); mixin UICtxParameter!(f32, "border_thickness"); mixin UICtxParameter!(f32, "edge_softness"); - mixin UICtxParameter!(f32, "text_scale"); + mixin UICtxParameter!(u32, "text_size"); mixin UICtxParameter!(UISyntaxHighlight, "syntax_highlight"); debug bool dbg; + debug u64 item_count; +} + +struct FontGlyphs +{ + u32 size; + u32 index; + FontAtlasBuf abuf; } struct Stack(T) @@ -337,6 +346,7 @@ struct UIItem UIItem* next, prev, first, last; // parent in mixin UIItem* transient_next; + UIItem* last_relative_item; Rect rect; Vec2 size; @@ -412,6 +422,7 @@ struct Vertex f32 edge_softness; f32 raised; u32 texture; + u32 atlas_index; } union Rect @@ -462,26 +473,23 @@ InitUICtx(PlatformWindow* window) UIBuffer[FRAME_OVERLAP] buffers; - UICtx ctx = { - items: CreateHashTable!(UIHash, UIItem*)(12), - free_items: Alloc!(UIItem)(&arena), - arena: arena, - temp_arena: CreateArena(MB(1)), - drag_item: g_UI_NIL, - transient_items: g_UI_NIL, - font: OpenFont(cast(u8[])FONT_BYTES), - font_data: cast(u8[])FONT_BYTES, - text_size: 16.0, - tab_width: 2, - syntax_colors: [DEFAULT_COLORS, SYNTAX_COLORS], - }; + UICtx* ctx = &g_ui_ctx; + + ctx.items = CreateHashTable!(UIHash, UIItem*)(12); + ctx.free_items = Alloc!(UIItem)(&arena); + ctx.arena = arena; + ctx.temp_arena = CreateArena(MB(1)); + ctx.drag_item = g_UI_NIL; + ctx.transient_items = g_UI_NIL; + ctx.font = OpenFont(cast(u8[])FONT_BYTES); + ctx.tab_width = 2; + ctx.syntax_colors = [DEFAULT_COLORS, SYNTAX_COLORS]; + + assert(ctx.font); UIItem* fi = ctx.free_items; fi.transient_next = fi.first = fi.last = fi.next = fi.prev = fi.parent = g_UI_NIL; - ctx.atlas_buf = CreateAtlas(&arena, ctx.font, 16.0, 256); - ctx.char_height = cast(f32)((ctx.font.size.metrics.ascender - ctx.font.size.metrics.descender) >> 6); - version(ENABLE_RENDERER) { ctx.rd = InitRenderer(handles, MB(16), MB(8)); @@ -496,28 +504,29 @@ InitUICtx(PlatformWindow* window) } DescLayoutBinding[2] layout_bindings = [ - { binding: 0, descriptorType: DT.Image, descriptorCount: 1, stageFlags: SS.All }, - { binding: 1, descriptorType: DT.Sampler, descriptorCount: 1, stageFlags: SS.All }, + { binding: 0, descriptorType: DT.Image, descriptorCount: FONT_SIZES, stageFlags: SS.All }, + { binding: 1, descriptorType: DT.Sampler, descriptorCount: 1, stageFlags: SS.All }, ]; ctx.desc_set_layout = CreateDescSetLayout(&ctx.rd, layout_bindings); ctx.desc_set = AllocDescSet(&ctx.rd, ctx.desc_set_layout); ctx.pipeline_layout = CreatePipelineLayout(&ctx.rd, ctx.desc_set_layout, Mat4.sizeof); - Attribute[13] attributes = [ - { binding: 0, location: 0, format: FMT.RGBA_F32, offset: Vertex.cols.offsetof }, + Attribute[] attributes = [ + { binding: 0, location: 0, format: FMT.RGBA_F32, offset: Vertex.cols.offsetof }, { binding: 0, location: 1, format: FMT.R_F32, offset: Vertex.corner_radius.offsetof + f32.sizeof*0 }, { binding: 0, location: 2, format: FMT.R_F32, offset: Vertex.corner_radius.offsetof + f32.sizeof*1 }, { binding: 0, location: 3, format: FMT.R_F32, offset: Vertex.corner_radius.offsetof + f32.sizeof*2 }, { binding: 0, location: 4, format: FMT.R_F32, offset: Vertex.corner_radius.offsetof + f32.sizeof*3 }, - { binding: 0, location: 5, format: FMT.RG_F32, offset: Vertex.dst_start.offsetof }, - { binding: 0, location: 6, format: FMT.RG_F32, offset: Vertex.dst_end.offsetof }, - { binding: 0, location: 7, format: FMT.RG_F32, offset: Vertex.src_start.offsetof }, - { binding: 0, location: 8, format: FMT.RG_F32, offset: Vertex.src_end.offsetof }, - { binding: 0, location: 9, format: FMT.R_F32, offset: Vertex.border_thickness.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_U32, offset: Vertex.texture.offsetof }, + { binding: 0, location: 5, format: FMT.RG_F32, offset: Vertex.dst_start.offsetof }, + { binding: 0, location: 6, format: FMT.RG_F32, offset: Vertex.dst_end.offsetof }, + { binding: 0, location: 7, format: FMT.RG_F32, offset: Vertex.src_start.offsetof }, + { binding: 0, location: 8, format: FMT.RG_F32, offset: Vertex.src_end.offsetof }, + { binding: 0, location: 9, format: FMT.R_F32, offset: Vertex.border_thickness.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_U32, offset: Vertex.texture.offsetof }, + { binding: 0, location: 13, format: FMT.R_U32, offset: Vertex.atlas_index.offsetof }, ]; GfxPipelineInfo ui_info = { @@ -535,16 +544,69 @@ InitUICtx(PlatformWindow* window) alpha_op: BO.Add, }; + for(u32 i = 0; i < ctx.font_descs.length; i += 1) + { + CreateImageViewTex(&ctx.rd, &ctx.font_descs[i], ATLAS_DIMENSION, ATLAS_DIMENSION, DT.Image, 0, i); + ctx.glyph_sets[i].index = i; + } + + FontAtlasBuf* abuf = GetFontAtlas(g_text_size_default); + CreateGraphicsPipeline(&ctx.rd, &ctx.pipeline, &ui_info); - CreateImageView(&ctx.rd, &ctx.font_atlas, ctx.atlas_buf.atlas.width, ctx.atlas_buf.atlas.height, 4, ctx.atlas_buf.data, DT.Image, 0); ctx.sampler = CreateSampler(&ctx.rd, MipmapMode.Nearest, 1); - Write(&ctx.rd, ctx.desc_set, [ctx.font_atlas, ctx.sampler]); + + u8[512*512*4] white_tex = 255; + for(u32 i = 1; i < ctx.font_descs.length; i += 1) + { + Transfer(&ctx.rd, &ctx.font_descs[i].view, white_tex, ATLAS_DIMENSION, ATLAS_DIMENSION); + } + + Write(&ctx.rd, ctx.desc_set, ctx.font_descs); + Write(&ctx.rd, ctx.desc_set, &ctx.sampler); SetClearColors(&ctx.rd, [0.0, 0.0, 0.0, 1.0], [0.0, 0.0, 0.0, 0.0]); } - InitStacks(&ctx); + InitStacks(ctx); +} - g_ui_ctx = ctx; +FontAtlasBuf* +GetFontAtlas(u32 size) +{ + return &GetFontGlyphs(size).abuf; +} + +FontGlyphs* +GetFontGlyphs(u32 size) +{ + UICtx* ctx = GetCtx(); + + FontGlyphs* fg = null; + for(u64 i = 0; i < ctx.glyph_sets_used; i += 1) + { + if(size == ctx.glyph_sets[i].size) + { + fg = &ctx.glyph_sets[i]; + break; + } + } + + if(!fg) + { + u32 i = ctx.glyph_sets_used; + fg = &ctx.glyph_sets[i]; + + assert(ctx.font); + + fg.abuf = CreateAtlas(&ctx.arena, ctx.font, cast(f32)size, ATLAS_DIMENSION); + fg.size = size; + + Transfer(&ctx.rd, &ctx.font_descs[i].view, fg.abuf.data, ATLAS_DIMENSION, ATLAS_DIMENSION); + Write(&ctx.rd, ctx.desc_set, &ctx.font_descs[i]); + + ctx.glyph_sets_used += 1; + } + + return fg; } void @@ -626,75 +688,41 @@ MakeItem(T)(T k, UIFlags flags = UIF.None) if(is(T: UIKey) || StringType!T) } } - item.max_text_width = 0.0; + FontAtlasBuf* abuf = GetFontAtlas(item.text_size); string str = item.display_string.length ? item.display_string : item.key.text; - + item.max_text_width = cast(f32)(str.length)*abuf.atlas.max_advance; if(item.flags & UIF.TextWrap) { - f32 width = item.size_info[A2D.X].type == ST.TextSize ? item.parent.size.x : item.size.x; - f32 text_width = CalcTextWidth(str); - if(text_width < width || width == 0.0) goto InitSingleLine; + f32 width = item.size_info[A2D.X].type == ST.TextSize ? item.parent.size.x : item.size.x; + u32 ch_per_line = cast(u32)floor(width/abuf.atlas.max_advance); + u64 lines = (str.length/ch_per_line) + (str.length%ch_per_line ? 1 : 0); - u64 lines = cast(u64)(ceil(text_width/width)); + u32 max_chars = str.length > ch_per_line ? ch_per_line : cast(u32)str.length; + item.max_text_width = cast(f32)(max_chars)*abuf.atlas.max_advance; item.text_lines = ScratchAlloc!(string)(lines); - assert(!item.syntax_tokens.length || item.syntax_tokens.length == str.length); + u64 start; + for(u64 i = 0; i < lines; i += 1) + { + u64 end = str.length-start <= ch_per_line ? str.length : start+ch_per_line; + item.text_lines[i] = str[start .. end]; + } if(item.syntax_tokens.length) { item.token_lines = ScratchAlloc!(u8[])(lines); - } - - f32 w = 0.0; - u64 line = 0; - u64 ch_start = 0; - Glyph[] glyphs = ctx.atlas_buf.atlas.glyphs; - - for(u64 i = 0; i < str.length; i += 1) - { - Glyph* g = str[i] < glyphs.length ? glyphs.ptr+str[i] : glyphs.ptr+0; - - f32 glyph_w = GlyphWidth(g); - if(glyph_w+w > width) + for(u64 i = 0; i < lines; i += 1) { - item.text_lines[line] = str[ch_start .. i]; - if(item.syntax_tokens.length) - { - item.token_lines[line] = item.syntax_tokens[ch_start .. i]; - } - - line += 1; - ch_start = i; - - item.max_text_width = item.max_text_width < w ? w : item.max_text_width; - - if(line == lines-1) - { - item.text_lines[line] = str[ch_start .. $]; - if(item.syntax_tokens.length) - { - item.token_lines[line] = item.syntax_tokens[ch_start .. $]; - } - - w = CalcTextWidth(item.text_lines[line]); - item.max_text_width = item.max_text_width < w ? w : item.max_text_width; - - break; - } - - w = 0.0; + u64 end = str.length-start <= ch_per_line ? str.length : start+ch_per_line; + item.token_lines[i] = item.syntax_tokens[start .. end]; } - - w += glyph_w; } } else { -InitSingleLine: - item.text_lines = ScratchAlloc!(string)(1); - item.text_lines[0] = str; - item.max_text_width = CalcTextWidth(item.text_lines[0]); + item.text_lines = ScratchAlloc!(string)(1); + item.text_lines[0] = str; if(item.syntax_tokens.length) { @@ -726,9 +754,9 @@ InitSingleLine: } } - item.last_frame = ctx.frame; - item.padding += item.border_thickness; - item.rendered = false; + item.last_frame = ctx.frame; + item.padding += item.border_thickness; + item.rendered = false; return item; } @@ -816,6 +844,8 @@ BeginUI(Inputs* inputs) UICtx* ctx = GetCtx(); Arena* a = &ctx.temp_arena; + debug ctx.item_count = 0; + Reset(a); // Convert Inputs @@ -885,19 +915,20 @@ BeginUI(Inputs* inputs) } } - for(UIItem* item = ctx.transient_items; !Nil(item); item = item.transient_next) + for(UIItem* item = ctx.transient_items; !Nil(item);) { + UIItem* next = item.transient_next; memset(item, 0, UIItem.sizeof); DLLPush(ctx.free_items, item, g_UI_NIL); + item = next; } - ctx.frame += 1; - ctx.transient_items = g_UI_NIL; // Ctx state - ctx.f_idx = ctx.frame%FRAME_OVERLAP; - ctx.inputs = inputs; - ctx.char_width = GlyphWidth(&ctx.atlas_buf.atlas.glyphs[' ']); + ctx.transient_items = g_UI_NIL; + ctx.frame += 1; + ctx.f_idx = ctx.frame%FRAME_OVERLAP; + ctx.inputs = inputs; ResetStacks(ctx); @@ -992,7 +1023,7 @@ EndUI() } else { - item.size.v[axis] = item.padding.y*2.0 + TEXT_SIZE*item.text_lines.length; + item.size.v[axis] = item.padding.y*2.0 + GetFontAtlas(item.text_size).atlas.line_height*item.text_lines.length; } } } @@ -1074,10 +1105,7 @@ EndUI() excess -= reduced; c.size.v[axis] -= reduced; - if(excess <= 0.0009) - { - break; - } + if(excess <= 0.0009) break; } if(excess > 0.0009) @@ -1093,10 +1121,7 @@ EndUI() excess -= reduced; c.size.v[axis] -= reduced; - if(excess < 0.0009) - { - break; - } + if(excess < 0.0009) break; } } } @@ -1118,72 +1143,42 @@ EndUI() // Calculate final sizes { f32 pos = 0.0; - for(UIItem* item = ctx.root; !Nil(item);) + for(UIItem* item = ctx.root; !Nil(item); item = Recurse!(true)(item, g_UI_NIL)) { - bool fixed = cast(bool)(item.flags & UIF.FixedPosition); + item.last_relative_item = g_UI_NIL; - bool first_child_fixed = item.parent.flags & UIF.FixedPosition && item == item.parent.first; - bool on_layout_axis = item.parent.layout_axis == axis; - if(!on_layout_axis || first_child_fixed) - { - pos = item.parent.rect.p0.v[axis] + item.parent.padding.v[axis]; - } - - if(item.view_offset.x != 0.0 || item.view_offset.y != 0.0) - { - for(UIItem* c = item.first; !Nil(c); c = c.next) - { - if(!(c.flags & UIF.FixedPosition)) - { - c.pos_offset = item.view_offset; - break; - } - } - } - - f32 next_pos = 0.0; + bool fixed = cast(bool)(item.flags & UIF.FixedPosition); + UIItem* parent = item.parent; if(fixed) { - item.rect.p0.v[axis] = item.fixed_pos.v[axis] + item.parent.rect.p0.v[axis]; - item.rect.p1.v[axis] = item.rect.p0.v[axis] + item.size.v[axis]; - - next_pos = pos; + item.rect.p0.v[axis] = parent.rect.p0.v[axis] + item.fixed_pos.v[axis] + item.padding.v[axis] + parent.view_offset.v[axis]; + item.rect.p1.v[axis] = item.rect.p0.v[axis] + item.size.v[axis] - item.padding.v[axis]; + } + else if(Nil(item.parent.last_relative_item)) + { + item.rect.p0.v[axis] = parent.rect.p0.v[axis] + item.padding.v[axis] + parent.view_offset.v[axis]; + item.rect.p1.v[axis] = item.rect.p0.v[axis] + item.size.v[axis] - item.padding.v[axis]; + } + else if(axis != item.parent.layout_axis) + { + item.rect.p0.v[axis] = parent.rect.p0.v[axis] + parent.view_offset.v[axis] + item.padding.v[axis]; + item.rect.p1.v[axis] = parent.rect.p0.v[axis] + item.size.v[axis] - item.padding.v[axis]; } else { - item.rect.p0.v[axis] = pos + item.pos_offset.v[axis]; - item.rect.p1.v[axis] = item.rect.p0.v[axis] + item.size.v[axis]; + UIItem* prev = parent.last_relative_item; - next_pos = item.parent.layout_axis == axis ? item.rect.p1.v[axis] : item.rect.p0.v[axis]; + item.rect.p0.v[axis] = prev.rect.p1.v[axis] + prev.padding.v[axis] + item.padding.v[axis]; + item.rect.p1.v[axis] = item.rect.p0.v[axis] + item.size.v[axis] - item.padding.v[axis]; + } + + if(!fixed && !Nil(parent)) + { + parent.last_relative_item = item; } assert(!isNaN(item.rect.p0.v[axis])); assert(!isNaN(item.rect.p1.v[axis])); - - if(!Nil(item.first)) - { - item = item.first; - } - else if(!Nil(item.next)) - { - item = item.next; - pos = next_pos; - } - else for(UIItem* p = item.parent;; p = p.parent) - { - if(!Nil(p.next)) - { - item = p.next; - pos = item.parent.layout_axis == axis ? item.prev.rect.p1.v[axis] : item.parent.rect.p0.v[axis]; - break; - } - - if(Nil(p)) - { - item = g_UI_NIL; - break; - } - } } } } @@ -1236,7 +1231,11 @@ FocusItem(T)(T focus) if(is(T == UIKey) || StringType!T || is(T == UIItem*)) void RenderItem(UICtx* ctx, UIItem* item) { - if(item.rendered) return; + if(item.rendered) return; + if(!(item.flags & DRAW_FLAGS)) return; + + Vec2 p0 = item.rect.p0 - item.padding; + Vec2 p1 = item.rect.p1 + item.padding; // Doesn't really support nesting scissors, will maybe change this later. bool scissor_x = cast(bool)(item.flags & UIF.PortalViewX); @@ -1245,18 +1244,18 @@ RenderItem(UICtx* ctx, UIItem* item) { DrawUI(ctx); - u32 x = cast(u32)(scissor_x ? floor(item.rect.p0.x) : 0); - u32 y = cast(u32)(scissor_y ? floor(item.rect.p0.y) : 0); - 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); + u32 x = cast(u32)(scissor_x ? floor(p0.x) : 0); + u32 y = cast(u32)(scissor_y ? floor(p0.y) : 0); + u32 w = cast(u32)(scissor_x ? floor(p1.x) - x : ctx.res.x); + u32 h = cast(u32)(scissor_y ? floor(p1.y) - y : ctx.res.y); SetScissor(&ctx.rd, x, y, w, h); } if(item.flags & UIF.DrawBackground) { Vertex* v = GetVertex(ctx); - v.dst_start = item.rect.p0 + item.border_thickness; - v.dst_end = item.rect.p1 - item.border_thickness; + v.dst_start = p0 + item.border_thickness; + v.dst_end = p1 - item.border_thickness; v.cols = item.bg_col; v.corner_radius = item.flags & UIF.DrawBorder ? item.corner_radius*0.5 : item.corner_radius; v.bounds = ItemBounds(item.parent); @@ -1267,8 +1266,8 @@ RenderItem(UICtx* ctx, UIItem* item) if(item.flags & UIF.DrawBorder) { Vertex* v = GetVertex(ctx); - v.dst_start = item.rect.p0; - v.dst_end = item.rect.p1; + v.dst_start = p0; + v.dst_end = p1; v.cols = item.border_col; v.corner_radius = item.corner_radius; v.border_thickness = clamp(item.border_thickness, 1.0, f32.max); @@ -1286,27 +1285,25 @@ RenderItem(UICtx* ctx, UIItem* item) } else { - // The math around all this is fucked - FontAtlas* atl = &ctx.atlas_buf.atlas; - f32 y_pos = item.rect.p0.y + item.padding.y; + FontGlyphs* fg = GetFontGlyphs(item.text_size); + f32 y_pos = p0.y + fg.abuf.atlas.line_height; Vec4[] syntax_cols = ctx.syntax_colors[item.syntax_highlight]; foreach(i; 0 .. item.text_lines.length) { string str = item.text_lines[i]; u8[] tks = item.token_lines.length ? item.token_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; + f32 x_pos = item.flags & UIF.RightAlignText ? p1.x - item.padding.x - CalcTextWidth(str, &fg.abuf) : p0.x + item.padding.x; - x_pos = clamp(x_pos, item.rect.p0.x, item.rect.p1.x); + x_pos = clamp(x_pos, p0.x, p1.x); if(tks.length) { 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, syntax_cols[tks[j]]); + Glyph* g = ch < fg.abuf.atlas.glyphs.length ? fg.abuf.atlas.glyphs.ptr + ch : null; + DrawGlyph(item, g, fg.index, &x_pos, y_pos, syntax_cols[tks[j]]); } } else @@ -1314,12 +1311,12 @@ RenderItem(UICtx* ctx, UIItem* item) 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, item.text_col); + Glyph* g = ch < fg.abuf.atlas.glyphs.length ? fg.abuf.atlas.glyphs.ptr + ch : null; + DrawGlyph(item, g, fg.index, &x_pos, y_pos, item.text_col); } } - y_pos += TEXT_SIZE; + y_pos += fg.abuf.atlas.line_height; } } } @@ -1376,6 +1373,17 @@ StackIDs(string stack, string ctx = "ctx") }; } +void +PushSizeInfo(SizeType type0, f32 value0, f32 strictness0, SizeType type1, f32 value1, f32 strictness1, bool auto_pop = false) +{ + UISize[2] size_info = [ + UISize(type0, value0, strictness0), + UISize(type1, value1, strictness1), + ]; + + Push!("size_info")(size_info, auto_pop); +} + void PushSizeInfoVec(int i)(SizeType type, f32 value, f32 strictness = 1.0, bool auto_pop = false) { @@ -1463,24 +1471,52 @@ PushScrollTargetY(f32 target, bool auto_pop = false) PushScrollTarget(Vec2(0.0, target), auto_pop); } +static string +PushScope(string stack, string value)() +{ + import std.conv; + return i"Push!(\"$(stack)\")($(value)); scope(exit) Pop!(\"$(stack)\")();".text; +} + +static string +PushOnce(UIPushInfo[] info)() +{ + import std.conv; + + string result = ""; + static foreach(i; info) + { + result ~= i"Push!(\"$(i.s)\")($(i.v), true); scope(exit) Pop!(\"$(i.s)\")();".text; + } + + return result; +} + +struct UIPushInfo +{ + string s; // stack + string v; // value +} + void Push(string stack_str, T)(T value, bool auto_pop = false) { import std.string : replace; enum ids = StackIDs!(stack_str, "g_ui_ctx"); + alias ST = typeof(mixin(ids.stack ~ ".top.value")); auto stack = &mixin(ids.stack); auto top = mixin(ids.stack_top_node); - Stack!(T)* node = stack.free; + Stack!(ST)* node = stack.free; if(node) { stack.free = node.next; } else { - node = Alloc!(Stack!(T))(&g_ui_ctx.temp_arena); + node = Alloc!(Stack!(ST))(&g_ui_ctx.temp_arena); } node.next = stack.top; @@ -1762,11 +1798,10 @@ NewItem(UICtx* ctx) { UIItem* item = g_UI_NIL; - if(!Nil(ctx.free_items.first)) - { - item = DLLPop(ctx.free_items, g_UI_NIL); - } - else + debug ctx.item_count += 1; + + item = DLLPop(ctx.free_items, g_UI_NIL); + if(Nil(item)) { item = Alloc!(UIItem)(&ctx.arena); } @@ -1807,6 +1842,7 @@ Get(T)(T k) if(is(T: UIKey) || StringType!T) Result!(UIItem*) res = ctx.items[key.hash]; if(res.ok) { + debug ctx.item_count += 1; item = res.value; } else @@ -1823,7 +1859,7 @@ Get(T)(T k) if(is(T: UIKey) || StringType!T) } f32 -CalcTextWidth(T)(T text) if(is(T == string) || StringType!T) +CalcTextWidth(bool fast = true, T, U)(T text, U param) if((is(T == string) || StringType!T) && (is(U: u32) || is(U == FontAtlasBuf*) )) { static if(is(T == string)) { @@ -1834,102 +1870,127 @@ CalcTextWidth(T)(T text) if(is(T == string) || StringType!T) string str = ConvToStr(text); } - u32 tab_width = g_ui_ctx.tab_width; - Glyph* space = g_ui_ctx.atlas_buf.atlas.glyphs.ptr + ' '; - - f32 width = 0.0; - for(u64 i = 0; i < str.length; i += 1) + static if(is(U: u32)) { - width += GlyphWidth(g_ui_ctx.atlas_buf.atlas.glyphs.ptr + str.ptr[i]); + FontAtlasBuf* abuf = GetFontAtlas(param); + } + else + { + FontAtlasBuf* abuf = param; + } + + u32 tab_width = g_ui_ctx.tab_width; + + static if(fast) + { + f32 width = str.length * abuf.atlas.max_advance; + assert(abuf.atlas.max_advance > 0.0009); + } + else + { + f32 width = 0.0; + for(u64 i = 0; i < str.length; i += 1) + { + width += GlyphWidth(abuf.atlas.glyphs.ptr + str.ptr[i], abuf); + } } return width; } pragma(inline) f32 -GlyphWidth(Glyph* g) +GlyphWidth(Glyph* g, FontAtlasBuf* abuf) { - return g.ch == '\t' ? (g_ui_ctx.atlas_buf.atlas.glyphs[' '].advance*cast(f32)(g_ui_ctx.tab_width)) : g.advance; + return g.ch == '\t' ? (abuf.atlas.glyphs[' '].advance*cast(f32)(g_ui_ctx.tab_width)) : g.advance; } void -DrawGlyph(UIItem* item, Glyph* glyph, f32* x_pos, f32 y, Vec4 col = Vec4(1.0)) +DrawGlyph(UIItem* item, Glyph* glyph, u32 atlas_index, f32* x_pos, f32 y, Vec4 col = Vec4(1.0)) { if(glyph) { UICtx* ctx = GetCtx(); Vertex* v = null; - f32 advance = glyph.advance * item.text_scale; + f32 advance = glyph.advance; - if(glyph.ch == '\t') + if(glyph.ch == ' ' || glyph.ch == '\n') + { + *x_pos += advance; + } + else if(glyph.ch == '\t') { *x_pos += advance * (GetCtx().tab_width - 1); } - - f32 r = glyph.plane_right * item.text_scale; - f32 l = glyph.plane_left * item.text_scale; - f32 t = glyph.plane_top * item.text_scale; - f32 b = glyph.plane_bottom * item.text_scale; - - GlyphBounds gb = { - r: r, - l: l, - t: t, - b: b, - w: r - l, - h: b - t, - atlas_r: glyph.atlas_right, - atlas_l: glyph.atlas_left, - atlas_t: glyph.atlas_top, - atlas_b: glyph.atlas_bottom, - }; - - v = ctx.buffers[ctx.f_idx].vtx.ptr + ctx.buffers[ctx.f_idx].count; - - f32 y_pos = (y - gb.t) + TEXT_SIZE; - - v.dst_start = Vec2(*x_pos+gb.l, y_pos); - v.dst_end = Vec2(*x_pos+gb.w+gb.l, y_pos+gb.h); - v.cols = col; - v.texture = true; - v.bounds = ItemBounds(item); - - if(glyph.ch != '\t' && glyph.ch != '\n') + else { - v.src_start = Vec2(gb.atlas_l, gb.atlas_t); - v.src_end = Vec2(gb.atlas_r, gb.atlas_b); - } + f32 r = glyph.plane_right; + f32 l = glyph.plane_left; + f32 t = glyph.plane_top; + f32 b = glyph.plane_bottom; - f32 end_x = *x_pos + advance; - f32 width = end_x - *x_pos; - 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; - v.src_end.x -= (v.src_end.x - v.src_start.x) * cull_pct; - } + GlyphBounds gb = { + r: r, + l: l, + t: t, + b: b, + w: r - l, + h: b - t, + atlas_r: glyph.atlas_right, + atlas_l: glyph.atlas_left, + atlas_t: glyph.atlas_top, + atlas_b: glyph.atlas_bottom, + }; - f32 end_y = y + TEXT_SIZE; - f32 height = end_y - y; - if(end_y > item.rect.p1.y) - { - f32 cull_pct = (end_y - item.rect.p1.y) / height; - v.dst_end.y -= (v.dst_end.y - v.dst_start.y) * cull_pct; - v.src_end.y -= (v.src_end.y - v.src_start.y) * cull_pct; - } + v = ctx.buffers[ctx.f_idx].vtx.ptr + ctx.buffers[ctx.f_idx].count; - static foreach(axis; A2D.min .. A2D.max) - { - static foreach(i; 0 .. v.pos.length) + f32 y_pos = y + gb.t; + + v.dst_start = Vec2(*x_pos+gb.l, y_pos); + v.dst_end = Vec2(*x_pos+gb.w+gb.l, y_pos+gb.h); + v.cols = col; + v.texture = true; + v.bounds = ItemBounds(item); + v.atlas_index = atlas_index; + + if(glyph.ch != '\t' && glyph.ch != '\n') { - 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]; + v.src_start = Vec2(gb.atlas_l, gb.atlas_t); + 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.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; + v.src_end.x -= (v.src_end.x - v.src_start.x) * cull_pct; + } + + /* + f32 end_y = y; + f32 height = end_y - y; + if(end_y > item.rect.p1.y) + { + f32 cull_pct = (end_y - item.rect.p1.y) / height; + v.dst_end.y -= (v.dst_end.y - v.dst_start.y) * cull_pct; + v.src_end.y -= (v.src_end.y - v.src_start.y) * cull_pct; + } + */ + + static foreach(axis; A2D.min .. A2D.max) + { + static foreach(i; 0 .. v.pos.length) + { + 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); + + *x_pos += advance; } - - AddVertexCount(ctx); - - *x_pos += advance; } } @@ -1952,30 +2013,23 @@ GetVertex(UICtx* ctx) } static UISize[2] -MakeUISize(UISize x, UISize y) +UIS2(SizeType t0 = ST.Percentage, SizeType t1 = ST.Percentage, f32 v0 = 1.0, f32 v1 = 1.0, f32 s0 = 1.0, f32 s1 = 1.0) { - return [x, y]; + return [UISize(t0, v0, s0), UISize(t1, v1, s1)]; } static UISize[2] -MakeUISizeX(SizeType type, f32 value, f32 strictness = 1.0) +UISX(SizeType type, f32 value = 1.0, f32 strictness = 1.0) { return [UISize(type, value, strictness), UISize(ST.Percentage, 1.0)]; } static UISize[2] -MakeUISizeY(SizeType type, f32 value, f32 strictness = 1.0) +UISY(SizeType type, f32 value = 1.0, f32 strictness = 1.0) { return [UISize(ST.Percentage, 1.0), UISize(type, value, strictness)]; } -pragma(inline) Glyph* -GetGlyph(u8 ch) -{ - FontAtlas* a = &g_ui_ctx.atlas_buf.atlas; - return ch < a.glyphs.length ? a.glyphs.ptr + ch : a.glyphs.ptr; -} - pragma(inline) void AddVertexCount(UICtx* ctx) { diff --git a/src/editor/views.d b/src/editor/views.d index e1be8a2..d958927 100644 --- a/src/editor/views.d +++ b/src/editor/views.d @@ -31,84 +31,105 @@ struct Panel Axis2D layout_axis; Editor* ed; u64 id; + u32 text_size; } void -LineCounterView(u64 max_line, u64 lines, i64 line_offset, f32 view_offset) +LineCounterView(FontAtlasBuf* abuf, u64 max_line, u64 lines, i64 line_offset, f32 view_offset) { UICtx* ctx = GetCtx(); UIKey zero = ZeroKey(); u64 ch_width = max_line.toChars().length; - f32 lc_width = cast(f32)(ch_width+1)*ctx.char_width; // Should figure out how to accurately measure text width + f32 lc_width = cast(f32)(ch_width+1)*abuf.atlas.max_advance; - PushLayoutAxis(A2D.Y, true); - PushViewOffsetY(view_offset, true); - PushPaddingX(4.0, true); - PushSizeInfoX(ST.Pixels, lc_width, 1.0, true); + enum UIPushInfo[] lc_params = [ + { "layout_axis", q{ A2D.Y } }, + { "view_offset", q{ Vec2(0.0, view_offset) } }, + { "padding", q{ Vec2(8.0) } }, + { "size_info", q{ UISX(ST.Pixels, lc_width) }}, + ]; + + mixin(PushOnce!(lc_params)); UIItem* line_count = MakeItem(zero, UIF.DrawBorder|UIF.PortalViewY); - PushTextCol(Vec4(1.0)); - PushSizeInfoY(ST.Pixels, TEXT_SIZE); - PushParent(line_count); + mixin(PushScope!("text_col", q{ Vec4(1.0) } )); + mixin(PushScope!("size_info", q{ UISY(ST.Pixels, abuf.atlas.line_height) } )); + mixin(PushScope!("parent", q{ line_count } )); u64 end_line = lines+line_offset; for(u64 i = line_offset; i < end_line && i < max_line; i += 1) { char[] buf = ScratchAlloc!(char)(ch_width); - Push!("display_string")(ConvToStr(sformat(buf, "%s", i)), true); + Push!("display_string")(ConvToStr(sformat(ScratchAlloc!(char)(ch_width), "%s", i)), true); MakeItem(zero, UIF.DrawText); } - - Pop!("text_col", "size_info", "parent"); } void -EditorTextView(UIItem* editor, Panel* p, u64 lines, i64 line_offset, f32 view_offset) +EditorTextView(UIItem* editor, Panel* p, FontAtlasBuf* abuf, u64 lines, i64 line_offset, f32 view_offset) { Editor* ed = p.ed; PushLayoutAxis(A2D.Y, true); - f32 clamp_y = cast(f32)(ed.buf.line_count-lines)*TEXT_SIZE; - f32 scroll_pos = cast(f32)(ed.line_offset)*TEXT_SIZE; + f32 text_size = cast(f32)p.text_size; + f32 clamp_y = cast(f32)(ed.buf.line_count-lines)*text_size; + f32 scroll_pos = cast(f32)(ed.line_offset)*text_size; + f32 padding = 8.0; - PushLayoutAxis(A2D.Y, true); - PushScrollClampY(0.0, clamp_y, true); - PushSizeInfo(g_size_info_default, true); - PushBorderCol(Vec4(1.0), true); - PushScrollTargetY(scroll_pos, true); - PushViewOffsetY(view_offset, true); + enum UIPushInfo[] text_view_params = [ + { "layout_axis", q{ A2D.Y } }, + { "border_col", q{ Vec4(1.0) } }, + { "size_info", q{ UIS2() } }, + { "scroll_target", q{ Vec2(0.0, scroll_pos) } }, + { "scroll_clamp", q{ Vec2(0.0, clamp_y) } }, + { "view_offset", q{ Vec2(0.0, view_offset) } }, + { "padding", q{ Vec2(padding) } }, + ]; + mixin(PushOnce!(text_view_params)); editor = MakeItem(editor.key, UIF.DrawBorder|UIF.ScrollY|UIF.ClampY); - PushParent(editor); + mixin(PushScope!("parent", q{ editor })); + UIKey zero = ZeroKey(); // Cursor { LineBuffer* lb = GetLine(&ed.buf, ed.cursor_pos.y); - f32 cursor_x = CalcTextWidth(lb.text[0 .. ed.cursor_pos.x]); - f32 cursor_y = cast(f32)(ed.cursor_pos.y - line_offset)*TEXT_SIZE + view_offset; - PushSizeInfo(MakeUISize(UISize(ST.Pixels, GetCtx().char_width), UISize(ST.Pixels, TEXT_SIZE)), true); - PushFixedPos(Vec2(cursor_x, cursor_y), true); - PushBgCol(Vec4(1.0), true); + u8 ch = lb.text.length > ed.cursor_pos.y ? lb.text[ed.cursor_pos.y] : 0; + f32 line_h = abuf.atlas.line_height; + f32 cursor_x = CalcTextWidth!(false)(lb.text[0 .. ed.cursor_pos.x], abuf); + f32 cursor_y = cast(f32)(ed.cursor_pos.y - line_offset)*line_h; + Glyph* g = abuf.atlas.glyphs.length > ch ? abuf.atlas.glyphs.ptr + ch : abuf.atlas.glyphs.ptr + ' '; + + enum UIPushInfo[] cursor_info = [ + { "size_info", q{ UIS2(ST.Pixels, ST.Pixels, g.advance, line_h) } }, + { "fixed_pos", q{ Vec2(cursor_x, cursor_y) } }, + { "bg_col", q{ Vec4(1.0) } }, + ]; + mixin(PushOnce!(cursor_info)); + MakeItem(zero, UIF.DrawBackground|UIF.FixedPosition); } - u64 end_line = line_offset+lines; - PushSizeInfoY(ST.TextSize, 1.0); - PushSyntaxHighlight(UISH.D); + mixin(PushScope!("size_info", q{ UISY(ST.TextSize) } )); + mixin(PushScope!("syntax_highlight", q{ UISH.D } )); - scope(exit) Pop!("size_info", "parent", "syntax_highlight"); + // NEED TO FIX LINES BEING OFFSET FOR WHATEVER REASON u64 i = line_offset; for(LineBuffer* lb = GetLine(&ed.buf, i); !CheckNil(g_NIL_LINE_BUF, lb) && i < line_offset+lines; i += 1, lb = GetLine(&ed.buf, i)) { - PushDisplayString(ConvToStr(lb.text), true); - PushSyntaxTokens(cast(u8[])lb.style, true); + enum UIPushInfo[] lc_info = [ + { "display_string", q{ ConvToStr(lb.text) } }, + { "syntax_tokens", q{ cast(u8[])(lb.style) } }, + ]; + mixin(PushOnce!(lc_info)); + UIItem* line = MakeItem(zero, UIF.DrawText); } } @@ -116,9 +137,10 @@ EditorTextView(UIItem* editor, Panel* p, u64 lines, i64 line_offset, f32 view_of void EditorView(Panel* p) { - Editor* ed = p.ed; - UICtx* ctx = GetCtx(); - UIKey zero = ZeroKey(); + Editor* ed = p.ed; + UICtx* ctx = GetCtx(); + UIKey zero = ZeroKey(); + FontAtlasBuf* abuf = GetFontAtlas(p.text_size); if(CheckNil(g_NIL_ED, ed)) { @@ -132,24 +154,26 @@ EditorView(Panel* p) UIKey ed_key = MakeKey("###ed_%s", ed.editor_id); UIItem* editor = Get(ed_key); - u64 frame_line_offset = ed.line_offset; - f32 frame_view_offset = -(editor.scroll_offset.y%TEXT_SIZE); + f32 text_size = abuf.atlas.line_height; - PushBgCol(BG_COL, true); - PushSizeInfoX(ST.Percentage, 1.0, 1.0, true); + u64 frame_line_offset = ed.line_offset; + f32 frame_view_offset = -(editor.scroll_offset.y%text_size); + + enum UIPushInfo[] c_info = [ + { "bg_col", q{ BG_COL } }, + { "size_info", q{ UIS2() } }, + ]; + mixin(PushOnce!(c_info)); UIItem* container = MakeItem(zero, UIF.DrawBackground); - PushParent(container); - PushBorderCol(Vec4(1.0)); - - scope(exit) Pop!("parent", "border_col"); + mixin(PushScope!("parent", q{ container } )); + mixin(PushScope!("border_col", q{ Vec4(1.0) } )); u64 view_lines; if(editor.size.y > 0.0) { - view_lines = cast(u64)ceil(editor.size.y/TEXT_SIZE)+1; - + view_lines = cast(u64)floor(editor.size.y/text_size); const u64 SCROLL_BUFFER = 4; u64 start = ed.line_offset; @@ -166,9 +190,9 @@ EditorView(Panel* p) } } - u64 start = cast(u64)floor(editor.scroll_offset.y/TEXT_SIZE); - LineCounterView(ed.buf.line_count, view_lines, start, frame_view_offset); - EditorTextView(editor, p, view_lines, start, frame_view_offset); + u64 start = cast(u64)floor(editor.scroll_offset.y/text_size); + LineCounterView(abuf, ed.buf.line_count, view_lines, start, frame_view_offset); + EditorTextView(editor, p, abuf, view_lines, start, frame_view_offset); for(UIInput* i = ctx.events.first; !CheckNil(g_UI_NIL_INPUT, i) && g_ed_ctx.focused_editor == p.ed; i = i.next) { @@ -201,355 +225,73 @@ EditorView(Panel* p) ed.cursor_pos = VecPos(&ed.buf); } + + ResetBuffer(&ed.buf); } void CommandPalette(CmdPalette* cmd) { - UICtx* ctx = GetCtx(); - Vec2 ext = GetExtent(); + UICtx* ctx = GetCtx(); + Vec2 ext = GetExtent(); + FontAtlasBuf* abuf = &g_ui_ctx.glyph_sets[0].abuf; f32 w = ext.x*0.4; f32 h = ext.y*0.7; - PushFixedPos(Vec2(ext.x*0.3, ext.y*0.1), true); - PushBgCol(BG_COL, true); - PushBorderCol(HL_BORDER_COL, true); - PushBorderThickness(2.0f, true); - PushCornerRadius(8.0f, true); - PushViewOffset(Vec2(-2.0f), true); - PushLayoutAxis(A2D.Y, true); - PushSizeInfo(MakeUISize(UISize(ST.Pixels, w), UISize(ST.Pixels, h))); + enum UIPushInfo[] cmd_params = [ + { "layout_axis", q{ A2D.Y } }, + { "fixed_pos", q{ Vec2(ext.x*0.3, ext.y*0.1) } }, + { "bg_col", q{ BG_COL } }, + { "border_col", q{ HL_BORDER_COL } }, + { "border_thickness", q{ 4.0 } }, + { "corner_radius", q{ Vec4(8.0) } }, + { "size_info", q{ UIS2(ST.Pixels, ST.Pixels, w, h) } }, + ]; + mixin(PushOnce!(cmd_params)); UIItem* cmd_item = MakeItem("###cmd_palette", UIF.Window|UIF.FixedPosition|UIF.DrawBackground|UIF.DrawBorder); - f32 padding_y = 8.0; - PushParent(cmd_item); - PushPadding(Vec2(4.0, padding_y), true); - scope(exit) Pop!("parent", "padding")(); + f32 padding_y = 4.0; - PushBgCol(HL_BG_COL, true); - PushBorderCol(HL_BORDER_COL); - PushBorderThickness(2.0f, true); - PushCornerRadius(Vec4(8.0, 8.0, 0.0, 0.0), true); - PushSizeInfo(MakeUISize(UISize(ST.Pixels, w-padding_y), UISize(ST.TextSize, 1.0)), true); - PushDisplayString(ConvToStr(cmd.buffer[0 .. cmd.icount]), true); + mixin(PushScope!("parent", q{ cmd_item } )); + mixin(PushScope!("padding", q{ Vec2(4.0, padding_y) })); + + enum UIPushInfo[] cmd_input_params = [ + { "bg_col", q{ HL_BG_COL } }, + { "size_info", q{ UISY(ST.TextSize) } }, + { "display_string", q{ ConvToStr(cmd.buffer[0 .. cmd.icount]) } }, + ]; + + mixin(PushOnce!(cmd_input_params)); UIKey zero = ZeroKey(); - MakeItem(zero, UIF.DrawBorder|UIF.DrawBackground|UIF.DrawText|UIF.Overflow); - PushPadding(Vec2(4.0)); - PushSizeInfoY(ST.TextSize, 1.0); - scope(exit) Pop!("size_info", "padding")(); + enum UIPushInfo[] sep_params = [ + { "padding", q{ Vec2(0.0) } }, + { "size_info", q{ UISY(ST.Pixels, 4.0) } }, + { "bg_col", q{ HL_BORDER_COL } }, + ]; + + mixin(PushOnce!(sep_params)); + MakeItem(zero, UIF.DrawBackground); + + mixin(PushScope!("padding", q{ Vec2(4.0) } )); + mixin(PushScope!("size_info", q{ UISY(ST.TextSize) } )); + + u64 max_opts = cast(u64)ceil(h/abuf.atlas.line_height); Vec4[2] opt_cols = [ Vec4(0.22, 0.22, 0.22, 1.0), Vec4(0.35, 0.35, 0.35, 1.0), ]; - foreach(i; 0 .. cmd.opt_strs.length) + for(u64 i = 0; i < cmd.opt_strs.length && i < max_opts; i += 1) { PushDisplayString(ConvToStr(cmd.opt_strs[i]), true); PushBgCol(cmd.selected == i ? HL_BG_COL : opt_cols[i%2], true); MakeItem(zero, UIF.DrawBackground|UIF.DrawText); } - - //PushDisplayString(ConvToStr(cmd.buffer)); } -/* -void -Panel(UIPanel* panel) -{ - UICtx* ctx = GetCtx(); - UIItem* item = Get(panel.id); - Editor* ed = panel.ed; - bool focused = GetFocusedPanel() == panel; - - UIPanel* parent = panel.parent; - UIPanel* prev = panel.prev; - - Axis2D pax = parent.axis; - - Vec2 adj = Vec2( - parent.axis == A2D.X ? 10 : 0, - parent.axis == A2D.Y ? 10 : 0 - ); - - Vec2 p0 = panel.rect.p0+adj; - Vec2 p1 = panel.rect.p1-adj; - Rect r = Rect(p0: p0, p1: p1); - - if(!Nil(prev)) with(panel) - { - Vec2 d0 = rect.p0-adj; - Vec2 d1 = Vec2( - pax == A2D.X ? rect.p0.x+adj.x : rect.p1.x, - pax == A2D.Y ? rect.p0.y+adj.y : rect.p1.y - ); - - Rect dr = Rect(p0: d0, p1: d1); - if(Dragged(item, &dr) && item.dragged.v[pax] != 0.0) - { - f32 mov_pct = Remap(item.dragged.v[pax], 0.0, panel.parent.size.v[pax], 0.0, 1.0); - if(CheckPanelBounds(pct + mov_pct) && CheckPanelBounds(panel.prev.pct - mov_pct)) - { - pct += mov_pct; - panel.prev.pct -= mov_pct; - } - } - } - - if(panel.ed != null) - { - if(Clicked(item, &r)) - { - SetFocusedPanel(panel); - } - - Vec2 inner = InnerSize(panel); - - SetScrollOffset(panel); - - panel.start_ln = cast(u64)(floor(panel.scroll_offset/TEXT_SIZE)); - panel.end_ln = panel.start_ln + cast(u64)(ceil(inner.y/TEXT_SIZE)); - panel.vis_lines = panel.end_ln - panel.start_ln; - - char[64] ch_buf = '\0'; - char[] fmt = ch_buf.sformat("%%0%ss", u64(panel.end_ln.toChars().length)); - - f32 lc_w = panel.end_ln.toChars().length*ctx.char_width + LINE_COUNT_PADDING*2.0; - f32 code_view_width = inner.x-lc_w; - - StartLineBuffer(&panel.ed.buf, code_view_width); - - U64Vec2 pos = VecPos(&ed.buf); - - DrawPanel(panel, lc_w, focused); - - f32 y_rem = fmod(panel.scroll_offset, TEXT_SIZE); - - f32 x = panel.rect.p0.x; - f32 y = panel.rect.p1.y + TEXT_SIZE - fmod(panel.scroll_offset, TEXT_SIZE); - - u64 i = panel.start_ln; - for(auto buf = GetLine(&ed.buf, i); !CheckNil(g_NIL_LINE_BUF, buf) && i < panel.end_ln; i += 1, buf = GetLine(&ed.buf, i)) - { - f32 x_pos = x + LINE_COUNT_PADDING; - DrawLineCount(fmt, &x_pos, y, i); - - u64 ch_offset; - - auto parts = MakeMultiline(buf.text, code_view_width, buf.style); - if(parts == null) - { - if(pos.y == i) - { - DrawCursor([], 0, x+lc_w, y, ch_offset); - } - } - else for(auto n = parts; n != null; n = n.next) - { - auto l = n; - - if(pos.y == i) - { - DrawCursor(l.text, pos.x, x+lc_w, y, ch_offset); - } - - foreach(j; 0 .. l.text.length) - { - bool hl = pos.y == i && !EditModeActive() && j == pos.x-ch_offset; - DrawChar(l.text[j], &x_pos, y, hl ? Vec4(Vec3(0.0), 1.0) : SYNTAX_COLORS[l.style[j]]); - } - - y += TEXT_SIZE; - x_pos = x + lc_w + LINE_COUNT_PADDING*2.0; - ch_offset += l.text.length; - } - } - } -} - -void -CommandPalette(CmdPalette* cmd) -{ - UICtx* ctx = GetCtx(); - - u8[] text = cmd.buffer[0 .. cmd.icount]; - u8[][] options = cmd.opt_strs; - - Vec2 size = RootSize(); - - f32 x = size.x*0.15; - f32 y = size.y*0.1; - f32 w = size.x*0.7; - f32 h = 40.0; - - DrawCmdRect(Vec2(x, y), Vec2(w, h), false); - - f32 y_off = h*0.5 + 6; - f32 ch_x = x + 6.0; - f32 ch_y = y + y_off; - - foreach(i; 0 .. text.length) - { - DrawChar(text[i], &ch_x, ch_y, Vec4(1.0)); - } - - for(u64 i = 0; i < options.length; i += 1) - { - y += h; - ch_x = x + 6.0; - ch_y = y + y_off; - - DrawCmdRect(Vec2(x, y), Vec2(w, h), cmd.selected == i); - - foreach(j; 0 .. options[i].length) - { - DrawChar(options[i][j], &ch_x, ch_y, Vec4(1.0)); - } - - if(y+h > size.y+h) break; - } -} - -bool -CheckPanelBounds(f32 pct) -{ - return pct >= 0.0 && pct <= 1.0; -} - -void -PushPanel(UIPanel* parent, UIPanel* panel) -{ - DLLPush(parent, panel, g_UI_NIL_PANEL); - panel.parent = parent; -} - -void -InsertPanel(UIPanel* parent, UIPanel* prev, UIPanel* panel) -{ - DLLInsert(parent, panel, prev, g_UI_NIL_PANEL); - panel.parent = prev.parent; -} - -void -SetFocusedPanel(UIPanel* panel) -{ - if(!CheckNil(g_UI_NIL_PANEL, panel)) - { - g_ui_ctx.focused_panel = panel; - } -} - -UIPanel* -GetFocusedPanel() -{ - return Nil(g_ui_ctx.focused_panel) ? g_UI_NIL_PANEL : g_ui_ctx.focused_panel; -} - -TextBuffer* -MakeMultiline(u8[] text, f32 width, TS[] style = []) -{ - f32 scaled_width = width * (g_ui_ctx.atlas_buf.atlas.size/g_ui_ctx.text_size); - f32 text_width = CalcTextWidth(text); - - u64 line_count = cast(u64)(ceil(text_width/scaled_width)); - TextBuffer* node = null; - if(line_count > 0) - { - f32 w = 0.0; - u64 line = 0; - u64 start = 0; - const u64 extra_buf = 20; - for(u64 i = 0; i < text.length; i += 1) - { - f32 ch_w = GlyphWidth(g_ui_ctx.atlas_buf.atlas.glyphs.ptr + text[i]); - - if(ch_w + w > scaled_width || i == text.length-1) - { - u64 len = i-start+1; - - u8[] str = ScratchAlloc!(u8)(text, start, len); - - TS[] stl = []; - if(style.length > 0) - { - stl = ScratchAlloc!(TS)(style, start, len); - } - - TextBuffer* n = node; - for(;;) - { - if(node == null) - { - node = ScratchAlloc!(TextBuffer)(); - - node.text = str; - node.style = stl; - node.next = null; - - break; - } - - if(n.next == null) - { - n.next = ScratchAlloc!(TextBuffer)(); - - n.next.text = str; - n.next.style = stl; - n.next.next = null; - - break; - } - - n = n.next; - } - - line += 1; - start = i; - w = 0.0; - } - - w += ch_w; - } - } - - return node; -} - -pragma(inline) void -DrawCursor(u8[] text, u64 ch_x, f32 x, f32 y, u64 offset) -{ - Glyph* g = GetGlyph(' '); - foreach(j; 0 .. text.length) - { - bool hl = j == ch_x-offset; - if(hl) - { - break; - } - - g = j == text.length-1 ? GetGlyph(' ') : GetGlyph(text[j]); - x += GlyphWidth(g); - } - - DrawRect(x, y, cast(u8)g.ch, Vec4(1.0), EditModeActive()); -} - -pragma(inline) void -DrawLineCount(char[] fmt, f32* x_pos, f32 y, u64 line) -{ - char[32] line_buf = '\0'; - char[] line_str = sformat(line_buf, fmt, line+1); - - foreach(j; 0 .. line_str.length) - { - DrawChar(line_str[j], x_pos, y, Vec4(1.0)); - } - - *x_pos += LINE_COUNT_PADDING; -} -*/ diff --git a/src/shaders/gui.frag.glsl b/src/shaders/gui.frag.glsl index 5ae2b2a..67442a5 100644 --- a/src/shaders/gui.frag.glsl +++ b/src/shaders/gui.frag.glsl @@ -5,9 +5,14 @@ #include "gui.layout" -layout (location = 0) flat in uint in_has_texture; +layout (location = 0) flat in struct FragDataFlatIn +{ + uint texture; + uint atlas_index; +} FDF; -layout (location = 1) in struct FragDataIn { +layout (location = 2) in struct FragDataIn +{ vec4 color; vec2 uv; vec2 dst_pos; @@ -20,7 +25,6 @@ layout (location = 1) in struct FragDataIn { float border_thickness; } FD; - layout (location = 0) out vec4 FragColor; float RectSDF(vec2 pos, vec2 half_size, float radius) @@ -75,7 +79,7 @@ void main() vec4 gamma = vec4(1.0/1.4); vec4 tex_color = vec4(1.0); - if(in_has_texture != 0) + if(FDF.texture != 0) { tex_color = texture(sampler2D(SpriteAtlas, SamplerNearest), FD.uv); } diff --git a/src/shaders/gui.layout b/src/shaders/gui.layout index 2555672..e27d573 100644 --- a/src/shaders/gui.layout +++ b/src/shaders/gui.layout @@ -1,9 +1,11 @@ layout (rgba16f, set = 0, binding = 0) uniform image2D DrawImage; -layout (set = 1, binding = 0) uniform texture2D SpriteAtlas; +layout (set = 1, binding = 0) uniform texture2D SpriteAtlasArray[24]; layout (set = 1, binding = 1) uniform sampler SamplerNearest; layout (push_constant) uniform Constants { mat4 projection; } PC; + +#define SpriteAtlas SpriteAtlasArray[FDF.atlas_index] diff --git a/src/shaders/gui.vert.glsl b/src/shaders/gui.vert.glsl index ba71ca7..99dfa3d 100644 --- a/src/shaders/gui.vert.glsl +++ b/src/shaders/gui.vert.glsl @@ -17,10 +17,16 @@ layout (location = 9) in float border_thickness; layout (location = 10) in float edge_softness; layout (location = 11) in float raised; layout (location = 12) in uint in_has_texture; +layout (location = 13) in uint in_atlas_index; -layout (location = 0) flat out uint out_has_texture; +layout (location = 0) flat out struct FragDataFlatOut +{ + uint texture; + uint atlas_index; +} FDF; -layout (location = 1) out struct FragDataOut { +layout (location = 2) out struct FragDataOut +{ vec4 color; vec2 uv; vec2 dst_pos; @@ -31,7 +37,7 @@ layout (location = 1) out struct FragDataOut { float softness; float raised; float border_thickness; -} FragData; +} FD; vec2 Vertices[4] = vec2[4]( vec2(-1.0, -1.0), @@ -77,17 +83,18 @@ void main() vec2 dst_verts_pct = vec2(bool(gl_VertexIndex >> 1) ? 1.0f : 0.0f, bool(gl_VertexIndex & 1) ? 0.0f : 1.0f); - FragData.color = in_col; - FragData.uv = uvs[gl_VertexIndex] / tex_size; - FragData.dst_pos = pos; - FragData.dst_center = center; - FragData.dst_half_size = half_size; - FragData.corner_radius = corner_radius[gl_VertexIndex]; - FragData.softness = edge_softness; - FragData.raised = raised; - FragData.border_thickness = border_thickness; - FragData.sdf_sample_pos = (2.0f * dst_verts_pct - 1.0f) * half_size; - out_has_texture = in_has_texture; + FD.color = in_col; + FD.uv = uvs[gl_VertexIndex] / tex_size; + FD.dst_pos = pos; + FD.dst_center = center; + FD.dst_half_size = half_size; + FD.corner_radius = corner_radius[gl_VertexIndex]; + FD.softness = edge_softness; + FD.raised = raised; + FD.border_thickness = border_thickness; + FD.sdf_sample_pos = (2.0f * dst_verts_pct - 1.0f) * half_size; + FDF.texture = in_has_texture; + FDF.atlas_index = in_atlas_index; 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);