Skip to content

Commit d5a571b

Browse files
Track'n'Truck DevsTrack'n'Truck Devs
authored andcommitted
Fix: UI crash on dynamic font loading and renderer architecture update
- Fixed a crash when loading fonts from memory by moving font atlas rebuilding to the Update phase (before ImGui::NewFrame). - Introduced Renderer::OnRendererUpdate to separate logic/state updates from the pure rendering phase. - Added support for compressed font data in UI_LoadFontFromMemory with automatic heuristic detection. - Improved memory safety by persisting font glyph ranges (ImWchar) locally within UIManager to prevent use-after-free. - Updated D3D11, D3D12, and OpenGL renderer implementations to follow the new update/render lifecycle.
1 parent a297e3e commit d5a571b

11 files changed

Lines changed: 2468 additions & 17 deletions

File tree

include/SPF/Renderer/Renderer.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,15 @@ class Renderer {
8484
*/
8585
void OnRendererInit();
8686

87+
/**
88+
* @brief A callback invoked by the renderer implementation each frame to perform UI-independent updates.
89+
* This MUST be called BEFORE any ImGui NewFrame calls.
90+
*/
91+
void OnRendererUpdate();
92+
8793
/**
8894
* @brief A callback invoked by the renderer implementation each frame to perform UI rendering.
95+
* This MUST be called AFTER ImGui NewFrame and BEFORE ImGui::Render().
8996
*/
9097
void OnRendererRenderImGui();
9198

include/SPF/UI/UIManager.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ class UIManager : public Config::IConfigurable {
7373

7474
void RegisterWindow(std::shared_ptr<IWindow> window);
7575
IWindow* GetWindow(const std::string& componentName, const std::string& windowId) const;
76+
77+
/**
78+
* @brief Updates internal UI state (processes queues, rebuilds font atlas if needed).
79+
* This MUST be called before ImGui::NewFrame().
80+
*/
81+
void Update();
82+
7683
void RenderAll();
7784

7885
// Renderer access
@@ -179,8 +186,9 @@ class UIManager : public Config::IConfigurable {
179186
std::vector<unsigned char> data;
180187
float size_pixels;
181188
bool merge;
182-
const uint16_t* ranges;
189+
std::vector<uint16_t> ranges;
183190
bool isMemory;
191+
bool isCompressed;
184192
};
185193
std::vector<FontRequest> m_pendingFontRequests;
186194
std::vector<std::unique_ptr<std::vector<unsigned char>>> m_fontDataBuffers;

plugins/ExamplePlugin/ExamplePlugin.cpp

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
#include "ExamplePlugin.hpp"
1111
#include <cstring> // For C-style string manipulation functions like strncpy_s, strcpy_s, strcmp, strstr.
1212

13+
// --- Custom Fonts ---
14+
#include "font\DRKrapkaSquare.h"
15+
1316
namespace ExamplePlugin {
1417

1518
// =================================================================================================
@@ -426,7 +429,11 @@ void OnActivated(const SPF_Core_API* core_api) {
426429
// The actual SPF_Font_Handle should be retrieved later during rendering using UI_GetFont("ExamplePlugin_CustomFont").
427430
g_ctx.uiAPI->UI_LoadFontFromFile("ExamplePlugin_CustomFont", fontPath, &config);
428431

429-
g_ctx.coreAPI->logger->Log(logger, SPF_LOG_INFO, "Dynamic Font Management: Requested custom font Rushon Ground.ttf. It will be available in the next frame.");
432+
// --- Demo: Load Font from Memory (DRKrapkaSquare) ---
433+
// We use the compressed data from the generated .h file.
434+
g_ctx.uiAPI->UI_LoadFontFromMemory("ExamplePlugin_MemoryFont", Font_DRKrapkaSquare_compressed_data, Font_DRKrapkaSquare_compressed_size, &config);
435+
436+
g_ctx.coreAPI->logger->Log(logger, SPF_LOG_INFO, "Dynamic Font Management: Requested fonts from file and memory. They will be available in the next frame.");
430437
}
431438
}
432439

@@ -1862,16 +1869,36 @@ void RenderStylingTab(SPF_UI_API* ui, void* user_data) {
18621869

18631870
ui->UI_Spacing();
18641871
ui->UI_TextStyled(separator_style, ICON_FA_FONT " Dynamic Font Rendering");
1865-
ui->UI_TextWrapped("Demonstrating UI_LoadFontFromFile. Below is text rendered with 'Rushon Ground.ttf' loaded from the plugin's data folder.");
1872+
ui->UI_TextWrapped("Demonstrating UI_LoadFontFromFile and UI_LoadFontFromMemory.");
1873+
1874+
// --- File Font Demo ---
18661875
if (!g_ctx.pluginFont) {
1867-
ui->UI_TextColored(1.0f, 0.5f, 0.0f, 1.0f, "Custom font not loaded yet (queued for next frame or missing file).");
18681876
g_ctx.pluginFont = ui->UI_GetFont("ExamplePlugin_CustomFont");
18691877
}
1870-
else{
1878+
1879+
if (g_ctx.pluginFont) {
18711880
ui->UI_PushFont(g_ctx.pluginFont);
1872-
ui->UI_TextColored(0.4f, 0.7f, 1.0f, 1.0f, "This text uses a custom plugin font!");
1881+
ui->UI_TextColored(0.4f, 0.7f, 1.0f, 1.0f, "This text uses a custom font loaded from FILE (Rushon Ground.ttf)!");
1882+
ui->UI_Text("Sample: ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789");
1883+
ui->UI_PopFont();
1884+
} else {
1885+
ui->UI_TextColored(1.0f, 0.5f, 0.0f, 1.0f, "File font not loaded yet (queued for next frame or missing file).");
1886+
}
1887+
1888+
ui->UI_Spacing();
1889+
1890+
// --- Memory Font Demo ---
1891+
if (!g_ctx.memoryFont) {
1892+
g_ctx.memoryFont = ui->UI_GetFont("ExamplePlugin_MemoryFont");
1893+
}
1894+
1895+
if (g_ctx.memoryFont) {
1896+
ui->UI_PushFont(g_ctx.memoryFont);
1897+
ui->UI_TextColored(0.7f, 1.0f, 0.4f, 1.0f, "This text uses a custom font loaded from MEMORY (DRKrapkaSquare)!");
18731898
ui->UI_Text("Sample: ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789");
18741899
ui->UI_PopFont();
1900+
} else {
1901+
ui->UI_TextColored(1.0f, 0.5f, 0.0f, 1.0f, "Memory font not loaded yet (queued for next frame).");
18751902
}
18761903

18771904
ui->UI_Spacing();

plugins/ExamplePlugin/ExamplePlugin.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ struct PluginContext {
279279

280280
// --- Dynamic Font Management Demo ---
281281
SPF_Font_Handle pluginFont = nullptr;
282+
SPF_Font_Handle memoryFont = nullptr;
282283
};
283284

284285
/**

0 commit comments

Comments
 (0)