From 443e88b4a92e7b55677893585105c44cf5c6d998 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Sat, 22 Jun 2024 12:29:40 +0200 Subject: [PATCH] Extract font grid from raylib --- src/text_editor/main.cpp | 136 +++++++++++++++++++++------------------ 1 file changed, 74 insertions(+), 62 deletions(-) diff --git a/src/text_editor/main.cpp b/src/text_editor/main.cpp index 0995584..a7f0769 100644 --- a/src/text_editor/main.cpp +++ b/src/text_editor/main.cpp @@ -61,7 +61,7 @@ Rect2 GetScreenRectRenderUnits() { // Draw text using Font // NOTE: chars spacing is NOT proportional to fontSize -void DrawTextNew(Font font, String text, Vector2 position, float fontSize, float spacing, Color tint) { +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 float textOffsetX = 0.0f; // Offset X to next character to draw @@ -93,43 +93,46 @@ int main() { SetTargetFPS(60); InitArena(&FrameArena); - float font_size = 14; + float font_size = 25; float font_spacing = 1; - Font font = LoadFontEx("C:/Windows/Fonts/consola.ttf", (int)font_size, NULL, 250); - - Buffer 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); - } + Font font = LoadFontEx("C:/Windows/Fonts/times.ttf", (int)font_size, NULL, 250); Array windows = {}; windows.add({GetScreenRectRenderUnits()}); + { + Buffer *buffer = &windows[0].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); + } + } Vec2 camera_offset_world_to_render_units = {}; while (!WindowShouldClose()) { - if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) || IsKeyDown(KEY_SPACE)) { - camera_offset_world_to_render_units = Vector2Subtract(camera_offset_world_to_render_units, GetMouseDelta()); - } { Window *focused_window = &windows[0]; - float mouse_wheel = GetMouseWheelMove() * 48; - focused_window->window_world_to_window_units.y -= mouse_wheel; - focused_window->window_world_to_window_units.y = ClampBottom(focused_window->window_world_to_window_units.y, 0.f); - } - for (int c = GetCharPressed(); c; c = GetCharPressed()) { - String string = "?"; - UTF8Result utf8 = UTF32ToUTF8((uint32_t)c); - if (utf8.error == 0) { - string = {(char *)utf8.out_str, (int64_t)utf8.len}; + if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) || IsKeyDown(KEY_SPACE)) { + camera_offset_world_to_render_units = Vector2Subtract(camera_offset_world_to_render_units, GetMouseDelta()); } - Array edits = {FrameArena}; - AddEdit(&edits, {}, string); - ApplyEdits(&buffer, edits); + float mouse_wheel = GetMouseWheelMove() * 48; + focused_window->window_world_to_window_units.y -= mouse_wheel; + focused_window->window_world_to_window_units.y = ClampBottom(focused_window->window_world_to_window_units.y, 0.f); + + for (int c = GetCharPressed(); c; c = GetCharPressed()) { + String string = "?"; + UTF8Result utf8 = UTF32ToUTF8((uint32_t)c); + if (utf8.error == 0) { + string = {(char *)utf8.out_str, (int64_t)utf8.len}; + } + + Array edits = {FrameArena}; + AddEdit(&edits, {}, string); + ApplyEdits(&focused_window->buffer, edits); + } } BeginDrawing(); @@ -143,52 +146,61 @@ int main() { Rectangle rectangle_in_render_units = ToRectangle(window_rect_in_render_units); DrawRectangleRec(rectangle_in_render_units, WHITE); - // @todo: add window bar? - // { - // Vec2 text_position_in_window_units = {}; - // Vec2 text_position_in_world_units = WindowToWorldUnits(text_position_in_window_units, it); - // Vec2 text_position_in_render_units = WorldToRenderUnits(text_position_in_world_units, camera_offset_world_to_render_units); - // DrawTextEx(font, "window 1", text_position_in_render_units, font_size, font_spacing, BLACK); - // } - // // Line rendering // - { - // @todo: how do I implement the minimal drawing of text - // 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); + // @todo: how to constrain x? + // @optimize: I could clip to visible on screen window_rectangle but I couldn't get it right + 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; + float _line_max_y = (s.y + window.window_world_to_window_units.y) / line_offset; + int64_t line_min_y = (int64_t)floorf(_line_min_y); + int64_t line_max_y = (int64_t)ceilf(_line_max_y); - // @todo: x - 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; - float _line_max_y = (s.y + window.window_world_to_window_units.y) / line_offset; - 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); + for (int64_t line = line_min_y; line < line_max_y; line += 1) { + if (line < 0) break; + if (line >= window.buffer.lines.len) break; - 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); - for (int64_t line = line_min_y; line < line_max_y; line += 1) { - if (line < 0) break; - if (line >= buffer.lines.len) break; + Range line_range = window.buffer.lines[line]; - Range line_range = 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); - 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); + // + // 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;) { + int codepointByteCount = 0; + int codepoint = GetCodepointNext(&text.data[i], &codepointByteCount); + int index = GetGlyphIndex(font, codepoint); + GlyphInfo *glyph = font.glyphs + index; + Vec2 glyph_position = {text_position_in_render_units.x + textOffsetX, text_position_in_render_units.y}; - String string = GetString(buffer, line_range); - DrawTextNew(font, string, text_position_in_render_units, font_size, font_spacing, BLACK); + 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); + } + + textOffsetX += x_to_offset_by; + i += codepointByteCount; // Move text bytes counter to next codepoint } - EndScissorMode(); } + EndScissorMode(); } EndDrawing();