From e8d13b931e8ad885f7cbec299106759630e1b49e Mon Sep 17 00:00:00 2001 From: OmniaX-Dev Date: Wed, 15 Apr 2026 17:15:34 +0200 Subject: [PATCH] Added triangle drawing functions to BasicRenderer2D --- other/TODO.txt | 1 + src/ogfx/render/BasicRenderer.cpp | 105 ++++++++++++++++++++++++------ src/ogfx/render/BasicRenderer.hpp | 6 ++ src/test/GuiTest.cpp | 3 +- 4 files changed, 94 insertions(+), 21 deletions(-) diff --git a/other/TODO.txt b/other/TODO.txt index b90c147..040506c 100644 --- a/other/TODO.txt +++ b/other/TODO.txt @@ -15,6 +15,7 @@ ***FIX: WindowOutputHandler text rendering ***Implement wrappers in Renderer2D to take a center and size for rects ***find a way to add fixed update to gui::Window +***Add triangle drawing functions to BasicRenderer2D Add theme caching Implement global scale (probably query desktop scale and adjust accordingly) Implement show/hide functionality for widgets diff --git a/src/ogfx/render/BasicRenderer.cpp b/src/ogfx/render/BasicRenderer.cpp index 64f1290..7019cd0 100644 --- a/src/ogfx/render/BasicRenderer.cpp +++ b/src/ogfx/render/BasicRenderer.cpp @@ -215,27 +215,27 @@ namespace ogfx Vec2 BasicRenderer2D::getStringDimensions(const String& message, i32 fontSize, TTF_Font* font) { if (!isValid()) return { 0, 0 }; - if (fontSize <= 0) fontSize = m_fontSize; - if (!font) font = m_font; + if (fontSize <= 0) fontSize = m_fontSize; + if (!font) font = m_font; i32 oldFontSize = getFontSize(); - setFontSize(fontSize); + setFontSize(fontSize); - auto glyphs = m_fontGlyphAtlas.processString(message, font, fontSize); - if (glyphs.empty()) return { 0, 0 }; + auto glyphs = m_fontGlyphAtlas.processString(message, font, fontSize); + if (glyphs.empty()) return { 0, 0 }; - f32 totalWidth = 0; - for (size_t i = 0; i < glyphs.size(); i++) - { - totalWidth += glyphs[i]->advance; - if (i > 0) - { - i32 kern = 0; - TTF_GetGlyphKerning(font, glyphs[i - 1]->codepoint, glyphs[i]->codepoint, &kern); - totalWidth += kern; - } - } + f32 totalWidth = 0; + for (size_t i = 0; i < glyphs.size(); i++) + { + totalWidth += glyphs[i]->advance; + if (i > 0) + { + i32 kern = 0; + TTF_GetGlyphKerning(font, glyphs[i - 1]->codepoint, glyphs[i]->codepoint, &kern); + totalWidth += kern; + } + } setFontSize(oldFontSize); - return { totalWidth, glyphs[0]->size.y }; + return { totalWidth, glyphs[0]->size.y }; } // ===================================================== UTILS ===================================================== @@ -361,7 +361,7 @@ namespace ogfx void BasicRenderer2D::drawCenteredString(const String& str, const Rectangle& bounds, const Color& color, i32 fontSize, f32 scale) { - drawCenteredString(str, Vec2 { bounds.x + bounds.w * 0.5f, bounds.y + bounds.h * 0.5f }, color, fontSize, scale); + drawCenteredString(str, Vec2 { bounds.x + bounds.w * 0.5f, bounds.y + bounds.h * 0.5f }, color, fontSize, scale); } // ===================================================== SPECIALIZED ===================================================== @@ -430,7 +430,7 @@ namespace ogfx void BasicRenderer2D::drawRect(const Vec2& center, const Vec2& size, const Color& color, i32 thickness) { - drawRect({ center.x - size.x * 0.5f, center.y - size.y * 0.5f, size.x, size.y }, color, thickness); + drawRect({ center.x - size.x * 0.5f, center.y - size.y * 0.5f, size.x, size.y }, color, thickness); } void BasicRenderer2D::drawRoundRect(const Rectangle& rect, const Color& color, f32 radius, i32 thickness) @@ -473,7 +473,7 @@ namespace ogfx void BasicRenderer2D::drawRoundRect(const Vec2& center, const Vec2& size, const Color& color, f32 radius, i32 thickness) { - drawRoundRect({ center.x - size.x * 0.5f, center.y - size.y * 0.5f, size.x, size.y }, color, radius, thickness); + drawRoundRect({ center.x - size.x * 0.5f, center.y - size.y * 0.5f, size.x, size.y }, color, radius, thickness); } void BasicRenderer2D::drawCircle(const Vec2& center, f32 radius, const Color& color, i32 thickness) @@ -511,6 +511,25 @@ namespace ogfx generate_ellipse_stroke(center, rx, ry, thickness, 0.0f, 2.0f * M_PI, color, segments); } + void BasicRenderer2D::drawTriangle(const Triangle& tri, const Color& color, i32 thickness) + { + if (!m_initialized) + return; + drawTriangle(tri.vA, tri.vB, tri.vC, color, thickness); + } + + void BasicRenderer2D::drawTriangle(const Vec2& A, const Vec2& B, const Vec2& C, const Color& color, i32 thickness) + { + if (!m_initialized) + return; + drawLine({ A, B }, color, thickness, false); + drawLine({ B, C }, color, thickness, false); + drawLine({ C, A }, color, thickness, false); + } + + + + void BasicRenderer2D::fillRect(const Rectangle& rect, const Color& color) { if (!m_initialized) @@ -679,6 +698,26 @@ namespace ogfx generate_filled_ellipse(center, radiusX, radiusY, color, segments); } + void BasicRenderer2D::fillTriangle(const Triangle& tri, const Color& color) + { + if (!m_initialized) + return; + fillTriangle(tri.vA, tri.vB, tri.vC, color); + } + + void BasicRenderer2D::fillTriangle(const Vec2& A, const Vec2& B, const Vec2& C, const Color& color) + { + if (!m_initialized) + return; + Vec2 verts[3] = { A, B, C }; + Vec2 texCoords[3] = { {0, 0}, {0, 0}, {0, 0} }; + u32 inds[3] = { 0, 1, 2 }; + push_polygon(verts, texCoords, 3, inds, 3, color, nullptr); + } + + + + void BasicRenderer2D::outlinedRect(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, i32 outlineThickness) { if (!m_initialized) return; @@ -733,6 +772,32 @@ namespace ogfx fillEllipse(rect + offset, fillColor); drawEllipse(rect, outlineColor, outlineThickness); } + + void BasicRenderer2D::outlinedTriangle(const Triangle& tri, const Color& fillColor, const Color& outlineColor, i32 outlineThickness) + { + if (!m_initialized) return; + outlinedTriangle(tri.vA, tri.vB, tri.vC, fillColor, outlineColor, outlineThickness); + } + + void BasicRenderer2D::outlinedTriangle(const Vec2& A, const Vec2& B, const Vec2& C, const Color& fillColor, const Color& outlineColor, i32 outlineThickness) + { + if (!m_initialized) return; + drawTriangle(A, B, C, outlineColor, outlineThickness); + // Inset the fill triangle so it doesn't bleed past the outline + f32 inset = cast(outlineThickness); + Vec2 centroid = { (A.x + B.x + C.x) / 3.0f, (A.y + B.y + C.y) / 3.0f }; + + auto shrink = [&](const Vec2& v) -> Vec2 { + Vec2 dir = { centroid.x - v.x, centroid.y - v.y }; + f32 len = std::sqrt(dir.x * dir.x + dir.y * dir.y); + if (len < 0.001f) return v; + dir.x /= len; + dir.y /= len; + return { v.x + dir.x * inset, v.y + dir.y * inset }; + }; + + fillTriangle(shrink(A), shrink(B), shrink(C), fillColor); + } // ===================================================== PRIMITIVES ===================================================== diff --git a/src/ogfx/render/BasicRenderer.hpp b/src/ogfx/render/BasicRenderer.hpp index 600f77a..13eb052 100644 --- a/src/ogfx/render/BasicRenderer.hpp +++ b/src/ogfx/render/BasicRenderer.hpp @@ -96,6 +96,8 @@ namespace ogfx void drawCircle(const Vec2& center, f32 radius, const Color& color, i32 thickness = 1); void drawCircle(const Rectangle& rect, const Color& color, i32 thickness = 1); void drawEllipse(const Rectangle& rect, const Color& color, i32 thickness = 1); + void drawTriangle(const Triangle& tri, const Color& color, i32 thickness = 1); + void drawTriangle(const Vec2& A, const Vec2& B, const Vec2& C, const Color& color, i32 thickness = 1); void fillRect(const Rectangle& rect, const Color& color); void fillRect(const Vec2& center, const Vec2& size, const Color& color); @@ -104,6 +106,8 @@ namespace ogfx void fillCircle(const Vec2& center, f32 radius, const Color& color); void fillCircle(const Rectangle& rect, const Color& color); void fillEllipse(const Rectangle& rect, const Color& color); + void fillTriangle(const Triangle& tri, const Color& color); + void fillTriangle(const Vec2& A, const Vec2& B, const Vec2& C, const Color& color); void outlinedRect(const Vec2& center, const Vec2& size, const Color& fillColor, const Color& outlineColor, i32 outlineThickness = 1); void outlinedRect(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, i32 outlineThickness = 1); @@ -112,6 +116,8 @@ namespace ogfx void outlinedCircle(const Vec2& center, f32 radius, const Color& fillColor, const Color& outlineColor, i32 outlineThickness = 1); void outlinedCircle(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, i32 outlineThickness = 1); void outlinedEllipse(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, i32 outlineThickness = 1); + void outlinedTriangle(const Triangle& tri, const Color& fillColor, const Color& outlineColor, i32 outlineThickness = 1); + void outlinedTriangle(const Vec2& A, const Vec2& B, const Vec2& C, const Color& fillColor, const Color& outlineColor, i32 outlineThickness = 1); private: void init_arrays(void); diff --git a/src/test/GuiTest.cpp b/src/test/GuiTest.cpp index 0d0b20e..d2d9247 100644 --- a/src/test/GuiTest.cpp +++ b/src/test/GuiTest.cpp @@ -153,7 +153,8 @@ class Window : public ogfx::gui::Window void onRedraw(ogfx::BasicRenderer2D& gfx) override { gfx.drawAnimation(m_anim, { 200, 200 }); - wout().xy(100, 100).fg(Colors::Crimson).p("CIAO BELLA").resetColors(); + gfx.outlinedTriangle({ 30, 30 }, { 100, 50 }, { 60, 90 }, Colors::Crimson, Colors::DarkBlue, 5); + gfx.endFrame(); } void onFixedUpdate(void) override