diff --git a/src/editor/buffer.d b/src/editor/buffer.d index 544bcdf..0c26f68 100644 --- a/src/editor/buffer.d +++ b/src/editor/buffer.d @@ -6,9 +6,10 @@ import util; struct FlatBuffer { Arena arena; - u8[] data; - u64 length; - u64 line_count; + u8[] data; + u64 length; + u64 line_count; + Range pos; } struct Range @@ -17,6 +18,13 @@ struct Range u32 y; } +struct LineBuffers +{ + Arena arena; + u8[][] lines; + u32[] lengths; +} + FlatBuffer CreateFlatBuffer(u8[] data) { @@ -42,6 +50,14 @@ CreateFlatBuffer(u8[] data) ); } +LineBuffers +CreateLineBuffers(u64 arena_size) +{ + return LineBuffers( + arena: CreateArena(arena_size), + ); +} + void Insert(FlatBuffer* buffer, u8[] insert, u64 length, u64 pos) { @@ -81,11 +97,17 @@ Insert(FlatBuffer* buffer, u8[] insert, u64 length, Range pos) Insert(buffer, insert, length, RangeToPos(buffer, pos)); } +// TODO: handle case for when lines are longer than line buffer void -GetLines(FlatBuffer* buffer, u8[][] lines, u64 start_line, u64 length) +GetLines(FlatBuffer* buffer, LineBuffers* linebufs, u64 start_line, u64 length) { - assert(length <= lines.length, "GetLines failure: selection cannot fit within lines buffer"); assert(start_line < buffer.line_count, "GetLines failure: start is not less than line_count"); + assert(linebufs != null, "GetLines failure: linebufs is null"); + + Reset(&linebufs.arena); + linebufs.lines = AllocArray!(u8[])(&linebufs.arena, length); + linebufs.lengths = AllocArray!(u32)(&linebufs.arena, length); + i64 start = -1; u64 line = 0; u64 current_line = 0; @@ -105,7 +127,9 @@ GetLines(FlatBuffer* buffer, u8[][] lines, u64 start_line, u64 length) if (start < 0 && new_line) { - lines[current_line] = buffer.data[i .. i+1]; + linebufs.lines[current_line] = AllocArray!(u8)(&linebufs.arena, 1); + linebufs.lines[current_line][0] = '\n'; + linebufs.lengths[current_line] = 1; current_line += 1; continue; } @@ -118,7 +142,9 @@ GetLines(FlatBuffer* buffer, u8[][] lines, u64 start_line, u64 length) if (new_line) { - lines[current_line] = buffer.data[start .. i]; + linebufs.lines[current_line] = AllocArray!(u8)(&linebufs.arena, i-start); + linebufs.lines[current_line][0 .. $] = buffer.data[start .. i]; + linebufs.lengths[current_line] = cast(u32)(i-start); current_line += 1; start = -1; continue; @@ -126,7 +152,9 @@ GetLines(FlatBuffer* buffer, u8[][] lines, u64 start_line, u64 length) if (i == buffer.length-1) { - lines[current_line] = buffer.data[start .. buffer.length]; + linebufs.lines[current_line] = AllocArray!(u8)(&linebufs.arena, buffer.length-start); + linebufs.lines[current_line][0 .. $] = buffer.data[start .. buffer.length]; + linebufs.lengths[current_line] = cast(u32)(buffer.length-start); } } } diff --git a/src/editor/editor.d b/src/editor/editor.d index c008624..d3a636a 100644 --- a/src/editor/editor.d +++ b/src/editor/editor.d @@ -5,6 +5,7 @@ import fonts; import vulkan; import math; import alloc; +import buffer; import std.stdio; import std.exception; @@ -18,7 +19,7 @@ struct Editor PlatformWindow* window; Renderer rd; - ImageView font_atlas; + ImageView font_atlas; Pipeline pipeline; DescSetLayout desc_set_layout; DescSet desc_set; @@ -30,8 +31,11 @@ struct Editor u32[] indices; u32 ui_count; - Buffer[] buffers; + FlatBuffer[] buffers; u8[][] buffer_names; + u32 buffer_count; + FlatBuffer* active_buffer; + LineBuffers linebufs; u8[] font_data; FontFace font; @@ -59,7 +63,13 @@ Cycle(Editor* ed) Reset(&ed.temp_arena); - DrawText(ed, 200.0, 200.0, 16.0, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + f32 pos = 0.0; + f32 h = ed.atlas_buf.atlas.size; + foreach(i, line; ed.linebufs.lines) + { + DrawText(ed, 0.0, pos, h, line[0 .. ed.linebufs.lengths[i]]); + pos += h; + } BeginFrame(&ed.rd); @@ -103,7 +113,7 @@ LoadFile(Arena* arena, string name) } Editor -CreateEditor(PlatformWindow* window) +CreateEditor(PlatformWindow* window, u8[] buffer_data, u8[] buffer_name) { InitFreeType(); @@ -124,7 +134,7 @@ CreateEditor(PlatformWindow* window) u8[] font_data = LoadFile(&arena, "assets/pc-9800.ttf"); FontFace font = OpenFont(font_data); - FontAtlasBuf atlas_buf = CreateAtlas(&arena, font, 16.0, 256); + FontAtlasBuf atlas_buf = CreateAtlas(&arena, font, 14.0, 256); Editor editor = { window: window, @@ -134,8 +144,25 @@ CreateEditor(PlatformWindow* window) font_data: font_data, font: font, atlas_buf: atlas_buf, + buffers: MAllocArray!(FlatBuffer)(32), + buffer_names: MAllocArray!(u8[])(32), + linebufs: CreateLineBuffers(MB(32)), }; + if (buffer_data != null) + { + assert(buffer_name != null, "CreateEditor failure: buffer_name is null while buffer_data is not"); + + editor.buffers[0] = CreateFlatBuffer(buffer_data); + editor.buffer_names[0] = AllocArray!(u8)(&editor.arena, buffer_name.length); + editor.buffer_names[0][0 .. $] = buffer_name[0 .. $]; + + editor.buffer_count += 1; + editor.active_buffer = &editor.buffers[0]; + + GetLines(editor.active_buffer, &editor.linebufs, 0, editor.active_buffer.line_count); + } + DescLayoutBinding[2] layout_bindings = [ { binding: 0, descriptorType: DT.Image, descriptorCount: 1, stageFlags: SS.All }, { binding: 1, descriptorType: DT.Storage, descriptorCount: 1, stageFlags: SS.All }, @@ -188,6 +215,7 @@ DrawText(Editor* ed, f32 x, f32 y, f32 px, string str) void DrawText(Editor* ed, f32 x, f32 y, f32 px, u8[] str) { + u32 tab_count = 2; f32 x_pos = x; f32 scale = px / ed.atlas_buf.atlas.size; foreach(ch; str) @@ -196,29 +224,25 @@ DrawText(Editor* ed, f32 x, f32 y, f32 px, u8[] str) { if (ch == glyph.ch) { - Vertex* v = ed.vertices.ptr + ed.ui_count; - - f32 r = glyph.plane_right * scale; - f32 l = glyph.plane_left * scale; - f32 w = r - l; - f32 h = (glyph.plane_bottom - glyph.plane_top) * scale; - f32 y_pos = glyph.plane_top * scale; - - v.dst_start.x = x_pos + l; - v.dst_start.y = y + h - y_pos; - v.dst_end.x = x_pos + w + l; - v.dst_end.y = y - y_pos; - - v.src_start.x = glyph.atlas_left; - v.src_start.y = glyph.atlas_top; - v.src_end.x = glyph.atlas_right; - v.src_end.y = glyph.atlas_bottom; - - v.col = Vec4(1.0, 1.0, 1.0, 1.0); - - x_pos += glyph.advance * scale; - - AddUIIndices(ed); + if (ch == '\t') + { + Glyph g = glyph; + g.atlas_left = g.atlas_right = 0.0; + foreach(i; 0 .. tab_count) + { + DrawGlyph(ed, &g, scale, &x_pos, y); + } + } + else if (ch == '\n') + { + Glyph g = glyph; + g.atlas_left = g.atlas_right = 0.0; + DrawGlyph(ed, &g, scale, &x_pos, y); + } + else + { + DrawGlyph(ed, &glyph, scale, &x_pos, y); + } break; } @@ -226,6 +250,41 @@ DrawText(Editor* ed, f32 x, f32 y, f32 px, u8[] str) } } +pragma(inline): void +DrawGlyph(Editor* ed, Glyph* glyph, f32 scale, f32* x_pos, f32 y) +{ + if (glyph.atlas_left != glyph.atlas_right) + { + Vertex* v = ed.vertices.ptr + ed.ui_count; + + f32 r = glyph.plane_right * scale; + f32 l = glyph.plane_left * scale; + f32 w = r - l; + f32 h = (glyph.plane_bottom - glyph.plane_top) * scale; + f32 y_pos = glyph.plane_top * scale; + + v.dst_start.x = *x_pos + l; + v.dst_start.y = y + h - y_pos; + v.dst_end.x = *x_pos + w + l; + v.dst_end.y = y - y_pos; + + v.src_start.x = glyph.atlas_left; + v.src_start.y = glyph.atlas_top; + v.src_end.x = glyph.atlas_right; + v.src_end.y = glyph.atlas_bottom; + + v.col = Vec4(1.0, 1.0, 1.0, 1.0); + if (glyph.atlas_left == glyph.atlas_right) + { + v.col.r = v.col.g = v.col.b = 0.0; + } + + AddUIIndices(ed); + } + + *x_pos += glyph.advance * scale; +} + void AddUIIndices(Editor* ed) { diff --git a/src/editor/main.d b/src/editor/main.d index 6004b0f..fd808be 100644 --- a/src/editor/main.d +++ b/src/editor/main.d @@ -1,11 +1,25 @@ +import aliases; import platform; import editor; +import std.stdio; +import alloc; void main(string[] argv) { + u8[] buffer = null; + u8[] buffer_name = null; + if (argv.length > 1) + { + buffer_name = (cast(u8*)argv[1].ptr)[0 .. argv[1].length]; + File f = File(argv[1], "rb"); + buffer = MAllocArray!(u8)(f.size()); + f.rawRead(buffer); + f.close(); + } + PlatformWindow window = CreateWindow("Editor", 1920, 1080); - Editor editor = CreateEditor(&window); + Editor editor = CreateEditor(&window, buffer, buffer_name); while (true) {