Flint Engine
Modular C++20 2D game engine powered by SDL3
Loading...
Searching...
No Matches
ui-canvas.h
1// SPDX-License-Identifier: MIT
2// SPDX-FileCopyrightText: 2025-2026 Manuel Osorio
3#pragma once
4
5#include "flint/graphics/gpu/gpu-texture.h"
6#include "flint/graphics/types/color.h"
7#include "flint/math/types.h"
8#include "flint/ui/ui-types.h"
9
10#include <SDL3/SDL_gpu.h>
11#include <SDL3_ttf/SDL_textengine.h>
12#include <SDL3_ttf/SDL_ttf.h>
13
14#include <memory>
15#include <string>
16#include <unordered_map>
17#include <vector>
18
19namespace Flint {
20 struct GpuTextItem;
21
22 class GPURenderer;
23 class RenderQueue;
24
29 struct FontKey {
30 std::string name;
31 uint16_t weight;
32 uint16_t fontSize = 0;
34 bool operator==(const FontKey &other) const {
35 return name == other.name && weight == other.weight && fontSize == other.fontSize;
36 }
37 };
38
43 struct FontKeyHash {
44 std::size_t operator()(const FontKey &key) const {
45 return std::hash<std::string>()(key.name) ^ (std::hash<uint16_t>()(key.weight) << 8) ^
46 (std::hash<uint16_t>()(key.fontSize) << 16);
47 }
48 };
49
55 struct TextCacheKey {
56 std::string text;
57 std::string fontName;
58 uint16_t fontSize;
59 uint16_t weight;
62 bool operator==(const TextCacheKey &other) const {
63 return text == other.text && fontName == other.fontName && fontSize == other.fontSize &&
64 weight == other.weight && color == other.color;
65 }
66 };
67
73 std::size_t operator()(const TextCacheKey &key) const {
74 std::size_t seed = 0;
75
76 auto combine = [&seed](std::size_t value) {
77 value += 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);
78 seed ^= value;
79 };
80
81 combine(std::hash<std::string>{}(key.text));
82 combine(std::hash<std::string>{}(key.fontName));
83 combine(std::hash<uint16_t>{}(key.fontSize));
84 combine(std::hash<uint16_t>{}(key.weight));
85
86 const uint32_t color = static_cast<uint32_t>(key.color.r) << 24 |
87 static_cast<uint32_t>(key.color.g) << 16 |
88 static_cast<uint32_t>(key.color.b) << 8 |
89 static_cast<uint32_t>(key.color.a);
90
91 combine(std::hash<uint32_t>{}(color));
92
93 return seed;
94 }
95 };
96
106 class UICanvas {
107 public:
110 explicit UICanvas(GPURenderer &renderer);
111 ~UICanvas();
112
113 UICanvas(const UICanvas &) = delete;
114 UICanvas &operator=(const UICanvas &) = delete;
115
116 void emit(RenderQueue &queue);
124 void uploadGeometry(SDL_GPUCommandBuffer *cmd);
125
132 void flushDrawCalls(SDL_GPURenderPass *renderPass, SDL_GPUCommandBuffer *commandBuffer);
133
137
145 void drawRect(Rect<float> rect, Color color);
146
153 void drawText(std::string text, float x, float y, float fontSize, Color color,
154 std::string fontName = "", uint16_t weight = 400);
155
163 void drawTexture(const GPUTexture &texture, Rect<float> rect,
164 Color tint = {255, 255, 255, 255});
165
168 return m_screenSize;
169 }
170
178 Vec2f measureText(const std::string &text, float fontSize, const std::string &fontName = "",
179 uint16_t weight = 400);
180
181 float getGlyphCenterOffset(const std::string &text, float fontSize,
182 const std::string &fontName = "", uint16_t weight = 400);
183
191 bool loadFont(std::vector<char> &&data, const std::string &fontName, uint16_t weight = 400);
192
194 void setDefaultFont(const std::string &name) {
195 m_defaultFont = name;
196 }
197
201
202 private:
206 struct RectVertex {
207 float x, y, u, v;
208 };
209
213 struct RectDrawCall {
214 std::size_t vertexOffset;
215 Color color;
216 SDL_GPUTexture *texture = nullptr;
217 };
218
223 struct TextDrawCall {
224 std::string text;
225 float x, y;
226 std::string fontName;
227 float fontSize;
228 uint16_t weight = 400;
229 Color color;
230 };
231
232 GPURenderer
233 &m_renderer;
234 Vec2f m_screenSize = {1.0f, 1.0f};
235
236 static constexpr std::size_t MAX_RECT_VERTICES =
237 6 * 1024;
240 std::vector<RectVertex>
241 m_rectVertices;
242 std::vector<RectDrawCall> m_rectDrawCalls;
244 SDL_GPUBuffer *m_rectVBO = nullptr;
245 SDL_GPUTransferBuffer *m_rectTransfer = nullptr;
246 void initRectBuffers();
247 void appendRectVertices(const Rect<float> &rect);
248
249 std::vector<TextDrawCall> m_textDrawCalls;
250
251 SDL_GPUSampler *m_sampler = nullptr;
252 SDL_GPUTexture *m_whiteTexture =
253 nullptr;
255 void initSharedGpuObjects();
256
257 std::unordered_map<FontKey, TTF_Font *, FontKeyHash> m_fontCache;
258 std::unordered_map<FontKey, std::vector<char>, FontKeyHash> m_fontDataByWeight;
259 std::unordered_map<TextCacheKey, std::unique_ptr<GpuTextItem>, TextCacheKeyHash> m_textCache;
260
267 TTF_Font *getFont(const std::string &name, uint16_t fontSize, uint16_t weight = 400);
268 std::string m_defaultFont = "default";
269
270 TTF_TextEngine *m_textEngine = nullptr;
271 };
272
273}
High-level SDL GPU renderer managing pipeline state, batching, and frame presentation.
Definition renderer.h:39
Owns an SDL GPU texture and its associated sampler.
Definition gpu-texture.h:20
Batches drawables into sorted geometry, primitive, and custom execution passes for GPURenderer.
void drawText(std::string text, float x, float y, float fontSize, Color color, std::string fontName="", uint16_t weight=400)
Enqueues a string draw command record to be processed during the geometry generation pass.
void flushDrawCalls(SDL_GPURenderPass *renderPass, SDL_GPUCommandBuffer *commandBuffer)
Pass 2 of the render loop: Binds graphics pipelines and triggers draw execution commands.
void drawRect(Rect< float > rect, Color color)
Submits a flat quad drawing sequence down to the current active runtime pipeline layer.
void setDefaultFont(const std::string &name)
Assigns the base default fallback typography name token.
Definition ui-canvas.h:194
Vec2f getScreenSize() const
Returns the active window coordinates representing the screen boundaries.
Definition ui-canvas.h:167
Vec2f measureText(const std::string &text, float fontSize, const std::string &fontName="", uint16_t weight=400)
Calculates structural spatial dimensions a text block requires before executing layout renders.
bool loadFont(std::vector< char > &&data, const std::string &fontName, uint16_t weight=400)
Registers raw binary TTF font file data into the subsystem memory allocator.
void uploadGeometry(SDL_GPUCommandBuffer *cmd)
Pass 1 of the render loop: Synchronizes local vertex lists down to the physical GPU VRAM.
void drawTexture(const GPUTexture &texture, Rect< float > rect, Color tint={255, 255, 255, 255})
Appends a geometric quad textured draw record down to the dynamic vertex batch structure arrays.
Dynamic 2D batching engine processing shape vector geometry and hardware-accelerated text strings....
Definition ui-canvas.h:106
void discardDrawCalls()
Instantly clears local staging arrays, abandoning all un-flushed vector and character draw steps.
void setScreenSize(Vec2f size)
Syncs internal display bounding metrics to transform absolute screen pixel bounds cleanly.
UICanvas(GPURenderer &renderer)
Binds the UI renderer subsystem to the master application graphics context layout tree.
RGBA color with 8-bit unsigned components.
Definition color.h:13
Custom hashing mechanism to facilitate constant-time O(1) font lookups inside associative arrays.
Definition ui-canvas.h:43
uint16_t weight
Definition ui-canvas.h:31
uint16_t fontSize
Definition ui-canvas.h:32
std::string name
Definition ui-canvas.h:30
Internal tracking key used to map a physical font asset instance in memory.
Definition ui-canvas.h:29
Generic axis-aligned rectangle defined by a position and size.
Definition types.h:87
64-bit golden ratio hash combiner designed to prevent lookup collisions across active text strings.
Definition ui-canvas.h:72
std::string text
Definition ui-canvas.h:56
std::string fontName
Definition ui-canvas.h:57
Compound lookup key combining text copy with style states to handle discrete GPU text caching.
Definition ui-canvas.h:55