Implemented batched text rendering

This commit is contained in:
OmniaX-Dev 2026-04-14 06:46:31 +02:00
parent ceb25e8e38
commit 17fdf08a20
10 changed files with 722 additions and 943 deletions

BIN
extra/FreeSans.ttf Normal file

Binary file not shown.

View file

@ -5,7 +5,7 @@ $accentColor = Color(rgba(255, 0, 255, 255))
const $color2 = Color(#0000FFFF) 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)) $accentColor = Color(rgb(255, 0, 0))
@ -13,7 +13,7 @@ $accentColor = Color(rgb(255, 0, 0))
textColor = $accentColor textColor = $accentColor
backgroundColor = Color(#000000FF) backgroundColor = Color(#000000FF)
borderColor = $accentColor borderColor = $accentColor
fontSize = 50 fontSize = 20
borderRadius = 0 borderRadius = 0
borderWidth = 2 borderWidth = 2
showBackground = true showBackground = true
@ -65,7 +65,7 @@ $accentColor = Color(rgb(255, 0, 0))
(@testLabel label) { (@testLabel label) {
textColor = $color2 textColor = $color2
backgroundColor = Color(#000000FF) backgroundColor = Color(#000000FF)
fontSize = 20 fontSize = 50
} }
(@testLabel2 label) { (@testLabel2 label) {
@ -108,7 +108,6 @@ $accentColor = Color(rgb(255, 0, 0))
(@label3 label) { (@label3 label) {
textColor = $color2 textColor = $color2
backgroundColor = Color(#000000FF) backgroundColor = Color(#000000FF)
fontSize = 20
borderColor = Color(#FF0000FF) borderColor = Color(#FF0000FF)
borderWidth = 4 borderWidth = 4
borderRadius = 15 borderRadius = 15

View file

@ -14,6 +14,11 @@ Add theme caching
Implement callback for state changes in checkbox Implement callback for state changes in checkbox
FIX: WindowOutputHandler text rendering FIX: WindowOutputHandler text rendering
find a way to add fixed update to gui::Window 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: Implement following widgets:

View file

@ -1 +1 @@
2060 2061

View file

@ -73,6 +73,8 @@ namespace ogfx
void CheckBox::onMouseReleased(const Event& event) void CheckBox::onMouseReleased(const Event& event)
{ {
if (!isMouseInside())
return;
m_checked = !m_checked; m_checked = !m_checked;
setThemeQualifier("active", m_checked); setThemeQualifier("active", m_checked);
} }

File diff suppressed because it is too large Load diff

View file

@ -1,21 +1,21 @@
/* /*
OmniaFramework - A collection of useful functionality OmniaFramework - A collection of useful functionality
Copyright (C) 2025 OmniaX-Dev 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 OmniaFramework is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
OmniaFramework is distributed in the hope that it will be useful, OmniaFramework is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with OmniaFramework. If not, see <https://www.gnu.org/licenses/>. along with OmniaFramework. If not, see <https://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
@ -68,7 +68,7 @@ namespace ogfx
int32_t openFont(const ostd::String& fontPath, int32_t fontSize = 0); 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 openFont(const ostd::UByte resource_data[], uint32_t data_size, int32_t fontSize = 0);
int32_t setFontSize(int32_t fontSize); 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 uint32_t getDrawCallCount(void) { return m_drawCallCount; }
inline bool hasOpenFont(void) { return m_fontOpen; } inline bool hasOpenFont(void) { return m_fontOpen; }
@ -80,11 +80,13 @@ namespace ogfx
inline bool isInitialized(void) { return m_initialized; } inline bool isInitialized(void) { return m_initialized; }
inline FontGlyphAtlas& getFontGlyphAtlas(void) { return m_fontGlyphAtlas; } 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 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 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); 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 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); 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 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_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); 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 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); void print_ttf_error(const ostd::String& funcName);
inline int32_t set_error_state(int32_t err) { m_errorState = err; return m_errorState; } 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: public:
inline static constexpr int32_t MaxVertices { 8192 }; inline static constexpr int32_t MaxVertices { 8192 };

View file

@ -23,6 +23,7 @@
#include <SDL3/SDL_pixels.h> #include <SDL3/SDL_pixels.h>
#include <SDL3/SDL_render.h> #include <SDL3/SDL_render.h>
#include <SDL3/SDL_surface.h> #include <SDL3/SDL_surface.h>
#include <SDL3_ttf/SDL_ttf.h>
namespace ogfx namespace ogfx
{ {
@ -37,45 +38,67 @@ namespace ogfx
return *this; return *this;
} }
bool FontGlyphAtlas::rasterize_glyph(const ostd::String& glyphStr, TTF_Font* font, uint32_t fontSize) const std::vector<const FontGlyphAtlas::GlyphInfo*> 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<const GlyphInfo*> 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) if (!font || m_currentAtlasCount <= 0)
return false; return false;
// 1. Extract codepoint from the ostd::String
auto cps = glyphStr.getUTF8Codepoints(); auto cps = glyphStr.getUTF8Codepoints();
if (cps.size() != 1) if (cps.size() != 1)
return false; // must be exactly one character return false;
uint32_t codepoint = cps[0]; uint32_t codepoint = cps[0];
GlyphKey key { codepoint, uint64_t(font), fontSize }; 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; return true;
}
// 2. Convert the ostd::String to UTF-8 for SDL_ttf SDL_Surface* surf = TTF_RenderText_Blended(font, glyphStr.c_str(), glyphStr.len(), SDL_Color{255, 255, 255, 255});
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});
if (!surf) if (!surf)
return false; return false;
// SDL_Surface* converted = SDL_ConvertSurface(surf, SDL_PIXELFORMAT_RGBA32);
// SDL_DestroySurface(surf);
// surf = converted;
int gw = surf->w; int gw = surf->w;
int gh = surf->h; 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_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)) if (m_penX + gw > int(AtlasTextureDimension))
{ {
m_penX = 0; m_penX = 0;
@ -83,13 +106,12 @@ namespace ogfx
m_rowHeight = 0; m_rowHeight = 0;
} }
// 6. If still doesn't fit → create new atlas
if (m_penY + gh > int(AtlasTextureDimension)) if (m_penY + gh > int(AtlasTextureDimension))
{ {
SDL_DestroySurface(surf); SDL_DestroySurface(surf);
if (!create_new_atlas()) if (!create_new_atlas())
return false; // no more atlases available return false;
atlas = m_atlases[m_currentAtlasCount - 1]; atlas = m_atlases[m_currentAtlasCount - 1];
m_penX = 0; m_penX = 0;
@ -97,74 +119,28 @@ namespace ogfx
m_rowHeight = 0; 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_Rect dstRect { m_penX, m_penY, gw, gh };
SDL_LockSurface(surf); SDL_LockSurface(surf);
SDL_UpdateTexture(atlas, &dstRect, surf->pixels, surf->pitch); SDL_UpdateTexture(atlas, &dstRect, surf->pixels, surf->pitch);
SDL_UnlockSurface(surf); SDL_UnlockSurface(surf);
SDL_DestroySurface(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 u0 = float(m_penX) / float(AtlasTextureDimension);
float v0 = float(m_penY) / float(AtlasTextureDimension); float v0 = float(m_penY) / float(AtlasTextureDimension);
float u1 = float(m_penX + gw) / float(AtlasTextureDimension); float u1 = float(m_penX + gw) / float(AtlasTextureDimension);
float v1 = float(m_penY + gh) / float(AtlasTextureDimension); float v1 = float(m_penY + gh) / float(AtlasTextureDimension);
GlyphUV uv; glyph.atlas = atlas;
uv.atlas = atlas; glyph.uvs[0] = { u0, v0 };
uv.uvs[0] = { u0, v0 }; glyph.uvs[1] = { u1, v0 };
uv.uvs[1] = { u1, v0 }; glyph.uvs[2] = { u1, v1 };
uv.uvs[2] = { u1, v1 }; glyph.uvs[3] = { u0, v1 };
uv.uvs[3] = { u0, v1 }; glyph.size = { static_cast<float>(gw), static_cast<float>(gh) };
uv.size = { static_cast<float>(gw), static_cast<float>(gh) };
// 9. Store in hashmap m_uvs[key] = glyph;
m_uvs[key] = uv; *outGlyph = &(m_uvs[key]);
// 10. Advance shelf packing cursor
m_penX += gw; m_penX += gw;
m_rowHeight = std::max(m_rowHeight, gh); m_rowHeight = std::max(m_rowHeight, gh);
return true; return true;
@ -172,7 +148,6 @@ namespace ogfx
bool FontGlyphAtlas::create_new_atlas(void) bool FontGlyphAtlas::create_new_atlas(void)
{ {
// 1. Check if we can create another atlas
if (m_currentAtlasCount >= int(MaxAtlasCount)) if (m_currentAtlasCount >= int(MaxAtlasCount))
return false; return false;
@ -183,18 +158,15 @@ namespace ogfx
if (!sdlRenderer) if (!sdlRenderer)
return false; return false;
// 2. Create the texture SDL_Texture* tex = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, AtlasTextureDimension, AtlasTextureDimension);
SDL_Texture* tex = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STREAMING, AtlasTextureDimension, AtlasTextureDimension);
if (!tex) if (!tex)
return false; return false;
// 3. Set blend mode (important for alpha glyphs)
SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND);
SDL_SetTextureScaleMode(tex, SDL_SCALEMODE_LINEAR); SDL_SetTextureScaleMode(tex, SDL_SCALEMODE_LINEAR);
// 4. Clear the texture to transparent
{ { // Clear the texture to transparent
void* pixels = nullptr; void* pixels = nullptr;
int pitch = 0; int pitch = 0;
if (SDL_LockTexture(tex, nullptr, &pixels, &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_atlases[m_currentAtlasCount] = tex;
m_currentAtlasCount++; m_currentAtlasCount++;
// 6. Reset packing cursor for this new atlas
m_penX = 0; m_penX = 0;
m_penY = 0; m_penY = 0;
m_rowHeight = 0; m_rowHeight = 0;
return true; 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);
}
} }

View file

@ -29,11 +29,13 @@ namespace ogfx
class BasicRenderer2D; class BasicRenderer2D;
class FontGlyphAtlas class FontGlyphAtlas
{ {
public: struct GlyphUV public: struct GlyphInfo
{ {
ostd::Vec2 uvs[4]; ostd::Vec2 uvs[4];
SDL_Texture* atlas { nullptr }; SDL_Texture* atlas { nullptr };
ostd::Vec2 size; ostd::Vec2 size;
uint32_t codepoint { 0 };
int32_t advance { 0 };
}; };
struct GlyphKey struct GlyphKey
{ {
@ -62,18 +64,18 @@ namespace ogfx
inline FontGlyphAtlas(void) { } inline FontGlyphAtlas(void) { }
inline FontGlyphAtlas(BasicRenderer2D& renderer) { init(renderer); } inline FontGlyphAtlas(BasicRenderer2D& renderer) { init(renderer); }
FontGlyphAtlas init(BasicRenderer2D& renderer); FontGlyphAtlas init(BasicRenderer2D& renderer);
const std::vector<const GlyphInfo*> processString(const ostd::String& str, TTF_Font* font, uint32_t fontSize);
public: private:
bool rasterize_glyph(const ostd::String& glyphStr, TTF_Font* font, uint32_t fontSize); bool rasterize_glyph(const ostd::String& glyphStr, TTF_Font* font, uint32_t fontSize, const GlyphInfo** outGlyph);
bool create_new_atlas(void); bool create_new_atlas(void);
void save_atlas_to_png(SDL_Renderer* renderer, SDL_Texture* atlas, const char* filename);
public: public:
inline static constexpr uint32_t AtlasTextureDimension { 8192 }; inline static constexpr uint32_t AtlasTextureDimension { 8192 };
inline static constexpr uint32_t MaxAtlasCount { 16 }; inline static constexpr uint32_t MaxAtlasCount { 16 };
public: public:
std::unordered_map<GlyphKey, GlyphUV, GlyphKeyHasher> m_uvs; std::unordered_map<GlyphKey, GlyphInfo, GlyphKeyHasher> m_uvs;
SDL_Texture* m_atlases[FontGlyphAtlas::MaxAtlasCount]; SDL_Texture* m_atlases[FontGlyphAtlas::MaxAtlasCount];
int32_t m_currentAtlasCount { 0 }; int32_t m_currentAtlasCount { 0 };
BasicRenderer2D* m_renderer { nullptr }; BasicRenderer2D* m_renderer { nullptr };

View file

@ -1,21 +1,21 @@
/* /*
OmniaFramework - A collection of useful functionality OmniaFramework - A collection of useful functionality
Copyright (C) 2025 OmniaX-Dev 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 OmniaFramework is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
OmniaFramework is distributed in the hope that it will be useful, OmniaFramework is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with OmniaFramework. If not, see <https://www.gnu.org/licenses/>. along with OmniaFramework. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "gui/Events.hpp" #include "gui/Events.hpp"
@ -25,42 +25,39 @@
ostd::ConsoleOutputHandler out; ostd::ConsoleOutputHandler out;
void drawTexturedQuad(SDL_Renderer* renderer, void drawTexturedQuad(SDL_Renderer* renderer, SDL_Texture* tex, const ostd::Rectangle& rect, const ostd::Vec2 uvs[4])
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 // Expand rectangle into quad corners
const float x = rect.x; const float x = rect.x;
const float y = rect.y; const float y = rect.y;
const float w = rect.w; const float w = rect.w;
const float h = rect.h; const float h = rect.h;
const ostd::Vec2 quad[4] = { const ostd::Vec2 quad[4] = {
{ x, y }, { x, y },
{ x + w, y }, { x + w, y },
{ x + w, y + h }, { x + w, y + h },
{ x, y + h } { x, y + h }
}; };
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
verts[i].position.x = quad[i].x; verts[i].position.x = quad[i].x;
verts[i].position.y = quad[i].y; verts[i].position.y = quad[i].y;
verts[i].tex_coord.x = uvs[i].x; verts[i].tex_coord.x = uvs[i].x;
verts[i].tex_coord.y = uvs[i].y; verts[i].tex_coord.y = uvs[i].y;
auto crim = ostd::Colors::Crimson.getNormalizedColor(); auto crim = ostd::Colors::Crimson.getNormalizedColor();
verts[i].color = SDL_FColor{crim.r, crim.g, crim.b, crim.a}; verts[i].color = SDL_FColor{crim.r, crim.g, crim.b, crim.a};
} }
// Two triangles: (0,1,2) and (2,3,0) // Two triangles: (0,1,2) and (2,3,0)
const int indices[6] = { 0, 1, 2, 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 { m_label1.setMouseScrolledCallback([&](const ogfx::gui::Event& event) -> void {
std::cout << "SCROLL!\n"; std::cout << "SCROLL!\n";
}); });
// addWidget(m_label1); addWidget(m_label1);
m_panel2.addChild(m_panel1); m_panel2.addChild(m_panel1);
// addWidget(m_panel2); addWidget(m_panel2);
m_check1.setPosition(30, 30); m_check1.setPosition(30, 30);
m_check1.setText("Check this out!"); m_check1.setText("Check this out!");
// addWidget(m_check1); addWidget(m_check1);
m_label2.setPosition(0, 0); m_label2.setPosition(0, 0);
m_label2.setText("Ciccia Bella!"); m_label2.setText("Ciccia Bella!");
@ -156,63 +153,7 @@ class Window : public ogfx::gui::Window
m_panel1.addChild(m_label3); m_panel1.addChild(m_label3);
setTheme(m_theme); 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 inline void onSignal(ostd::Signal& signal) override
{ {
@ -226,39 +167,6 @@ class Window : public ogfx::gui::Window
void onRedraw(ogfx::BasicRenderer2D& gfx) override 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<uint32_t>(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: private:
@ -270,7 +178,6 @@ class Window : public ogfx::gui::Window
ogfx::gui::widgets::CheckBox m_check1 { *this }; ogfx::gui::widgets::CheckBox m_check1 { *this };
ostd::Stylesheet m_theme; ostd::Stylesheet m_theme;
ostd::Vec2 pos { 0, 0 }; ostd::Vec2 pos { 0, 0 };
uint32_t fs = 30;
}; };
int main(int argc, char** argv) int main(int argc, char** argv)