diff --git a/src/build_tool/cache.cpp b/src/build_tool/cache.cpp index 0902057..8cbc0cf 100644 --- a/src/build_tool/cache.cpp +++ b/src/build_tool/cache.cpp @@ -1,3 +1,11 @@ +/* @todo: I guess I'm overcomplicating a little: +https://github.com/Mango0x45/cbs/ + +Seems like you only need to compare timestamps of all files with the artifact timestamp, +if one of the files is newer then the artifact then it needs to be recompiled. Do we +even need to store anything then? Just supply artifact file in code and that's it? + +*/ #define SRC_CACHE_ENTRY_COUNT 1024 struct SRC_CacheEntry { diff --git a/src/text_editor/main.cpp b/src/text_editor/main.cpp index a7f0769..2039bc0 100644 --- a/src/text_editor/main.cpp +++ b/src/text_editor/main.cpp @@ -4,25 +4,10 @@ #include "raymath.h" #include "buffer.cpp" +#include "rect2.cpp" Arena FrameArena; -using Vec2 = Vector2; -struct Rect2 { - Vec2 min; - Vec2 max; -}; - -Vec2 GetSize(Rect2 r) { - Vec2 result = {r.max.x - r.min.x, r.max.y - r.min.y}; - return result; -} - -Rectangle ToRectangle(Rect2 r) { - Rectangle result = {r.min.x, r.min.y, r.max.x - r.min.x, r.max.y - r.min.y}; - return result; -} - // Render units - positions ready to draw, y // World units - positions offset by screen movement // Window units - positions inside the window (starts in left top of window) @@ -59,8 +44,6 @@ Rect2 GetScreenRectRenderUnits() { return result; } -// Draw text using Font -// NOTE: chars spacing is NOT proportional to fontSize void DrawString(Font font, String text, Vector2 position, float fontSize, float spacing, Color tint) { if (font.texture.id == 0) font = GetFontDefault(); // Security check in case of not valid font @@ -100,13 +83,16 @@ int main() { Array windows = {}; windows.add({GetScreenRectRenderUnits()}); { - Buffer *buffer = &windows[0].buffer; + Window *window = &windows[0]; + Buffer *buffer = &window->buffer; InitBuffer(buffer); for (int i = 0; i < 100; i += 1) { Array edits = {FrameArena}; AddEdit(&edits, GetEnd(*buffer), Format(FrameArena, "line number: %d\n", i)); ApplyEdits(buffer, edits); } + + window->cursors.add({}); } Vec2 camera_offset_world_to_render_units = {}; @@ -130,15 +116,22 @@ int main() { } Array edits = {FrameArena}; - AddEdit(&edits, {}, string); + For(focused_window->cursors) { + AddEdit(&edits, it, string); + } ApplyEdits(&focused_window->buffer, edits); } + + if (IsKeyPressed(KEY_F1)) { + font = LoadFontEx("C:/Windows/Fonts/consola.ttf", (int)font_size, NULL, 250); + } } BeginDrawing(); ClearBackground(RAYWHITE); ForItem(window, windows) { + // Draw the frame Rect2 window_rect_in_render_units = { WorldToRenderUnits(window.rect_in_world_units.min, camera_offset_world_to_render_units), WorldToRenderUnits(window.rect_in_world_units.max, camera_offset_world_to_render_units), @@ -146,11 +139,18 @@ int main() { Rectangle rectangle_in_render_units = ToRectangle(window_rect_in_render_units); DrawRectangleRec(rectangle_in_render_units, WHITE); - // - // Line rendering - // - // @todo: how to constrain x? - // @optimize: I could clip to visible on screen window_rectangle but I couldn't get it right + Rect2 screen_rect_in_render_units = GetScreenRectRenderUnits(); + Rect2 window_rect_in_render_units_clamped_to_screen = window_rect_in_render_units; + window_rect_in_render_units_clamped_to_screen.min.x = Clamp(window_rect_in_render_units_clamped_to_screen.min.x, screen_rect_in_render_units.min.x, screen_rect_in_render_units.max.x); + window_rect_in_render_units_clamped_to_screen.max.x = Clamp(window_rect_in_render_units_clamped_to_screen.max.x, screen_rect_in_render_units.min.x, screen_rect_in_render_units.max.x); + window_rect_in_render_units_clamped_to_screen.min.y = Clamp(window_rect_in_render_units_clamped_to_screen.min.y, screen_rect_in_render_units.min.y, screen_rect_in_render_units.max.y); + window_rect_in_render_units_clamped_to_screen.max.y = Clamp(window_rect_in_render_units_clamped_to_screen.max.y, screen_rect_in_render_units.min.y, screen_rect_in_render_units.max.y); + if (0) { + window_rect_in_render_units_clamped_to_screen = Shrink(window_rect_in_render_units_clamped_to_screen, 10); + DrawRectangleRec(ToRectangle(window_rect_in_render_units_clamped_to_screen), {255, 0, 0, 50}); + } + + // Figure out which lines to draw Vec2 s = GetSize(window_rect_in_render_units); float line_offset = font_size; float _line_min_y = (window.window_world_to_window_units.y) / line_offset; @@ -158,27 +158,40 @@ int main() { int64_t line_min_y = (int64_t)floorf(_line_min_y); int64_t line_max_y = (int64_t)ceilf(_line_max_y); - Vec2 window_rect_in_render_units_size = GetSize(window_rect_in_render_units); - BeginScissorMode((int)window_rect_in_render_units.min.x, (int)window_rect_in_render_units.min.y, (int)window_rect_in_render_units_size.x, (int)window_rect_in_render_units_size.y); + struct Cell { + Rect2 rect; + int codepoint; + int64_t pos; + }; + + struct CellRow { + Array cells; + Rect2 rect; + int64_t line; + }; + + Array rows = {FrameArena}; for (int64_t line = line_min_y; line < line_max_y; line += 1) { if (line < 0) break; if (line >= window.buffer.lines.len) break; + CellRow row = {}; + row.line = line; + row.cells.allocator = FrameArena; + Range line_range = window.buffer.lines[line]; Vec2 text_position_in_world_window_units = {0, line_offset * (float)line}; Vec2 text_position_in_window_units = WindowWorldToWindowUnits(text_position_in_world_window_units, window); Vec2 text_position_in_world_units = WindowToWorldUnits(text_position_in_window_units, window); Vec2 text_position_in_render_units = WorldToRenderUnits(text_position_in_world_units, camera_offset_world_to_render_units); + row.rect.min = text_position_in_render_units; - // - // Glyph inside the line rendering - // String text = GetString(window.buffer, line_range); if (font.texture.id == 0) font = GetFontDefault(); float textOffsetX = 0.0f; float scaleFactor = font_size / font.baseSize; // Character quad scaling factor - for (int i = 0; i < text.len;) { + for (int64_t i = 0; i < text.len;) { int codepointByteCount = 0; int codepoint = GetCodepointNext(&text.data[i], &codepointByteCount); int index = GetGlyphIndex(font, codepoint); @@ -188,18 +201,57 @@ int main() { float x_to_offset_by = ((float)glyph->advanceX * scaleFactor + font_spacing); if (glyph->advanceX == 0) x_to_offset_by = ((float)font.recs[index].width * scaleFactor + font_spacing); - Vec2 cell_size = {x_to_offset_by, font_size}; - Rect2 cell_rect = {glyph_position, Vector2Add(glyph_position, cell_size)}; - - DrawRectangleLinesEx(ToRectangle(cell_rect), 1, {255, 0, 0, 120}); - if ((codepoint != ' ') && (codepoint != '\t')) { - DrawTextCodepoint(font, codepoint, glyph_position, font_size, BLACK); + Vec2 cell_size = {x_to_offset_by, font_size}; + Rect2 cell_rect = {glyph_position, Vector2Add(glyph_position, cell_size)}; + Rectangle cell_rectangle = ToRectangle(cell_rect); + if (CheckCollisionRecs(cell_rectangle, ToRectangle(window_rect_in_render_units_clamped_to_screen))) { + row.cells.add({cell_rect, codepoint, line_range.min + i}); + row.rect.max = cell_rect.max; } textOffsetX += x_to_offset_by; i += codepointByteCount; // Move text bytes counter to next codepoint } + + if (row.cells.len) rows.add(row); } + + // Draw debug markers + if (0) { + ForItem(row, rows) { + For(row.cells) { + DrawRectangleLinesEx(ToRectangle(it.rect), 1, {255, 0, 0, 50}); + } + DrawRectangleLinesEx(ToRectangle(row.rect), 1, {0, 190, 50, 255}); + } + } + + // Draw the glyphs + Vec2 window_rect_in_render_units_size = GetSize(window_rect_in_render_units); + BeginScissorMode((int)window_rect_in_render_units.min.x, (int)window_rect_in_render_units.min.y, (int)window_rect_in_render_units_size.x, (int)window_rect_in_render_units_size.y); + ForItem(row, rows) { + For(row.cells) { + if ((it.codepoint != ' ') && (it.codepoint != '\t')) { + DrawTextCodepoint(font, it.codepoint, it.rect.min, font_size, BLACK); + } + } + } + + ForItem(cursor, window.cursors) { + ForItem(row, rows) { + Range line_range = window.buffer.lines[row.line]; + if (cursor.min >= line_range.min && cursor.min <= line_range.max) { + ForItem(cell, row.cells) { + if (cursor.min == cell.pos) { + Rect2 rect = cell.rect; + rect = CutLeft(&rect, 4); + DrawRectangleRec(ToRectangle(rect), RED); + } + } + } + } + } + EndScissorMode(); } diff --git a/src/text_editor/rect2.cpp b/src/text_editor/rect2.cpp new file mode 100644 index 0000000..0ab7eb6 --- /dev/null +++ b/src/text_editor/rect2.cpp @@ -0,0 +1,65 @@ +using Vec2 = Vector2; +struct Rect2 { + Vec2 min; + Vec2 max; +}; + +Vec2 GetSize(Rect2 r) { + Vec2 result = {r.max.x - r.min.x, r.max.y - r.min.y}; + return result; +} + +Rectangle ToRectangle(Rect2 r) { + Rectangle result = {r.min.x, r.min.y, r.max.x - r.min.x, r.max.y - r.min.y}; + return result; +} + +Rect2 Shrink(Rect2 result, float v) { + result.min.x += v; + result.max.x -= v; + result.min.y += v; + result.max.y -= v; + return result; +} + +Rect2 CutLeft(Rect2 *r, float value) { + float minx = r->min.x; + r->min.x = Min(r->min.x + value, r->max.x); + Rect2 result = { + { minx, r->min.y}, + {r->min.x, r->max.y} + }; + return result; +} + +Rect2 CutRight(Rect2 *r, float value) { + float maxx = r->max.x; + r->max.x = Max(r->min.x, r->max.x - value); + Rect2 result = { + {r->max.x, r->min.y}, + { maxx, r->max.y}, + }; + return result; +} + +// Y is up +Rect2 CutBottom(Rect2 *r, float value) { + float maxy = r->max.y; + r->max.y = Max(r->min.y, r->max.y - value); + Rect2 result = { + {r->min.x, r->max.y}, + {r->max.x, maxy}, + }; + return result; +} + +// Y is up +Rect2 CutTop(Rect2 *r, float value) { + float miny = r->min.y; + r->min.y = Min(r->min.y + value, r->max.y); + Rect2 result = { + {r->min.x, miny}, + {r->max.x, r->min.y}, + }; + return result; +}