From 17fdf08a20a67b80d3b2d23fdf5ebdf570d7cfa5 Mon Sep 17 00:00:00 2001 From: OmniaX-Dev Date: Tue, 14 Apr 2026 06:46:31 +0200 Subject: [PATCH] Implemented batched text rendering --- extra/FreeSans.ttf | Bin 0 -> 264072 bytes extra/testTheme.txt | 7 +- other/TODO.txt | 5 + other/build.nr | 2 +- src/ogfx/gui/widgets/CheckBox.cpp | 2 + src/ogfx/render/BasicRenderer.cpp | 1243 +++++++++++++--------------- src/ogfx/render/BasicRenderer.hpp | 42 +- src/ogfx/render/FontGlyphAtlas.cpp | 175 ++-- src/ogfx/render/FontGlyphAtlas.hpp | 12 +- src/test/GuiTest.cpp | 177 +--- 10 files changed, 722 insertions(+), 943 deletions(-) create mode 100644 extra/FreeSans.ttf diff --git a/extra/FreeSans.ttf b/extra/FreeSans.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6de62ebf6718daed7c4eacc2ce45b9db67673b68 GIT binary patch literal 264072 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 Mb9-ZLZEcSIAA)mzIsgCw literal 0 HcmV?d00001 diff --git a/extra/testTheme.txt b/extra/testTheme.txt index 28d7ae9..57dc24b 100644 --- a/extra/testTheme.txt +++ b/extra/testTheme.txt @@ -5,7 +5,7 @@ $accentColor = Color(rgba(255, 0, 255, 255)) const $color2 = Color(#0000FFFF) % ------------------- -window.backgroundColor = Color(rgba(0, 0, 0, 255)) +window.backgroundColor = Color(rgba(160, 160, 160, 255)) $accentColor = Color(rgb(255, 0, 0)) @@ -13,7 +13,7 @@ $accentColor = Color(rgb(255, 0, 0)) textColor = $accentColor backgroundColor = Color(#000000FF) borderColor = $accentColor - fontSize = 50 + fontSize = 20 borderRadius = 0 borderWidth = 2 showBackground = true @@ -65,7 +65,7 @@ $accentColor = Color(rgb(255, 0, 0)) (@testLabel label) { textColor = $color2 backgroundColor = Color(#000000FF) - fontSize = 20 + fontSize = 50 } (@testLabel2 label) { @@ -108,7 +108,6 @@ $accentColor = Color(rgb(255, 0, 0)) (@label3 label) { textColor = $color2 backgroundColor = Color(#000000FF) - fontSize = 20 borderColor = Color(#FF0000FF) borderWidth = 4 borderRadius = 15 diff --git a/other/TODO.txt b/other/TODO.txt index 91db5f1..4fbae84 100644 --- a/other/TODO.txt +++ b/other/TODO.txt @@ -14,6 +14,11 @@ Add theme caching Implement callback for state changes in checkbox FIX: WindowOutputHandler text rendering find a way to add fixed update to gui::Window +Implement global scale (probably query desktop scale and adjust accordingly) +Fix: Text rendering bug in labels +Implement show/hide functionality for widgets +Implement wrappers in Renderer2D to take a center and size for rects + Implement following widgets: diff --git a/other/build.nr b/other/build.nr index 1113ea2..8c6e25c 100644 --- a/other/build.nr +++ b/other/build.nr @@ -1 +1 @@ -2060 +2061 diff --git a/src/ogfx/gui/widgets/CheckBox.cpp b/src/ogfx/gui/widgets/CheckBox.cpp index d5aedfa..5c52c3b 100644 --- a/src/ogfx/gui/widgets/CheckBox.cpp +++ b/src/ogfx/gui/widgets/CheckBox.cpp @@ -73,6 +73,8 @@ namespace ogfx void CheckBox::onMouseReleased(const Event& event) { + if (!isMouseInside()) + return; m_checked = !m_checked; setThemeQualifier("active", m_checked); } diff --git a/src/ogfx/render/BasicRenderer.cpp b/src/ogfx/render/BasicRenderer.cpp index c6925ec..7ab85f3 100644 --- a/src/ogfx/render/BasicRenderer.cpp +++ b/src/ogfx/render/BasicRenderer.cpp @@ -1,21 +1,21 @@ /* - OmniaFramework - A collection of useful functionality - Copyright (C) 2025 OmniaX-Dev + OmniaFramework - A collection of useful functionality + Copyright (C) 2025 OmniaX-Dev - This file is part of OmniaFramework. + This file is part of OmniaFramework. - OmniaFramework is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + OmniaFramework is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - OmniaFramework is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + OmniaFramework is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with OmniaFramework. If not, see . + You should have received a copy of the GNU General Public License + along with OmniaFramework. If not, see . */ #include "BasicRenderer.hpp" @@ -77,7 +77,7 @@ namespace ogfx void BasicRenderer2D::flushBatch(void) { if (!m_initialized || m_vertexCount == 0) - return; + return; SDL_RenderGeometry(m_window->getSDLRenderer(), m_texture, m_vertices.data(), m_vertexCount, m_indices.data(), m_indexCount); m_drawCallCount++; m_texture = nullptr; @@ -95,22 +95,22 @@ namespace ogfx { if (!m_initialized) return; - ostd::Rectangle finalRect = rect; + ostd::Rectangle finalRect = rect; - if (additive && !m_clipStack.empty()) - finalRect = m_clipStack.back().getIntersection(rect, false); + if (additive && !m_clipStack.empty()) + finalRect = m_clipStack.back().getIntersection(rect, false); if (!m_clipStack.empty() && m_clipStack.back() == finalRect) return; flushBatch(); - m_clipStack.push_back(finalRect); + m_clipStack.push_back(finalRect); - SDL_Rect r; - r.x = (int)std::round(finalRect.x); - r.y = (int)std::round(finalRect.y); - r.w = (int)std::round(finalRect.w); - r.h = (int)std::round(finalRect.h); + SDL_Rect r; + r.x = (int)std::round(finalRect.x); + r.y = (int)std::round(finalRect.y); + r.w = (int)std::round(finalRect.w); + r.h = (int)std::round(finalRect.h); SDL_SetRenderClipRect(m_window->getSDLRenderer(), &r); } @@ -118,26 +118,26 @@ namespace ogfx void BasicRenderer2D::popClippingRect(void) { if (!m_initialized) return; - if (m_clipStack.empty()) return; + if (m_clipStack.empty()) return; - m_clipStack.pop_back(); + m_clipStack.pop_back(); flushBatch(); - if (m_clipStack.empty()) - { - SDL_SetRenderClipRect(m_window->getSDLRenderer(), nullptr); - return; - } + if (m_clipStack.empty()) + { + SDL_SetRenderClipRect(m_window->getSDLRenderer(), nullptr); + return; + } - const auto& rect = m_clipStack.back(); + const auto& rect = m_clipStack.back(); - SDL_Rect r; - r.x = (int)std::round(rect.x); - r.y = (int)std::round(rect.y); - r.w = (int)std::round(rect.w); - r.h = (int)std::round(rect.h); + SDL_Rect r; + r.x = (int)std::round(rect.x); + r.y = (int)std::round(rect.y); + r.w = (int)std::round(rect.w); + r.h = (int)std::round(rect.h); - SDL_SetRenderClipRect(m_window->getSDLRenderer(), &r); + SDL_SetRenderClipRect(m_window->getSDLRenderer(), &r); } int32_t BasicRenderer2D::loadDefaultFont(int32_t fontSize) @@ -211,44 +211,30 @@ namespace ogfx return set_error_state(tErrors::NoError); } - ostd::IPoint BasicRenderer2D::getStringDimensions(const ostd::String& message, int32_t fontSize) + ostd::Vec2 BasicRenderer2D::getStringDimensions(const ostd::String& message, int32_t fontSize, TTF_Font* font) { - if (!m_initialized) - { - set_error_state(tErrors::Uninitialized); - return { 0, 0 }; - } - if (!m_fontOpen) - { - set_error_state(tErrors::NoFont); - return { 0, 0 }; - } - if (m_font == nullptr) - { - set_error_state(tErrors::NullFont); - return { 0, 0 }; - } - setFontSize(fontSize); - SDL_Surface* surf = TTF_RenderText_Blended(m_font, message.c_str(), message.len(), { 0, 0, 0, 255 }); - if (surf == nullptr) - { - set_error_state(tErrors::TTFRenderTextBlendedFail); - print_ttf_error("TTF_RenderText_Blended"); - return { 0, 0 }; - } - SDL_Texture* texture = SDL_CreateTextureFromSurface(m_window->getSDLRenderer(), surf); - if (texture == nullptr) - { - set_error_state(tErrors::TTFCreateTextureFromSurfaceFail); - print_ttf_error("SDL_CreateTextureFromSurface"); - return { 0, 0 }; - } - SDL_DestroySurface(surf); + if (!isValid()) return { 0, 0 }; + if (fontSize <= 0) fontSize = m_fontSize; + if (!font) font = m_font; + int32_t oldFontSize = getFontSize(); + setFontSize(fontSize); - float w = 0, h = 0; - SDL_GetTextureSize(texture, &w, &h); - SDL_DestroyTexture(texture); - return { static_cast(w), static_cast(h) }; + auto glyphs = m_fontGlyphAtlas.processString(message, font, fontSize); + if (glyphs.empty()) return { 0, 0 }; + + float totalWidth = 0; + for (size_t i = 0; i < glyphs.size(); i++) + { + totalWidth += glyphs[i]->advance; + if (i > 0) + { + int kern = 0; + TTF_GetGlyphKerning(font, glyphs[i - 1]->codepoint, glyphs[i]->codepoint, &kern); + totalWidth += kern; + } + } + setFontSize(oldFontSize); + return { totalWidth, glyphs[0]->size.y }; } // ===================================================== UTILS ===================================================== @@ -257,83 +243,122 @@ namespace ogfx // ===================================================== SPECIALIZED ===================================================== - void BasicRenderer2D::drawImage(const ogfx::Image& image, const ostd::Vec2& position, const ostd::Vec2& size, const ostd::Rectangle& srcRect) - { - if (!m_initialized || !image.isLoaded()) - return; - - SDL_Texture* tex = image.getSDLTexture(); - if (!tex) - return; - - ostd::Vec2 texSize = image.getSize(); - - // 1. Resolve source rectangle - float sx, sy, sw, sh; - if (srcRect.w == 0 && srcRect.h == 0) - { - // Use entire texture - sx = 0.0f; - sy = 0.0f; - sw = texSize.x; - sh = texSize.y; - } - else - { - sx = srcRect.x; - sy = srcRect.y; - sw = srcRect.w; - sh = srcRect.h; - } - - // 2. Resolve destination rectangle - float dx = position.x; - float dy = position.y; - float dw = (size.x == 0) ? sw : size.x; - float dh = (size.y == 0) ? sh : size.y; - float x1 = dx; - float y1 = dy; - float x2 = dx + dw; - float y2 = dy + dh; - - // 3. Build quad vertices - ostd::Vec2 verts[4] = { - { x1, y1 }, - { x2, y1 }, - { x2, y2 }, - { x1, y2 } - }; - - // 4. Build UVs (normalized) - ostd::Vec2 uvs[4] = { - { sx / texSize.x, sy / texSize.y }, - { (sx + sw) / texSize.x, sy / texSize.y }, - { (sx + sw) / texSize.x, (sy + sh) / texSize.y }, - { sx / texSize.x, (sy + sh) / texSize.y } - }; - - // 5. Push quad - uint32_t inds[6] = QUAD_INDICES_ARR; - push_polygon(verts, uvs, 4, inds, 6, ostd::Colors::White, tex); - } - - void BasicRenderer2D::drawAnimation(const Animation& anim, const ostd::Vec2& position, const ostd::Vec2& size) - { - if (!m_initialized) return; - if (!anim.hasImage()) return; - const Image& img = anim.getSpriteSheet(); - if (!img.isLoaded() || !img.isValid()) return; - drawImage(img, position, size, anim.getFrameRect()); - } - - void BasicRenderer2D::drawString(const ostd::String& str, const ostd::Vec2& position, const ostd::Color& color, int32_t fontSize) + void BasicRenderer2D::drawImage(const ogfx::Image& image, const ostd::Vec2& position, const ostd::Vec2& size, const ostd::Rectangle& srcRect) { - if (!m_initialized) return; + if (!m_initialized || !image.isLoaded()) + return; + + SDL_Texture* tex = image.getSDLTexture(); + if (!tex) + return; + + ostd::Vec2 texSize = image.getSize(); + + // 1. Resolve source rectangle + float sx, sy, sw, sh; + if (srcRect.w == 0 && srcRect.h == 0) + { + // Use entire texture + sx = 0.0f; + sy = 0.0f; + sw = texSize.x; + sh = texSize.y; + } + else + { + sx = srcRect.x; + sy = srcRect.y; + sw = srcRect.w; + sh = srcRect.h; + } + + // 2. Resolve destination rectangle + float dx = position.x; + float dy = position.y; + float dw = (size.x == 0) ? sw : size.x; + float dh = (size.y == 0) ? sh : size.y; + float x1 = dx; + float y1 = dy; + float x2 = dx + dw; + float y2 = dy + dh; + + // 3. Build quad vertices + ostd::Vec2 verts[4] = { + { x1, y1 }, + { x2, y1 }, + { x2, y2 }, + { x1, y2 } + }; + + // 4. Build UVs (normalized) + ostd::Vec2 uvs[4] = { + { sx / texSize.x, sy / texSize.y }, + { (sx + sw) / texSize.x, sy / texSize.y }, + { (sx + sw) / texSize.x, (sy + sh) / texSize.y }, + { sx / texSize.x, (sy + sh) / texSize.y } + }; + + // 5. Push quad + uint32_t inds[6] = QUAD_INDICES_ARR; + push_polygon(verts, uvs, 4, inds, 6, ostd::Colors::White, tex); } - void BasicRenderer2D::drawCenteredString(const ostd::String& str, const ostd::Vec2& center, const ostd::Color& color, int32_t fontSize) + void BasicRenderer2D::drawAnimation(const Animation& anim, const ostd::Vec2& position, const ostd::Vec2& size) { if (!m_initialized) return; + if (!anim.hasImage()) return; + const Image& img = anim.getSpriteSheet(); + if (!img.isLoaded() || !img.isValid()) return; + drawImage(img, position, size, anim.getFrameRect()); + } + + void BasicRenderer2D::drawString(const ostd::String& str, const ostd::Vec2& position, const ostd::Color& color, int32_t fontSize, float scale) + { + if (!isValid()) return; + if (fontSize <= 0) + fontSize = m_fontSize; + setFontSize(fontSize); + + auto glyphs = m_fontGlyphAtlas.processString(str, m_font, fontSize); + if (glyphs.empty()) return; + + float x = position.x; + float y = position.y; + + + for (size_t i = 0; i < glyphs.size(); i++) + { + auto& g = glyphs[i]; + + if (i > 0) + { + int kern = 0; + TTF_GetGlyphKerning(m_font, glyphs[i - 1]->codepoint, g->codepoint, &kern); + x += (kern * scale); + } + + ostd::Vec2 verts[4] = { + { x, y }, + { x + g->size.x * scale, y }, + { x + g->size.x * scale, y + g->size.y * scale }, + { x, y + g->size.y * scale } + }; + uint32_t inds[6] = QUAD_INDICES_ARR; + push_polygon(verts, g->uvs, 4, inds, 6, color, g->atlas); + + x += (g->advance * scale); + } + } + + void BasicRenderer2D::drawCenteredString(const ostd::String& str, const ostd::Vec2& center, const ostd::Color& color, int32_t fontSize, float scale) + { + auto dims = getStringDimensions(str, fontSize); + drawString(str, { center.x - (dims.x * scale) * 0.5f, center.y - (dims.y * scale) * 0.5f }, color, fontSize, scale); + } + + void BasicRenderer2D::drawCenteredString(const ostd::String& str, const ostd::Rectangle& bounds, const ostd::Color& color, int32_t fontSize, float scale) + { + drawCenteredString(str, ostd::Vec2 { bounds.x + bounds.w * 0.5f, bounds.y + bounds.h * 0.5f }, color, fontSize, scale); } // ===================================================== SPECIALIZED ===================================================== @@ -357,7 +382,7 @@ namespace ogfx Vec2 off = perp * half; std::array verts = {{ - p1 - off, + p1 - off, p1 + off, p2 + off, p2 - off @@ -366,248 +391,248 @@ namespace ogfx push_polygon(verts.data(), nullptr, 4, inds.data(), 6, color, nullptr); - if (!rounded || thickness < 4) - return; + if (!rounded || thickness < 4) + return; int segments = std::max(6, int(thickness * 0.75f)); - generate_half_circle(p1, -dir, half, segments, color); - generate_half_circle(p2, dir, half, segments, color); + generate_half_circle(p1, -dir, half, segments, color); + generate_half_circle(p2, dir, half, segments, color); } void BasicRenderer2D::drawRect(const ostd::Rectangle& rect, const ostd::Color& color, int32_t thickness) { if (!m_initialized || thickness <= 0) - return; + return; - float half = thickness * 0.5f; + float half = thickness * 0.5f; - // Inset rectangle so the outline stays inside the original bounds - float x1 = rect.x + half; - float y1 = rect.y + half; - float x2 = rect.x + rect.w - half; - float y2 = rect.y + rect.h - half; + // Inset rectangle so the outline stays inside the original bounds + float x1 = rect.x + half; + float y1 = rect.y + half; + float x2 = rect.x + rect.w - half; + float y2 = rect.y + rect.h - half; - // Top - drawLine({ {x1, y1}, {x2, y1} }, color, thickness, false); + // Top + drawLine({ {x1, y1}, {x2, y1} }, color, thickness, false); - // Right - drawLine({ {x2, y1 - half}, {x2, y2 + half} }, color, thickness, false); + // Right + drawLine({ {x2, y1 - half}, {x2, y2 + half} }, color, thickness, false); - // Bottom - drawLine({ {x2, y2}, {x1, y2} }, color, thickness, false); + // Bottom + drawLine({ {x2, y2}, {x1, y2} }, color, thickness, false); - // Left - drawLine({ {x1, y2 + half}, {x1, y1 - half} }, color, thickness, false); + // Left + drawLine({ {x1, y2 + half}, {x1, y1 - half} }, color, thickness, false); } void BasicRenderer2D::drawRoundRect(const ostd::Rectangle& rect, const ostd::Color& color, float radius, int32_t thickness) { if (!m_initialized || thickness <= 0) - return; + return; - // Clamp radius so it never exceeds half the smallest dimension - radius = std::max(0.0f, std::min(radius, std::min(rect.w, rect.h) * 0.5f)); + // Clamp radius so it never exceeds half the smallest dimension + radius = std::max(0.0f, std::min(radius, std::min(rect.w, rect.h) * 0.5f)); - float half = thickness * 0.5f; + float half = thickness * 0.5f; - // Inset rectangle so the border stays INSIDE the given bounds - float x1 = rect.x + half; - float y1 = rect.y + half; - float x2 = rect.x + rect.w - half; - float y2 = rect.y + rect.h - half; + // Inset rectangle so the border stays INSIDE the given bounds + float x1 = rect.x + half; + float y1 = rect.y + half; + float x2 = rect.x + rect.w - half; + float y2 = rect.y + rect.h - half; - // Corner centers - ostd::Vec2 TL { x1 + radius, y1 + radius }; - ostd::Vec2 TR { x2 - radius, y1 + radius }; - ostd::Vec2 BR { x2 - radius, y2 - radius }; - ostd::Vec2 BL { x1 + radius, y2 - radius }; + // Corner centers + ostd::Vec2 TL { x1 + radius, y1 + radius }; + ostd::Vec2 TR { x2 - radius, y1 + radius }; + ostd::Vec2 BR { x2 - radius, y2 - radius }; + ostd::Vec2 BL { x1 + radius, y2 - radius }; - // Straight edges (shortened to meet the arcs cleanly) - drawLine({ {x1 + radius, y1}, {x2 - radius, y1} }, color, thickness, false); // top - drawLine({ {x2, y1 + radius}, {x2, y2 - radius} }, color, thickness, false); // right - drawLine({ {x2 - radius, y2}, {x1 + radius, y2} }, color, thickness, false); // bottom - drawLine({ {x1, y2 - radius}, {x1, y1 + radius} }, color, thickness, false); // left + // Straight edges (shortened to meet the arcs cleanly) + drawLine({ {x1 + radius, y1}, {x2 - radius, y1} }, color, thickness, false); // top + drawLine({ {x2, y1 + radius}, {x2, y2 - radius} }, color, thickness, false); // right + drawLine({ {x2 - radius, y2}, {x1 + radius, y2} }, color, thickness, false); // bottom + drawLine({ {x1, y2 - radius}, {x1, y1 + radius} }, color, thickness, false); // left - // Number of segments for smooth arcs - int segments = std::max(6, int(radius * 0.75f)); + // Number of segments for smooth arcs + int segments = std::max(6, int(radius * 0.75f)); - // Quarter‑ellipse strokes (each is 90°) - generate_ellipse_stroke(TL, radius, radius, thickness, M_PI, M_PI + M_PI * 0.5f, color, segments); // TL - generate_ellipse_stroke(TR, radius, radius, thickness, 1.5f * M_PI, 2.0f * M_PI, color, segments); // TR - generate_ellipse_stroke(BR, radius, radius, thickness, 0.0f, M_PI * 0.5f, color, segments); // BR - generate_ellipse_stroke(BL, radius, radius, thickness, M_PI * 0.5f, M_PI, color, segments); // BL + // Quarter‑ellipse strokes (each is 90°) + generate_ellipse_stroke(TL, radius, radius, thickness, M_PI, M_PI + M_PI * 0.5f, color, segments); // TL + generate_ellipse_stroke(TR, radius, radius, thickness, 1.5f * M_PI, 2.0f * M_PI, color, segments); // TR + generate_ellipse_stroke(BR, radius, radius, thickness, 0.0f, M_PI * 0.5f, color, segments); // BR + generate_ellipse_stroke(BL, radius, radius, thickness, M_PI * 0.5f, M_PI, color, segments); // BL } void BasicRenderer2D::drawCircle(const ostd::Vec2& center, float radius, const ostd::Color& color, int32_t thickness) { if (!m_initialized || thickness <= 0) - return; - int segments = std::max(12, int(radius * 0.75f)); - generate_ellipse_stroke(center, radius, radius, thickness, 0.0f, 2.0f * M_PI, color, segments); + return; + int segments = std::max(12, int(radius * 0.75f)); + generate_ellipse_stroke(center, radius, radius, thickness, 0.0f, 2.0f * M_PI, color, segments); } void BasicRenderer2D::drawCircle(const ostd::Rectangle& rect, const ostd::Color& color, int32_t thickness) { - if (!m_initialized || thickness <= 0) - return; + if (!m_initialized || thickness <= 0) + return; - ostd::Vec2 center { - rect.x + rect.w * 0.5f, - rect.y + rect.h * 0.5f - }; + ostd::Vec2 center { + rect.x + rect.w * 0.5f, + rect.y + rect.h * 0.5f + }; - float radius = std::min(rect.w, rect.h) * 0.5f; - drawCircle(center, radius, color, thickness); + float radius = std::min(rect.w, rect.h) * 0.5f; + drawCircle(center, radius, color, thickness); } void BasicRenderer2D::drawEllipse(const ostd::Rectangle& rect, const ostd::Color& color, int32_t thickness) { if (!m_initialized || thickness <= 0) - return; + return; ostd::Vec2 center = { rect.x + rect.w*0.5f, rect.y + rect.h*0.5f }; - float rx = rect.w * 0.5f; - float ry = rect.h * 0.5f; + float rx = rect.w * 0.5f; + float ry = rect.h * 0.5f; - int segments = std::max(12, int(std::max(rx, ry) * 0.75f)); - generate_ellipse_stroke(center, rx, ry, thickness, 0.0f, 2.0f * M_PI, color, segments); + int segments = std::max(12, int(std::max(rx, ry) * 0.75f)); + generate_ellipse_stroke(center, rx, ry, thickness, 0.0f, 2.0f * M_PI, color, segments); } void BasicRenderer2D::fillRect(const ostd::Rectangle& rect, const ostd::Color& color) { if (!m_initialized) - return; + return; - float x1 = rect.x; - float y1 = rect.y; - float x2 = rect.x + rect.w; - float y2 = rect.y + rect.h; + float x1 = rect.x; + float y1 = rect.y; + float x2 = rect.x + rect.w; + float y2 = rect.y + rect.h; - ostd::Vec2 verts[4] = { - { x1, y1 }, - { x2, y1 }, - { x2, y2 }, - { x1, y2 } - }; - uint32_t inds[6] = QUAD_INDICES_ARR; - push_polygon(verts, nullptr, 4, inds, 6, color, nullptr); + ostd::Vec2 verts[4] = { + { x1, y1 }, + { x2, y1 }, + { x2, y2 }, + { x1, y2 } + }; + uint32_t inds[6] = QUAD_INDICES_ARR; + push_polygon(verts, nullptr, 4, inds, 6, color, nullptr); } void BasicRenderer2D::fillRoundRect(const ostd::Rectangle& rect, const ostd::Color& color, float radius) { if (!m_initialized) - return; + return; - // Clamp radius - radius = std::max(0.0f, std::min(radius, std::min(rect.w, rect.h) * 0.5f)); + // Clamp radius + radius = std::max(0.0f, std::min(radius, std::min(rect.w, rect.h) * 0.5f)); - float x1 = rect.x; - float y1 = rect.y; - float x2 = rect.x + rect.w; - float y2 = rect.y + rect.h; + float x1 = rect.x; + float y1 = rect.y; + float x2 = rect.x + rect.w; + float y2 = rect.y + rect.h; - float cx1 = x1 + radius; - float cy1 = y1 + radius; - float cx2 = x2 - radius; - float cy2 = y2 - radius; + float cx1 = x1 + radius; + float cy1 = y1 + radius; + float cx2 = x2 - radius; + float cy2 = y2 - radius; - // Number of segments for smooth corners - int segments = std::max(6, int(radius * 0.75f)); + // Number of segments for smooth corners + int segments = std::max(6, int(radius * 0.75f)); - // - // 1. Fill the center rectangle - // - { - ostd::Vec2 verts[4] = { - { cx1, cy1 }, - { cx2, cy1 }, - { cx2, cy2 }, - { cx1, cy2 } - }; - uint32_t inds[6] = { 0,1,2, 2,3,0 }; - push_polygon(verts, nullptr, 4, inds, 6, color, nullptr); - } + // + // 1. Fill the center rectangle + // + { + ostd::Vec2 verts[4] = { + { cx1, cy1 }, + { cx2, cy1 }, + { cx2, cy2 }, + { cx1, cy2 } + }; + uint32_t inds[6] = { 0,1,2, 2,3,0 }; + push_polygon(verts, nullptr, 4, inds, 6, color, nullptr); + } - // - // 2. Fill the four side rectangles - // + // + // 2. Fill the four side rectangles + // - // Top - if (radius > 0) - { - ostd::Vec2 verts[4] = { - { x1 + radius, y1 }, - { x2 - radius, y1 }, - { x2 - radius, y1 + radius }, - { x1 + radius, y1 + radius } - }; - uint32_t inds[6] = { 0,1,2, 2,3,0 }; - push_polygon(verts, nullptr, 4, inds, 6, color, nullptr); - } + // Top + if (radius > 0) + { + ostd::Vec2 verts[4] = { + { x1 + radius, y1 }, + { x2 - radius, y1 }, + { x2 - radius, y1 + radius }, + { x1 + radius, y1 + radius } + }; + uint32_t inds[6] = { 0,1,2, 2,3,0 }; + push_polygon(verts, nullptr, 4, inds, 6, color, nullptr); + } - // Bottom - { - ostd::Vec2 verts[4] = { - { x1 + radius, y2 - radius }, - { x2 - radius, y2 - radius }, - { x2 - radius, y2 }, - { x1 + radius, y2 } - }; - uint32_t inds[6] = { 0,1,2, 2,3,0 }; - push_polygon(verts, nullptr, 4, inds, 6, color, nullptr); - } + // Bottom + { + ostd::Vec2 verts[4] = { + { x1 + radius, y2 - radius }, + { x2 - radius, y2 - radius }, + { x2 - radius, y2 }, + { x1 + radius, y2 } + }; + uint32_t inds[6] = { 0,1,2, 2,3,0 }; + push_polygon(verts, nullptr, 4, inds, 6, color, nullptr); + } - // Left - { - ostd::Vec2 verts[4] = { - { x1, y1 + radius }, - { x1 + radius, y1 + radius }, - { x1 + radius, y2 - radius }, - { x1, y2 - radius } - }; - uint32_t inds[6] = { 0,1,2, 2,3,0 }; - push_polygon(verts, nullptr, 4, inds, 6, color, nullptr); - } + // Left + { + ostd::Vec2 verts[4] = { + { x1, y1 + radius }, + { x1 + radius, y1 + radius }, + { x1 + radius, y2 - radius }, + { x1, y2 - radius } + }; + uint32_t inds[6] = { 0,1,2, 2,3,0 }; + push_polygon(verts, nullptr, 4, inds, 6, color, nullptr); + } - // Right - { - ostd::Vec2 verts[4] = { - { x2 - radius, y1 + radius }, - { x2, y1 + radius }, - { x2, y2 - radius }, - { x2 - radius, y2 - radius } - }; - uint32_t inds[6] = { 0,1,2, 2,3,0 }; - push_polygon(verts, nullptr, 4, inds, 6, color, nullptr); - } + // Right + { + ostd::Vec2 verts[4] = { + { x2 - radius, y1 + radius }, + { x2, y1 + radius }, + { x2, y2 - radius }, + { x2 - radius, y2 - radius } + }; + uint32_t inds[6] = { 0,1,2, 2,3,0 }; + push_polygon(verts, nullptr, 4, inds, 6, color, nullptr); + } - // - // 3. Fill the four rounded corners (quarter ellipses) - // + // + // 3. Fill the four rounded corners (quarter ellipses) + // - generate_filled_ellipse_stroke({cx1, cy1}, radius, radius, M_PI, color, segments); // TL - generate_filled_ellipse_stroke({cx2, cy1}, radius, radius, 1.5f * M_PI, color, segments); // TR - generate_filled_ellipse_stroke({cx2, cy2}, radius, radius, 0.0f, color, segments); // BR - generate_filled_ellipse_stroke({cx1, cy2}, radius, radius, 0.5f * M_PI, color, segments); // BL + generate_filled_ellipse_stroke({cx1, cy1}, radius, radius, M_PI, color, segments); // TL + generate_filled_ellipse_stroke({cx2, cy1}, radius, radius, 1.5f * M_PI, color, segments); // TR + generate_filled_ellipse_stroke({cx2, cy2}, radius, radius, 0.0f, color, segments); // BR + generate_filled_ellipse_stroke({cx1, cy2}, radius, radius, 0.5f * M_PI, color, segments); // BL } void BasicRenderer2D::fillCircle(const ostd::Vec2& center, float radius, const ostd::Color& color) { if (!m_initialized) - return; + return; - int segments = std::max(12, int(radius * 0.75f)); - generate_filled_ellipse(center, radius, radius, color, segments); + int segments = std::max(12, int(radius * 0.75f)); + generate_filled_ellipse(center, radius, radius, color, segments); } void BasicRenderer2D::fillCircle(const ostd::Rectangle& rect, const ostd::Color& color) { if (!m_initialized) - return; + return; ostd::Vec2 center { - rect.x + rect.w * 0.5f, - rect.y + rect.h * 0.5f + rect.x + rect.w * 0.5f, + rect.y + rect.h * 0.5f }; float radius = std::min(rect.w, rect.h) * 0.5f; @@ -617,18 +642,18 @@ namespace ogfx void BasicRenderer2D::fillEllipse(const ostd::Rectangle& rect, const ostd::Color& color) { if (!m_initialized) - return; + return; - ostd::Vec2 center { - rect.x + rect.w * 0.5f, - rect.y + rect.h * 0.5f - }; + ostd::Vec2 center { + rect.x + rect.w * 0.5f, + rect.y + rect.h * 0.5f + }; - float radiusX = rect.w * 0.5f; - float radiusY = rect.h * 0.5f; + float radiusX = rect.w * 0.5f; + float radiusY = rect.h * 0.5f; - int segments = std::max(12, int(std::max(radiusX, radiusY) * 0.75f)); - generate_filled_ellipse(center, radiusX, radiusY, color, segments); + int segments = std::max(12, int(std::max(radiusX, radiusY) * 0.75f)); + generate_filled_ellipse(center, radiusX, radiusY, color, segments); } void BasicRenderer2D::outlinedRect(const ostd::Rectangle& rect, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t outlineThickness) @@ -657,11 +682,11 @@ namespace ogfx void BasicRenderer2D::outlinedCircle(const ostd::Rectangle& rect, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t outlineThickness) { if (!m_initialized) - return; + return; ostd::Vec2 center { - rect.x + rect.w * 0.5f, - rect.y + rect.h * 0.5f + rect.x + rect.w * 0.5f, + rect.y + rect.h * 0.5f }; float radius = std::min(rect.w, rect.h) * 0.5f; @@ -696,52 +721,52 @@ namespace ogfx void BasicRenderer2D::generate_half_circle(const ostd::Vec2& center, const ostd::Vec2& dir, float radius, int segments, const ostd::Color& color) { - // Ensure we have room - if (m_vertexCount + segments + 2 >= MaxVertices || m_indexCount + segments * 3 >= MaxIndices) - flushBatch(); + // Ensure we have room + if (m_vertexCount + segments + 2 >= MaxVertices || m_indexCount + segments * 3 >= MaxIndices) + flushBatch(); - SDL_FColor col = COLOR_CAST(color); + SDL_FColor col = COLOR_CAST(color); - // Index of the center vertex - int centerIndex = m_vertexCount; + // Index of the center vertex + int centerIndex = m_vertexCount; - // Push center vertex - m_vertices[m_vertexCount++] = { - { center.x, center.y }, - col, - { 0.0f, 0.0f }, - }; + // Push center vertex + m_vertices[m_vertexCount++] = { + { center.x, center.y }, + col, + { 0.0f, 0.0f }, + }; - // Compute the base angle from the direction vector - float baseAngle = std::atan2(dir.y, dir.x); + // Compute the base angle from the direction vector + float baseAngle = std::atan2(dir.y, dir.x); - // Half circle spans 180 degrees - float startAngle = baseAngle - M_PI * 0.5f; - float endAngle = baseAngle + M_PI * 0.5f; + // Half circle spans 180 degrees + float startAngle = baseAngle - M_PI * 0.5f; + float endAngle = baseAngle + M_PI * 0.5f; - // Generate arc vertices - for (int i = 0; i <= segments; i++) - { - float t = float(i) / float(segments); - float angle = startAngle + t * (endAngle - startAngle); + // Generate arc vertices + for (int i = 0; i <= segments; i++) + { + float t = float(i) / float(segments); + float angle = startAngle + t * (endAngle - startAngle); - float x = center.x + std::cos(angle) * radius; - float y = center.y + std::sin(angle) * radius; + float x = center.x + std::cos(angle) * radius; + float y = center.y + std::sin(angle) * radius; - m_vertices[m_vertexCount++] = { - { x, y }, - col, - { 0.0f, 0.0f } - }; - } + m_vertices[m_vertexCount++] = { + { x, y }, + col, + { 0.0f, 0.0f } + }; + } - // Generate triangle fan indices - for (int i = 0; i < segments; i++) - { - m_indices[m_indexCount++] = centerIndex; - m_indices[m_indexCount++] = centerIndex + 1 + i; - m_indices[m_indexCount++] = centerIndex + 2 + i; - } + // Generate triangle fan indices + for (int i = 0; i < segments; i++) + { + m_indices[m_indexCount++] = centerIndex; + m_indices[m_indexCount++] = centerIndex + 1 + i; + m_indices[m_indexCount++] = centerIndex + 2 + i; + } } void BasicRenderer2D::generate_quarter_circle(const ostd::Vec2& center, float radius, float thickness, float startAngle, const ostd::Color& color, int segments) @@ -752,11 +777,11 @@ namespace ogfx float innerR = radius - half; if (innerR < 0.0f) - innerR = 0.0f; + innerR = 0.0f; // Ensure capacity if (m_vertexCount + (segments + 1) * 2 >= MaxVertices || m_indexCount + segments * 6 >= MaxIndices) - flushBatch(); + flushBatch(); SDL_FColor col = COLOR_CAST(color); @@ -767,263 +792,263 @@ namespace ogfx // Generate vertices: outer arc + inner arc for (int i = 0; i <= segments; i++) { - float t = float(i) / float(segments); - float angle = startAngle + t * (endAngle - startAngle); + float t = float(i) / float(segments); + float angle = startAngle + t * (endAngle - startAngle); - float cs = std::cos(angle); - float sn = std::sin(angle); + float cs = std::cos(angle); + float sn = std::sin(angle); - // Outer arc - m_vertices[m_vertexCount++] = { - { center.x + cs * outerR, center.y + sn * outerR }, - col, - { 0, 0 } - }; + // Outer arc + m_vertices[m_vertexCount++] = { + { center.x + cs * outerR, center.y + sn * outerR }, + col, + { 0, 0 } + }; - // Inner arc - m_vertices[m_vertexCount++] = { - { center.x + cs * innerR, center.y + sn * innerR }, - col, - { 0, 0 } - }; + // Inner arc + m_vertices[m_vertexCount++] = { + { center.x + cs * innerR, center.y + sn * innerR }, + col, + { 0, 0 } + }; } // Generate indices (triangle strip converted to triangles) for (int i = 0; i < segments; i++) { - int o0 = base + i * 2; - int i0 = o0 + 1; - int o1 = o0 + 2; - int i1 = o0 + 3; + int o0 = base + i * 2; + int i0 = o0 + 1; + int o1 = o0 + 2; + int i1 = o0 + 3; - // Triangle 1 - m_indices[m_indexCount++] = o0; - m_indices[m_indexCount++] = o1; - m_indices[m_indexCount++] = i0; + // Triangle 1 + m_indices[m_indexCount++] = o0; + m_indices[m_indexCount++] = o1; + m_indices[m_indexCount++] = i0; - // Triangle 2 - m_indices[m_indexCount++] = o1; - m_indices[m_indexCount++] = i1; - m_indices[m_indexCount++] = i0; + // Triangle 2 + m_indices[m_indexCount++] = o1; + m_indices[m_indexCount++] = i1; + m_indices[m_indexCount++] = i0; } } void BasicRenderer2D::generate_circle_stroke(const ostd::Vec2& center, float radius, float thickness, const ostd::Color& color, int segments) { - float half = thickness * 0.5f; + float half = thickness * 0.5f; - float outerR = radius + half; - float innerR = radius - half; - if (innerR < 0.0f) - innerR = 0.0f; + float outerR = radius + half; + float innerR = radius - half; + if (innerR < 0.0f) + innerR = 0.0f; - // Ensure capacity - if (m_vertexCount + (segments + 1) * 2 >= MaxVertices || m_indexCount + segments * 6 >= MaxIndices) - flushBatch(); + // Ensure capacity + if (m_vertexCount + (segments + 1) * 2 >= MaxVertices || m_indexCount + segments * 6 >= MaxIndices) + flushBatch(); - SDL_FColor col = COLOR_CAST(color); + SDL_FColor col = COLOR_CAST(color); - int base = m_vertexCount; + int base = m_vertexCount; - // Generate vertices: outer arc + inner arc - for (int i = 0; i <= segments; i++) - { - float t = float(i) / float(segments); - float angle = t * (2.0f * M_PI); + // Generate vertices: outer arc + inner arc + for (int i = 0; i <= segments; i++) + { + float t = float(i) / float(segments); + float angle = t * (2.0f * M_PI); - float cs = std::cos(angle); - float sn = std::sin(angle); + float cs = std::cos(angle); + float sn = std::sin(angle); - // Outer arc - m_vertices[m_vertexCount++] = { - { center.x + cs * outerR, center.y + sn * outerR }, - col, - { 0, 0 } - }; + // Outer arc + m_vertices[m_vertexCount++] = { + { center.x + cs * outerR, center.y + sn * outerR }, + col, + { 0, 0 } + }; - // Inner arc - m_vertices[m_vertexCount++] = { - { center.x + cs * innerR, center.y + sn * innerR }, - col, - { 0, 0 } - }; - } + // Inner arc + m_vertices[m_vertexCount++] = { + { center.x + cs * innerR, center.y + sn * innerR }, + col, + { 0, 0 } + }; + } - // Generate indices (triangle strip → triangles) - for (int i = 0; i < segments; i++) - { - int o0 = base + i * 2; - int i0 = o0 + 1; - int o1 = o0 + 2; - int i1 = o0 + 3; + // Generate indices (triangle strip → triangles) + for (int i = 0; i < segments; i++) + { + int o0 = base + i * 2; + int i0 = o0 + 1; + int o1 = o0 + 2; + int i1 = o0 + 3; - // Triangle 1 - m_indices[m_indexCount++] = o0; - m_indices[m_indexCount++] = o1; - m_indices[m_indexCount++] = i0; + // Triangle 1 + m_indices[m_indexCount++] = o0; + m_indices[m_indexCount++] = o1; + m_indices[m_indexCount++] = i0; - // Triangle 2 - m_indices[m_indexCount++] = o1; - m_indices[m_indexCount++] = i1; - m_indices[m_indexCount++] = i0; - } + // Triangle 2 + m_indices[m_indexCount++] = o1; + m_indices[m_indexCount++] = i1; + m_indices[m_indexCount++] = i0; + } } void BasicRenderer2D::generate_ellipse_stroke(const ostd::Vec2& center, float radiusX, float radiusY, float thickness, float startAngle, float endAngle, const ostd::Color& color, int segments) { - float half = thickness * 0.5f; + float half = thickness * 0.5f; - float outerRX = radiusX + half; - float outerRY = radiusY + half; - float innerRX = std::max(0.0f, radiusX - half); - float innerRY = std::max(0.0f, radiusY - half); + float outerRX = radiusX + half; + float outerRY = radiusY + half; + float innerRX = std::max(0.0f, radiusX - half); + float innerRY = std::max(0.0f, radiusY - half); - // Ensure capacity - if (m_vertexCount + (segments + 1) * 2 >= MaxVertices || - m_indexCount + segments * 6 >= MaxIndices) - { - flushBatch(); - } + // Ensure capacity + if (m_vertexCount + (segments + 1) * 2 >= MaxVertices || + m_indexCount + segments * 6 >= MaxIndices) + { + flushBatch(); + } - SDL_FColor col = COLOR_CAST(color); + SDL_FColor col = COLOR_CAST(color); - int base = m_vertexCount; + int base = m_vertexCount; - float angleRange = endAngle - startAngle; + float angleRange = endAngle - startAngle; - // Generate vertices: outer arc + inner arc - for (int i = 0; i <= segments; i++) - { - float t = float(i) / float(segments); - float angle = startAngle + t * angleRange; + // Generate vertices: outer arc + inner arc + for (int i = 0; i <= segments; i++) + { + float t = float(i) / float(segments); + float angle = startAngle + t * angleRange; - float cs = std::cos(angle); - float sn = std::sin(angle); + float cs = std::cos(angle); + float sn = std::sin(angle); - // Outer arc - m_vertices[m_vertexCount++] = { - { center.x + cs * outerRX, center.y + sn * outerRY }, - col, - { 0, 0 } - }; + // Outer arc + m_vertices[m_vertexCount++] = { + { center.x + cs * outerRX, center.y + sn * outerRY }, + col, + { 0, 0 } + }; - // Inner arc - m_vertices[m_vertexCount++] = { - { center.x + cs * innerRX, center.y + sn * innerRY }, - col, - { 0, 0 } - }; - } + // Inner arc + m_vertices[m_vertexCount++] = { + { center.x + cs * innerRX, center.y + sn * innerRY }, + col, + { 0, 0 } + }; + } - // Generate indices (triangle strip → triangles) - for (int i = 0; i < segments; i++) - { - int o0 = base + i * 2; - int i0 = o0 + 1; - int o1 = o0 + 2; - int i1 = o0 + 3; + // Generate indices (triangle strip → triangles) + for (int i = 0; i < segments; i++) + { + int o0 = base + i * 2; + int i0 = o0 + 1; + int o1 = o0 + 2; + int i1 = o0 + 3; - // Triangle 1 - m_indices[m_indexCount++] = o0; - m_indices[m_indexCount++] = o1; - m_indices[m_indexCount++] = i0; + // Triangle 1 + m_indices[m_indexCount++] = o0; + m_indices[m_indexCount++] = o1; + m_indices[m_indexCount++] = i0; - // Triangle 2 - m_indices[m_indexCount++] = o1; - m_indices[m_indexCount++] = i1; - m_indices[m_indexCount++] = i0; - } + // Triangle 2 + m_indices[m_indexCount++] = o1; + m_indices[m_indexCount++] = i1; + m_indices[m_indexCount++] = i0; + } } void BasicRenderer2D::generate_filled_ellipse_stroke(const ostd::Vec2& center, float radiusX, float radiusY, float startAngle, const ostd::Color& color, int segments) { - // Ensure capacity - if (m_vertexCount + segments + 2 >= MaxVertices || m_indexCount + segments * 3 >= MaxIndices) - flushBatch(); + // Ensure capacity + if (m_vertexCount + segments + 2 >= MaxVertices || m_indexCount + segments * 3 >= MaxIndices) + flushBatch(); - SDL_FColor col = COLOR_CAST(color); + SDL_FColor col = COLOR_CAST(color); - int base = m_vertexCount; + int base = m_vertexCount; - // Center vertex - m_vertices[m_vertexCount++] = { - { center.x, center.y }, - col, - { 0, 0 } - }; + // Center vertex + m_vertices[m_vertexCount++] = { + { center.x, center.y }, + col, + { 0, 0 } + }; - float endAngle = startAngle + M_PI * 0.5f; + float endAngle = startAngle + M_PI * 0.5f; - for (int i = 0; i <= segments; i++) - { - float t = float(i) / float(segments); - float angle = startAngle + t * (endAngle - startAngle); + for (int i = 0; i <= segments; i++) + { + float t = float(i) / float(segments); + float angle = startAngle + t * (endAngle - startAngle); - float x = center.x + std::cos(angle) * radiusX; - float y = center.y + std::sin(angle) * radiusY; + float x = center.x + std::cos(angle) * radiusX; + float y = center.y + std::sin(angle) * radiusY; - m_vertices[m_vertexCount++] = { - { x, y }, - col, - { 0, 0 } - }; - } + m_vertices[m_vertexCount++] = { + { x, y }, + col, + { 0, 0 } + }; + } - // Triangle fan indices - for (int i = 0; i < segments; i++) - { - m_indices[m_indexCount++] = base; - m_indices[m_indexCount++] = base + 1 + i; - m_indices[m_indexCount++] = base + 2 + i; - } + // Triangle fan indices + for (int i = 0; i < segments; i++) + { + m_indices[m_indexCount++] = base; + m_indices[m_indexCount++] = base + 1 + i; + m_indices[m_indexCount++] = base + 2 + i; + } } void BasicRenderer2D::generate_filled_ellipse(const ostd::Vec2& center, float radiusX, float radiusY, const ostd::Color& color, int segments) { - // Ensure capacity - if (m_vertexCount + segments + 2 >= MaxVertices || m_indexCount + segments * 3 >= MaxIndices) - flushBatch(); + // Ensure capacity + if (m_vertexCount + segments + 2 >= MaxVertices || m_indexCount + segments * 3 >= MaxIndices) + flushBatch(); - SDL_FColor col = COLOR_CAST(color); + SDL_FColor col = COLOR_CAST(color); - int base = m_vertexCount; + int base = m_vertexCount; - // Center vertex - m_vertices[m_vertexCount++] = { - { center.x, center.y }, - col, - { 0, 0 } - }; + // Center vertex + m_vertices[m_vertexCount++] = { + { center.x, center.y }, + col, + { 0, 0 } + }; - // Outer ring vertices - for (int i = 0; i <= segments; i++) - { - float t = float(i) / float(segments); - float angle = t * (2.0f * M_PI); + // Outer ring vertices + for (int i = 0; i <= segments; i++) + { + float t = float(i) / float(segments); + float angle = t * (2.0f * M_PI); - float x = center.x + std::cos(angle) * radiusX; - float y = center.y + std::sin(angle) * radiusY; + float x = center.x + std::cos(angle) * radiusX; + float y = center.y + std::sin(angle) * radiusY; - m_vertices[m_vertexCount++] = { - { x, y }, - col, - { 0, 0 } - }; - } + m_vertices[m_vertexCount++] = { + { x, y }, + col, + { 0, 0 } + }; + } - // Triangle fan indices - for (int i = 0; i < segments; i++) - { - m_indices[m_indexCount++] = base; - m_indices[m_indexCount++] = base + 1 + i; - m_indices[m_indexCount++] = base + 2 + i; - } + // Triangle fan indices + for (int i = 0; i < segments; i++) + { + m_indices[m_indexCount++] = base; + m_indices[m_indexCount++] = base + 1 + i; + m_indices[m_indexCount++] = base + 2 + i; + } } void BasicRenderer2D::push_polygon(const ostd::Vec2* verts, const ostd::Vec2* texCoords, uint32_t vertCount, const uint32_t* inds, uint32_t indexCount, const ostd::Color& color, SDL_Texture* texture) { - if (!m_initialized || vertCount <= 0 || indexCount <= 0) - return; + if (!m_initialized || vertCount <= 0 || indexCount <= 0) + return; if (vertCount > MaxVertices || indexCount > MaxIndices) { @@ -1031,127 +1056,33 @@ namespace ogfx return; } if (texture != m_texture) - flushBatch(); - m_texture = texture; - if (m_vertexCount + vertCount >= MaxVertices || m_indexCount + indexCount >= MaxIndices) - flushBatch(); + flushBatch(); + m_texture = texture; + if (m_vertexCount + vertCount >= MaxVertices || m_indexCount + indexCount >= MaxIndices) + flushBatch(); - SDL_FColor col = COLOR_CAST(color); + SDL_FColor col = COLOR_CAST(color); - int base = m_vertexCount; + int base = m_vertexCount; bool hasTexCoords = texCoords != nullptr; - for (int i = 0; i < vertCount; i++) - { + for (int i = 0; i < vertCount; i++) + { ostd::Vec2 tc { 0.0f, 0.0f }; if (hasTexCoords) tc = texCoords[i]; - m_vertices[m_vertexCount++] = { - { verts[i].x, verts[i].y }, - col, - { tc.x, tc.y }, - }; - } - for (int i = 0; i < indexCount; i++) - m_indices[m_indexCount++] = base + inds[i]; + m_vertices[m_vertexCount++] = { + { verts[i].x, verts[i].y }, + col, + { tc.x, tc.y }, + }; + } + for (int i = 0; i < indexCount; i++) + m_indices[m_indexCount++] = base + inds[i]; } void BasicRenderer2D::print_ttf_error(const ostd::String& funcName) { m_out.fg(ostd::ConsoleColors::Red).p(funcName).p("(...) failed: ").p(ostd::String(SDL_GetError())).reset().nl(); } - - void BasicRenderer2D::renderText(const ostd::String& message, int32_t x, int32_t y, const ostd::Color& color, int32_t fontSize) - { - if (!m_initialized) - { - set_error_state(tErrors::Uninitialized); - return; - } - if (!m_fontOpen) - { - set_error_state(tErrors::NoFont); - return; - } - if (m_font == nullptr) - { - set_error_state(tErrors::NullFont); - return; - } - setFontSize(fontSize); - SDL_Surface* surf = TTF_RenderText_Blended(m_font, message.c_str(), message.len(), { color.r, color.g, color.b, color.a }); - if (surf == nullptr) - { - set_error_state(tErrors::TTFRenderTextBlendedFail); - print_ttf_error("TTF_RenderText_Blended"); - return; - } - auto renderer = m_window->getSDLRenderer(); - SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surf); - if (texture == nullptr) - { - set_error_state(tErrors::TTFCreateTextureFromSurfaceFail); - print_ttf_error("SDL_CreateTextureFromSurface"); - return; - } - SDL_DestroySurface(surf); - - float w = 0, h = 0; - SDL_GetTextureSize(texture, &w, &h); - - SDL_FRect dst; - dst.x = x; - dst.y = y; - dst.w = w; - dst.h = h; - SDL_RenderTexture(renderer, texture, NULL, &dst); - SDL_DestroyTexture(texture); - } - - void BasicRenderer2D::renderCenteredText(const ostd::String& message, int32_t center_x, int32_t center_y, const ostd::Color& color, int32_t fontSize) - { - if (!m_initialized) - { - set_error_state(tErrors::Uninitialized); - return; - } - if (!m_fontOpen) - { - set_error_state(tErrors::NoFont); - return; - } - if (m_font == nullptr) - { - set_error_state(tErrors::NullFont); - return; - } - setFontSize(fontSize); - auto renderer = m_window->getSDLRenderer(); - SDL_Surface* surf = TTF_RenderText_Blended(m_font, message.c_str(), message.len(), { color.r, color.g, color.b, color.a }); - if (surf == nullptr) - { - set_error_state(tErrors::TTFRenderTextBlendedFail); - print_ttf_error("TTF_RenderText_Blended"); - return; - } - SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surf); - if (texture == nullptr) - { - set_error_state(tErrors::TTFCreateTextureFromSurfaceFail); - print_ttf_error("SDL_CreateTextureFromSurface"); - return; - } - SDL_DestroySurface(surf); - - float w = 0, h = 0; - SDL_GetTextureSize(texture, &w, &h); - - SDL_FRect dst; - dst.x = center_x - (w / 2); - dst.y = center_y - (h / 2); - dst.w = w; - dst.h = h; - SDL_RenderTexture(renderer, texture, NULL, &dst); - SDL_DestroyTexture(texture); - } // ===================================================== PRIVATE HELPERS ===================================================== } diff --git a/src/ogfx/render/BasicRenderer.hpp b/src/ogfx/render/BasicRenderer.hpp index 0f49c1b..dfd5b0a 100644 --- a/src/ogfx/render/BasicRenderer.hpp +++ b/src/ogfx/render/BasicRenderer.hpp @@ -1,21 +1,21 @@ /* - OmniaFramework - A collection of useful functionality - Copyright (C) 2025 OmniaX-Dev + OmniaFramework - A collection of useful functionality + Copyright (C) 2025 OmniaX-Dev - This file is part of OmniaFramework. + This file is part of OmniaFramework. - OmniaFramework is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + OmniaFramework is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - OmniaFramework is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + OmniaFramework is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with OmniaFramework. If not, see . + You should have received a copy of the GNU General Public License + along with OmniaFramework. If not, see . */ #pragma once @@ -68,7 +68,7 @@ namespace ogfx int32_t openFont(const ostd::String& fontPath, int32_t fontSize = 0); int32_t openFont(const ostd::UByte resource_data[], uint32_t data_size, int32_t fontSize = 0); int32_t setFontSize(int32_t fontSize); - ostd::IPoint getStringDimensions(const ostd::String& message, int32_t fontSize = 0); + ostd::Vec2 getStringDimensions(const ostd::String& message, int32_t fontSize = 0, TTF_Font* font = nullptr); inline uint32_t getDrawCallCount(void) { return m_drawCallCount; } inline bool hasOpenFont(void) { return m_fontOpen; } @@ -80,11 +80,13 @@ namespace ogfx inline bool isInitialized(void) { return m_initialized; } inline FontGlyphAtlas& getFontGlyphAtlas(void) { return m_fontGlyphAtlas; } - void drawImage(const ogfx::Image& image, const ostd::Vec2& position, const ostd::Vec2& size = { 0, 0 }, const ostd::Rectangle& srcRect = { 0, 0, 0, 0 }); - void drawAnimation(const Animation& anim, const ostd::Vec2& position, const ostd::Vec2& size = { 0, 0 }); + void drawImage(const ogfx::Image& image, const ostd::Vec2& position, const ostd::Vec2& size = { 0, 0 }, const ostd::Rectangle& srcRect = { 0, 0, 0, 0 }); + void drawAnimation(const Animation& anim, const ostd::Vec2& position, const ostd::Vec2& size = { 0, 0 }); + + void drawString(const ostd::String& str, const ostd::Vec2& position, const ostd::Color& color, int32_t fontSize = 0, float scale = 1.0f); + void drawCenteredString(const ostd::String& str, const ostd::Vec2& center, const ostd::Color& color, int32_t fontSize = 0, float scale = 1.0f); + void drawCenteredString(const ostd::String& str, const ostd::Rectangle& bounds, const ostd::Color& color, int32_t fontSize = 0, float scale = 1.0f); - void drawString(const ostd::String& str, const ostd::Vec2& position, const ostd::Color& color, int32_t fontSize = 0); - void drawCenteredString(const ostd::String& str, const ostd::Vec2& center, const ostd::Color& color, int32_t fontSize = 0); void drawLine(const ostd::FLine& line, const ostd::Color& color, int32_t thickness = 1, bool rounded = true); @@ -106,7 +108,7 @@ namespace ogfx void outlinedCircle(const ostd::Rectangle& rect, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t outlineThickness = 1); void outlinedEllipse(const ostd::Rectangle& rect, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t outlineThickness = 1); - public: + private: void init_arrays(void); void generate_half_circle(const ostd::Vec2& center, const ostd::Vec2& dir, float radius, int segments, const ostd::Color& color); void generate_quarter_circle(const ostd::Vec2& center, float radius, float thickness, float startAngle, const ostd::Color& color, int segments); @@ -117,8 +119,6 @@ namespace ogfx void push_polygon(const ostd::Vec2* verts, const ostd::Vec2* texCoords, uint32_t vertCount, const uint32_t* inds, uint32_t indexCount, const ostd::Color& color, SDL_Texture* texture); void print_ttf_error(const ostd::String& funcName); inline int32_t set_error_state(int32_t err) { m_errorState = err; return m_errorState; } - void renderText(const ostd::String& message, int32_t x, int32_t y, const ostd::Color& color, int32_t fontSize = 0); - void renderCenteredText(const ostd::String& message, int32_t center_x, int32_t center_y, const ostd::Color& color, int32_t fontSize = 0); public: inline static constexpr int32_t MaxVertices { 8192 }; diff --git a/src/ogfx/render/FontGlyphAtlas.cpp b/src/ogfx/render/FontGlyphAtlas.cpp index d11446b..529486d 100644 --- a/src/ogfx/render/FontGlyphAtlas.cpp +++ b/src/ogfx/render/FontGlyphAtlas.cpp @@ -23,6 +23,7 @@ #include #include #include +#include namespace ogfx { @@ -37,45 +38,67 @@ namespace ogfx return *this; } - bool FontGlyphAtlas::rasterize_glyph(const ostd::String& glyphStr, TTF_Font* font, uint32_t fontSize) + const std::vector FontGlyphAtlas::processString(const ostd::String& str, TTF_Font* font, uint32_t fontSize) + { + if (m_currentAtlasCount <= 0) + return {}; + + // Pass 1: ensure all glyphs are rasterized (map may rehash here) + for (auto& c : str) + { + const GlyphInfo* dummy; + if (!rasterize_glyph(ostd::String("").addChar(c), font, fontSize, &dummy)) + return {}; + } + + // Pass 2: collect stable pointers (no more insertions, no rehash risk) + std::vector glyphs; + glyphs.reserve(str.len()); + for (auto& c : str) + { + auto cps = ostd::String("").addChar(c).getUTF8Codepoints(); + if (cps.size() != 1) return {}; + GlyphKey key { cps[0], uint64_t(font), fontSize }; + glyphs.push_back(&m_uvs[key]); + } + return glyphs; + } + + bool FontGlyphAtlas::rasterize_glyph(const ostd::String& glyphStr, TTF_Font* font, uint32_t fontSize, const GlyphInfo** outGlyph) { if (!font || m_currentAtlasCount <= 0) return false; - // 1. Extract codepoint from the ostd::String auto cps = glyphStr.getUTF8Codepoints(); if (cps.size() != 1) - return false; // must be exactly one character + return false; uint32_t codepoint = cps[0]; GlyphKey key { codepoint, uint64_t(font), fontSize }; - if (auto it = m_uvs.find(key) != m_uvs.end()) + auto it = m_uvs.find(key); + if (it != m_uvs.end()) + { + *outGlyph = &(it->second); return true; + } - // 2. Convert the ostd::String to UTF-8 for SDL_ttf - std::string utf8 = glyphStr.cpp_str(); - - // 3. Rasterize glyph using SDL_ttf - SDL_Surface* surf = TTF_RenderText_Blended(font, utf8.c_str(), utf8.length(), SDL_Color{255, 255, 255, 255}); - + SDL_Surface* surf = TTF_RenderText_Blended(font, glyphStr.c_str(), glyphStr.len(), SDL_Color{255, 255, 255, 255}); if (!surf) return false; - // SDL_Surface* converted = SDL_ConvertSurface(surf, SDL_PIXELFORMAT_RGBA32); - // SDL_DestroySurface(surf); - // surf = converted; - int gw = surf->w; int gh = surf->h; - // 4. Get current atlas + int minx, maxx, miny, maxy, advance; + TTF_GetGlyphMetrics(font, codepoint, &minx, &maxx, &miny, &maxy, &advance); + + GlyphInfo glyph; + glyph.advance = advance; + glyph.codepoint = codepoint; + SDL_Texture* atlas = m_atlases[m_currentAtlasCount - 1]; - // SDL_Log("atlas format = %s", SDL_GetPixelFormatName(atlas->format)); - // SDL_Log("surf format = %s", SDL_GetPixelFormatName(surf->format)); - - // 5. Shelf packing: move to next row if needed if (m_penX + gw > int(AtlasTextureDimension)) { m_penX = 0; @@ -83,13 +106,12 @@ namespace ogfx m_rowHeight = 0; } - // 6. If still doesn't fit → create new atlas if (m_penY + gh > int(AtlasTextureDimension)) { SDL_DestroySurface(surf); if (!create_new_atlas()) - return false; // no more atlases available + return false; atlas = m_atlases[m_currentAtlasCount - 1]; m_penX = 0; @@ -97,74 +119,28 @@ namespace ogfx m_rowHeight = 0; } - uint8_t* pixels = (uint8_t*)surf->pixels; - int pitch = surf->pitch; - - // for (int y = 0; y < surf->h; y++) - // { - // uint32_t* row = (uint32_t*)(pixels + y * pitch); - - // for (int x = 0; x < surf->w; x++) - // { - // uint32_t px = row[x]; - - // uint8_t a = (px >> 24) & 0xFF; // ABGR → A is highest byte - // uint8_t r = (px >> 16) & 0xFF; - // uint8_t g = (px >> 8) & 0xFF; - // uint8_t b = (px) & 0xFF; - - // std::cout << (int)r << "," << (int)g << "," << (int)b << "," << (int)a << " "; - - // row[x] = (a << 24) | (r << 16) | (g << 8) | b; - // } - // } - - // 7. Upload glyph bitmap into atlas SDL_Rect dstRect { m_penX, m_penY, gw, gh }; - SDL_LockSurface(surf); SDL_UpdateTexture(atlas, &dstRect, surf->pixels, surf->pitch); SDL_UnlockSurface(surf); SDL_DestroySurface(surf); - // void* lockedPixels = nullptr; - // int lockedPitch = 0; - // if (SDL_LockTexture(atlas, &dstRect, &lockedPixels, &lockedPitch)) - // { - // SDL_LockSurface(surf); - // uint8_t* src = (uint8_t*)surf->pixels; - // uint8_t* dst = (uint8_t*)lockedPixels; - // for (int y = 0; y < gh; y++) - // { - // memcpy(dst, src, gw * 4); // 4 bytes per pixel (ARGB8888) - // src += surf->pitch; - // dst += lockedPitch; - // } - // SDL_UnlockSurface(surf); - // SDL_UnlockTexture(atlas); - // } - // // SDL_UpdateTexture(atlas, &dstRect, surf->pixels, surf->pitch); - // SDL_DestroySurface(surf); - - // 8. Compute UVs float u0 = float(m_penX) / float(AtlasTextureDimension); float v0 = float(m_penY) / float(AtlasTextureDimension); float u1 = float(m_penX + gw) / float(AtlasTextureDimension); float v1 = float(m_penY + gh) / float(AtlasTextureDimension); - GlyphUV uv; - uv.atlas = atlas; - uv.uvs[0] = { u0, v0 }; - uv.uvs[1] = { u1, v0 }; - uv.uvs[2] = { u1, v1 }; - uv.uvs[3] = { u0, v1 }; - uv.size = { static_cast(gw), static_cast(gh) }; + glyph.atlas = atlas; + glyph.uvs[0] = { u0, v0 }; + glyph.uvs[1] = { u1, v0 }; + glyph.uvs[2] = { u1, v1 }; + glyph.uvs[3] = { u0, v1 }; + glyph.size = { static_cast(gw), static_cast(gh) }; - // 9. Store in hashmap - m_uvs[key] = uv; + m_uvs[key] = glyph; + *outGlyph = &(m_uvs[key]); - // 10. Advance shelf packing cursor m_penX += gw; m_rowHeight = std::max(m_rowHeight, gh); return true; @@ -172,7 +148,6 @@ namespace ogfx bool FontGlyphAtlas::create_new_atlas(void) { - // 1. Check if we can create another atlas if (m_currentAtlasCount >= int(MaxAtlasCount)) return false; @@ -183,18 +158,15 @@ namespace ogfx if (!sdlRenderer) return false; - // 2. Create the texture - SDL_Texture* tex = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STREAMING, AtlasTextureDimension, AtlasTextureDimension); - + SDL_Texture* tex = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, AtlasTextureDimension, AtlasTextureDimension); if (!tex) return false; - // 3. Set blend mode (important for alpha glyphs) SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND); SDL_SetTextureScaleMode(tex, SDL_SCALEMODE_LINEAR); - // 4. Clear the texture to transparent - { + + { // Clear the texture to transparent void* pixels = nullptr; int pitch = 0; if (SDL_LockTexture(tex, nullptr, &pixels, &pitch) == 0) @@ -204,52 +176,13 @@ namespace ogfx } } - // 5. Store the atlas m_atlases[m_currentAtlasCount] = tex; m_currentAtlasCount++; - // 6. Reset packing cursor for this new atlas m_penX = 0; m_penY = 0; m_rowHeight = 0; return true; } - - void FontGlyphAtlas::save_atlas_to_png(SDL_Renderer* renderer, SDL_Texture* atlas, const char* filename) - { - // 1. Get texture dimensions and format - float w, h; - SDL_GetTextureSize(atlas, &w, &h); - int iw = (int)w, ih = (int)h; - - // 2. Create a target surface - SDL_Surface* surf = SDL_CreateSurface(iw, ih, SDL_PIXELFORMAT_ARGB8888); - if (!surf) return; - - // 3. Read pixels back from the texture - SDL_Rect rect { 0, 0, iw, ih }; - - // For STREAMING textures, lock/read directly: - void* pixels = nullptr; - int pitch = 0; - if (SDL_LockTexture(atlas, nullptr, &pixels, &pitch)) - { - uint8_t* src = (uint8_t*)pixels; - uint8_t* dst = (uint8_t*)surf->pixels; - for (int y = 0; y < ih; y++) - { - memcpy(dst, src, iw * 4); - src += pitch; - dst += surf->pitch; - } - SDL_UnlockTexture(atlas); - } - - // 4. Save - IMG_SavePNG(surf, filename); // needs SDL3_image - // or: SDL_SaveBMP(surf, "atlas_debug.bmp"); - - SDL_DestroySurface(surf); - } } diff --git a/src/ogfx/render/FontGlyphAtlas.hpp b/src/ogfx/render/FontGlyphAtlas.hpp index 748cdfa..a090e8d 100644 --- a/src/ogfx/render/FontGlyphAtlas.hpp +++ b/src/ogfx/render/FontGlyphAtlas.hpp @@ -29,11 +29,13 @@ namespace ogfx class BasicRenderer2D; class FontGlyphAtlas { - public: struct GlyphUV + public: struct GlyphInfo { ostd::Vec2 uvs[4]; SDL_Texture* atlas { nullptr }; ostd::Vec2 size; + uint32_t codepoint { 0 }; + int32_t advance { 0 }; }; struct GlyphKey { @@ -62,18 +64,18 @@ namespace ogfx inline FontGlyphAtlas(void) { } inline FontGlyphAtlas(BasicRenderer2D& renderer) { init(renderer); } FontGlyphAtlas init(BasicRenderer2D& renderer); + const std::vector processString(const ostd::String& str, TTF_Font* font, uint32_t fontSize); - public: - bool rasterize_glyph(const ostd::String& glyphStr, TTF_Font* font, uint32_t fontSize); + private: + bool rasterize_glyph(const ostd::String& glyphStr, TTF_Font* font, uint32_t fontSize, const GlyphInfo** outGlyph); bool create_new_atlas(void); - void save_atlas_to_png(SDL_Renderer* renderer, SDL_Texture* atlas, const char* filename); public: inline static constexpr uint32_t AtlasTextureDimension { 8192 }; inline static constexpr uint32_t MaxAtlasCount { 16 }; public: - std::unordered_map m_uvs; + std::unordered_map m_uvs; SDL_Texture* m_atlases[FontGlyphAtlas::MaxAtlasCount]; int32_t m_currentAtlasCount { 0 }; BasicRenderer2D* m_renderer { nullptr }; diff --git a/src/test/GuiTest.cpp b/src/test/GuiTest.cpp index b736ea5..0787c06 100644 --- a/src/test/GuiTest.cpp +++ b/src/test/GuiTest.cpp @@ -1,21 +1,21 @@ /* - OmniaFramework - A collection of useful functionality - Copyright (C) 2025 OmniaX-Dev + OmniaFramework - A collection of useful functionality + Copyright (C) 2025 OmniaX-Dev - This file is part of OmniaFramework. + This file is part of OmniaFramework. - OmniaFramework is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + OmniaFramework is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - OmniaFramework is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + OmniaFramework is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with OmniaFramework. If not, see . + You should have received a copy of the GNU General Public License + along with OmniaFramework. If not, see . */ #include "gui/Events.hpp" @@ -25,42 +25,39 @@ ostd::ConsoleOutputHandler out; -void drawTexturedQuad(SDL_Renderer* renderer, - SDL_Texture* tex, - const ostd::Rectangle& rect, - const ostd::Vec2 uvs[4]) +void drawTexturedQuad(SDL_Renderer* renderer, SDL_Texture* tex, const ostd::Rectangle& rect, const ostd::Vec2 uvs[4]) { - SDL_Vertex verts[4]; + SDL_Vertex verts[4]; - // Expand rectangle into quad corners - const float x = rect.x; - const float y = rect.y; - const float w = rect.w; - const float h = rect.h; + // Expand rectangle into quad corners + const float x = rect.x; + const float y = rect.y; + const float w = rect.w; + const float h = rect.h; - const ostd::Vec2 quad[4] = { - { x, y }, - { x + w, y }, - { x + w, y + h }, - { x, y + h } - }; + const ostd::Vec2 quad[4] = { + { x, y }, + { x + w, y }, + { x + w, y + h }, + { x, y + h } + }; - for (int i = 0; i < 4; i++) - { - verts[i].position.x = quad[i].x; - verts[i].position.y = quad[i].y; + for (int i = 0; i < 4; i++) + { + verts[i].position.x = quad[i].x; + verts[i].position.y = quad[i].y; - verts[i].tex_coord.x = uvs[i].x; - verts[i].tex_coord.y = uvs[i].y; + verts[i].tex_coord.x = uvs[i].x; + verts[i].tex_coord.y = uvs[i].y; - auto crim = ostd::Colors::Crimson.getNormalizedColor(); - verts[i].color = SDL_FColor{crim.r, crim.g, crim.b, crim.a}; - } + auto crim = ostd::Colors::Crimson.getNormalizedColor(); + verts[i].color = SDL_FColor{crim.r, crim.g, crim.b, crim.a}; + } - // Two triangles: (0,1,2) and (2,3,0) - const int indices[6] = { 0, 1, 2, 2, 3, 0 }; + // Two triangles: (0,1,2) and (2,3,0) + const int indices[6] = { 0, 1, 2, 2, 3, 0 }; - SDL_RenderGeometry(renderer, tex, verts, 4, indices, 6); + SDL_RenderGeometry(renderer, tex, verts, 4, indices, 6); } @@ -105,14 +102,14 @@ class Window : public ogfx::gui::Window m_label1.setMouseScrolledCallback([&](const ogfx::gui::Event& event) -> void { std::cout << "SCROLL!\n"; }); - // addWidget(m_label1); + addWidget(m_label1); m_panel2.addChild(m_panel1); - // addWidget(m_panel2); + addWidget(m_panel2); m_check1.setPosition(30, 30); m_check1.setText("Check this out!"); - // addWidget(m_check1); + addWidget(m_check1); m_label2.setPosition(0, 0); m_label2.setText("Ciccia Bella!"); @@ -156,63 +153,7 @@ class Window : public ogfx::gui::Window m_panel1.addChild(m_label3); setTheme(m_theme); - - m_gfx.setFontSize(fs); - m_gfx.getFontGlyphAtlas().rasterize_glyph(ostd::String("").addChar('H'), m_gfx.getSDLFont(), fs); - m_gfx.getFontGlyphAtlas().rasterize_glyph(ostd::String("").addChar('e'), m_gfx.getSDLFont(), fs); - m_gfx.getFontGlyphAtlas().rasterize_glyph(ostd::String("").addChar('l'), m_gfx.getSDLFont(), fs); - m_gfx.getFontGlyphAtlas().rasterize_glyph(ostd::String("").addChar('o'), m_gfx.getSDLFont(), fs); - - // int32_t count = 0; - // for (char c = 'A'; c <= 'Z'; c++) - // { - // for (int32_t i = 0; i < 200; i++) - // { - // count++; - // uint32_t _fs = ostd::Random::getui32(8, 200); - // m_gfx.setFontSize(_fs); - // m_gfx.getFontGlyphAtlas().rasterize_glyph(ostd::String("").addChar(c), m_gfx.getSDLFont(), _fs); - // } - // } - // for (char c = '0'; c <= '9'; c++) - // { - // for (int32_t i = 0; i < 200; i++) - // { - // count++; - // uint32_t _fs = ostd::Random::getui32(8, 200); - // m_gfx.setFontSize(_fs); - // m_gfx.getFontGlyphAtlas().rasterize_glyph(ostd::String("").addChar(c), m_gfx.getSDLFont(), _fs); - // } - // } - // for (char c = 'a'; c <= 'z'; c++) - // { - // count++; - // for (int32_t i = 0; i < 200; i++) - // { - // uint32_t _fs = ostd::Random::getui32(8, 200); - // m_gfx.setFontSize(_fs); - // m_gfx.getFontGlyphAtlas().rasterize_glyph(ostd::String("").addChar(c), m_gfx.getSDLFont(), _fs); - // } - // } - // for (char c = '0'; c <= '9'; c++) - // { - // for (int32_t i = 0; i < 200; i++) - // { - // count++; - // uint32_t _fs = ostd::Random::getui32(8, 200); - // m_gfx.setFontSize(_fs); - // m_gfx.getFontGlyphAtlas().rasterize_glyph(ostd::String("").addChar(c), m_gfx.getSDLFont(), _fs); - // } - // } - - // for (int32_t i = 0; i < m_gfx.getFontGlyphAtlas().m_currentAtlasCount; i++) - // { - // ostd::String file("./atlas"); - // file.add(i).add(".png"); - // m_gfx.getFontGlyphAtlas().save_atlas_to_png(m_gfx.getSDLRenderer(), m_gfx.getFontGlyphAtlas().m_atlases[i], file); - // } - // std::cout << "Atlas cound: " << (int)count << "\n"; - } + } inline void onSignal(ostd::Signal& signal) override { @@ -226,39 +167,6 @@ class Window : public ogfx::gui::Window void onRedraw(ogfx::BasicRenderer2D& gfx) override { - // auto l_rndPoint = [&](void) -> ostd::FPoint { - // using rnd = ostd::Random; - // return rnd::getVec2({ 0, (float)getWindowWidth() / 2 }, { 0, (float)getWindowHeight() / 2 }); - // }; - // for (int32_t i = 0; i < 1000; i++) - // gfx.drawLine({ l_rndPoint(), l_rndPoint() }, ostd::Colors::Crimson, 10); - // gfx.drawLine({ { 10, 10 }, { 200, 100 } }, ostd::Colors::Crimson, 3); - // gfx.drawRect({ 50, 50, 200, 120 }, ostd::Colors::Aquamarine, 1); - - // std::cout << (int)(gfx.getDrawCallCount() + 1) << "\n"; - - gfx.endFrame(); - - auto l_renderGlyph = [&](char c, float x, float y, float scale = 1) -> ostd::Vec2 { - auto& tex = m_gfx.getFontGlyphAtlas().m_atlases[0]; - auto glyph = m_gfx.getFontGlyphAtlas().m_uvs[ { static_cast(c), (uint64_t)gfx.getSDLFont(), fs }]; - drawTexturedQuad(getSDLRenderer(), tex, { x, y, glyph.size.x * scale, glyph.size.y * scale }, glyph.uvs); - return glyph.size; - }; - auto l_renderString = [&](const ostd::String& str, const ostd::Vec2& pos, float scale = 1.0f) -> void { - float x = pos.x; - float y = pos.y; - for (auto& c : str) - { - auto size = l_renderGlyph(c, x, y, scale); - x += (size.x * scale); - } - }; - - l_renderString("Hello", { 10, 140 }); - - gfx.renderText("Hello", 10, 100, ostd::Colors::Crimson, fs); - } private: @@ -270,7 +178,6 @@ class Window : public ogfx::gui::Window ogfx::gui::widgets::CheckBox m_check1 { *this }; ostd::Stylesheet m_theme; ostd::Vec2 pos { 0, 0 }; - uint32_t fs = 30; }; int main(int argc, char** argv)