Skip to content

Commit d84c36a

Browse files
committed
feat: Add BitmapFont support and modular font compilation
- Add BitmapFont class for lightweight font rendering without FreeType - Add pack_bitmap_font.py tool to generate font atlases from TTF - Add CMake options ES_FEATURE_SDF_FONT and ES_FEATURE_BITMAP_FONT - Update UIBatchRenderer with conditional font rendering methods - Update all widgets (Label, Button, TextField, etc.) for font modularity - FreeType dependency is now optional (only needed for SDF fonts) This enables building lightweight versions for playable ads and WeChat mini-games where package size is critical (<5MB).
1 parent 88061f4 commit d84c36a

14 files changed

Lines changed: 1179 additions & 77 deletions

CMakeLists.txt

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ option(ES_BUILD_EXAMPLES "Build examples" ON)
1212
option(ES_BUILD_TESTS "Build tests" ON)
1313
option(ES_BUILD_EDITOR "Build editor (native only)" OFF)
1414

15+
# Feature options (modular compilation)
16+
option(ES_FEATURE_SDF_FONT "Enable SDF font rendering (requires FreeType)" ON)
17+
option(ES_FEATURE_BITMAP_FONT "Enable bitmap font rendering (lightweight)" ON)
18+
1519
# Include custom CMake modules
1620
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
1721
include(ESEngineConfig)
@@ -41,7 +45,6 @@ set(ESENGINE_SOURCES
4145
# UI System
4246
src/esengine/ui/UIContext.cpp
4347
src/esengine/ui/rendering/UIBatchRenderer.cpp
44-
src/esengine/ui/font/SDFFont.cpp
4548
src/esengine/ui/layout/StackLayout.cpp
4649
src/esengine/ui/layout/WrapLayout.cpp
4750
src/esengine/ui/widgets/Widget.cpp
@@ -62,6 +65,15 @@ set(ESENGINE_SOURCES
6265
src/esengine/ui/docking/DockLayoutSerializer.cpp
6366
)
6467

68+
# Font sources (conditional)
69+
if(ES_FEATURE_SDF_FONT)
70+
list(APPEND ESENGINE_SOURCES src/esengine/ui/font/SDFFont.cpp)
71+
endif()
72+
73+
if(ES_FEATURE_BITMAP_FONT)
74+
list(APPEND ESENGINE_SOURCES src/esengine/ui/font/BitmapFont.cpp)
75+
endif()
76+
6577
set(ESENGINE_HEADERS
6678
src/esengine/ESEngine.hpp
6779
src/esengine/core/Types.hpp
@@ -111,7 +123,6 @@ set(ESENGINE_HEADERS
111123
src/esengine/ui/layout/Layout.hpp
112124
src/esengine/ui/layout/StackLayout.hpp
113125
src/esengine/ui/rendering/UIBatchRenderer.hpp
114-
src/esengine/ui/font/SDFFont.hpp
115126
src/esengine/ui/icons/Icons.hpp
116127
src/esengine/ui/widgets/Widget.hpp
117128
src/esengine/ui/widgets/Panel.hpp
@@ -133,6 +144,15 @@ set(ESENGINE_HEADERS
133144
src/esengine/ui/docking/DockLayoutSerializer.hpp
134145
)
135146

147+
# Font headers (conditional)
148+
if(ES_FEATURE_SDF_FONT)
149+
list(APPEND ESENGINE_HEADERS src/esengine/ui/font/SDFFont.hpp)
150+
endif()
151+
152+
if(ES_FEATURE_BITMAP_FONT)
153+
list(APPEND ESENGINE_HEADERS src/esengine/ui/font/BitmapFont.hpp)
154+
endif()
155+
136156
# Platform-specific sources
137157
if(ES_BUILD_WEB OR ES_BUILD_WXGAME)
138158
list(APPEND ESENGINE_SOURCES
@@ -244,8 +264,19 @@ if(NOT ES_BUILD_WEB AND NOT ES_BUILD_WXGAME)
244264
target_include_directories(esengine SYSTEM PRIVATE ${QUICKJS_INCLUDE_DIR})
245265
endif()
246266

247-
target_link_libraries(esengine PUBLIC glm freetype)
248-
target_include_directories(esengine PUBLIC ${CMAKE_SOURCE_DIR}/third_party/freetype/include)
267+
# Core dependencies
268+
target_link_libraries(esengine PUBLIC glm)
269+
270+
# FreeType dependency (only needed for SDF fonts)
271+
if(ES_FEATURE_SDF_FONT)
272+
target_link_libraries(esengine PUBLIC freetype)
273+
target_include_directories(esengine PUBLIC ${CMAKE_SOURCE_DIR}/third_party/freetype/include)
274+
target_compile_definitions(esengine PUBLIC ES_FEATURE_SDF_FONT=1)
275+
endif()
276+
277+
if(ES_FEATURE_BITMAP_FONT)
278+
target_compile_definitions(esengine PUBLIC ES_FEATURE_BITMAP_FONT=1)
279+
endif()
249280

250281
# Platform-specific settings
251282
if(ES_BUILD_WEB OR ES_BUILD_WXGAME)

src/esengine/ui/UIContext.cpp

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,17 @@
1414
#include "../events/Dispatcher.hpp"
1515
#include "../renderer/RenderCommand.hpp"
1616
#include "../renderer/RenderContext.hpp"
17-
#include "font/SDFFont.hpp"
1817
#include "rendering/UIBatchRenderer.hpp"
1918
#include "widgets/Widget.hpp"
2019

20+
#if ES_FEATURE_SDF_FONT
21+
#include "font/SDFFont.hpp"
22+
#endif
23+
24+
#if ES_FEATURE_BITMAP_FONT
25+
#include "font/BitmapFont.hpp"
26+
#endif
27+
2128
#include <glm/gtc/matrix_transform.hpp>
2229

2330
namespace esengine::ui {
@@ -55,7 +62,12 @@ void UIContext::shutdown() {
5562
if (!initialized_) return;
5663

5764
root_.reset();
65+
#if ES_FEATURE_SDF_FONT
5866
fonts_.clear();
67+
#endif
68+
#if ES_FEATURE_BITMAP_FONT
69+
bitmapFonts_.clear();
70+
#endif
5971
theme_.reset();
6072

6173
if (renderer_) {
@@ -107,9 +119,10 @@ void UIContext::setTheme(Unique<Theme> theme) {
107119
}
108120

109121
// =============================================================================
110-
// Font Management (SDF-based)
122+
// Font Management
111123
// =============================================================================
112124

125+
#if ES_FEATURE_SDF_FONT
113126
SDFFont* UIContext::loadFont(const std::string& name, const std::string& path, f32 fontSize,
114127
f32 sdfSpread) {
115128
auto font = SDFFont::create(path, fontSize, sdfSpread);
@@ -140,6 +153,36 @@ SDFFont* UIContext::getDefaultFont() {
140153
SDFFont* UIContext::getIconFont() {
141154
return getFont("icons");
142155
}
156+
#endif // ES_FEATURE_SDF_FONT
157+
158+
#if ES_FEATURE_BITMAP_FONT
159+
BitmapFont* UIContext::loadBitmapFont(const std::string& name, const std::string& atlasPath,
160+
const std::string& metricsPath) {
161+
auto font = BitmapFont::load(atlasPath, metricsPath);
162+
if (!font) {
163+
ES_LOG_ERROR("Failed to load bitmap font: {} / {}", atlasPath, metricsPath);
164+
return nullptr;
165+
}
166+
167+
BitmapFont* ptr = font.get();
168+
bitmapFonts_[name] = std::move(font);
169+
170+
ES_LOG_INFO("Loaded bitmap font '{}' from {}", name, atlasPath);
171+
return ptr;
172+
}
173+
174+
BitmapFont* UIContext::getBitmapFont(const std::string& name) {
175+
auto it = bitmapFonts_.find(name);
176+
if (it != bitmapFonts_.end()) {
177+
return it->second.get();
178+
}
179+
return nullptr;
180+
}
181+
182+
BitmapFont* UIContext::getDefaultBitmapFont() {
183+
return getBitmapFont(defaultFontName_);
184+
}
185+
#endif // ES_FEATURE_BITMAP_FONT
143186

144187
// =============================================================================
145188
// Update and Render

src/esengine/ui/UIContext.hpp

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,22 @@ class Dispatcher;
3333

3434
namespace ui {
3535

36+
#if ES_FEATURE_SDF_FONT
3637
class SDFFont;
38+
#endif
39+
40+
#if ES_FEATURE_BITMAP_FONT
41+
class BitmapFont;
42+
#endif
43+
3744
class UIBatchRenderer;
3845
class Widget;
3946

40-
// Alias for backward compatibility - Font now means SDFFont
47+
#if ES_FEATURE_SDF_FONT
4148
using Font = SDFFont;
49+
#elif ES_FEATURE_BITMAP_FONT
50+
using Font = BitmapFont;
51+
#endif
4252

4353
// =============================================================================
4454
// UIContext Class
@@ -136,42 +146,32 @@ class UIContext {
136146
const Theme& getTheme() const { return *theme_; }
137147

138148
// =========================================================================
139-
// Font Management (SDF-based)
149+
// Font Management
140150
// =========================================================================
141151

152+
#if ES_FEATURE_SDF_FONT
142153
/**
143154
* @brief Loads a font from file (uses SDF rendering)
144-
* @param name Name to register the font as
145-
* @param path Path to the TTF font file
146-
* @param fontSize SDF glyph size (recommended: 32-64)
147-
* @param sdfSpread SDF spread in pixels (default: 8)
148-
* @return Pointer to the loaded font or nullptr on failure
149155
*/
150156
SDFFont* loadFont(const std::string& name, const std::string& path, f32 fontSize = 48.0f,
151157
f32 sdfSpread = 8.0f);
152158

153-
/**
154-
* @brief Gets a loaded font by name
155-
* @param name Font name
156-
* @return Pointer to the font or nullptr if not found
157-
*/
158159
SDFFont* getFont(const std::string& name);
159-
160-
/**
161-
* @brief Gets the default font
162-
* @return Pointer to the default font or nullptr
163-
*/
164160
SDFFont* getDefaultFont();
165-
166-
/**
167-
* @brief Gets the icon font (Lucide icons)
168-
* @return Pointer to the icon font or nullptr
169-
*/
170161
SDFFont* getIconFont();
162+
#endif
171163

164+
#if ES_FEATURE_BITMAP_FONT
172165
/**
173-
* @brief Sets the default font name
166+
* @brief Loads a bitmap font from atlas and metrics files
174167
*/
168+
BitmapFont* loadBitmapFont(const std::string& name, const std::string& atlasPath,
169+
const std::string& metricsPath);
170+
171+
BitmapFont* getBitmapFont(const std::string& name);
172+
BitmapFont* getDefaultBitmapFont();
173+
#endif
174+
175175
void setDefaultFontName(const std::string& name) { defaultFontName_ = name; }
176176

177177
// =========================================================================
@@ -343,7 +343,14 @@ class UIContext {
343343
Unique<Widget> root_;
344344
Unique<Theme> theme_;
345345

346+
#if ES_FEATURE_SDF_FONT
346347
std::unordered_map<std::string, Unique<SDFFont>> fonts_;
348+
#endif
349+
350+
#if ES_FEATURE_BITMAP_FONT
351+
std::unordered_map<std::string, Unique<BitmapFont>> bitmapFonts_;
352+
#endif
353+
347354
std::string defaultFontName_ = "default";
348355

349356
u32 viewportWidth_ = 0;

src/esengine/ui/docking/DockTabBar.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,14 @@
1414
#include "DockPanel.hpp"
1515
#include "../UIContext.hpp"
1616
#include "../rendering/UIBatchRenderer.hpp"
17+
18+
#if ES_FEATURE_SDF_FONT
1719
#include "../font/SDFFont.hpp"
20+
#endif
21+
22+
#if ES_FEATURE_BITMAP_FONT
23+
#include "../font/BitmapFont.hpp"
24+
#endif
1825

1926
#include <cmath>
2027

@@ -166,12 +173,21 @@ void DockTabBar::renderTab(UIBatchRenderer& renderer, const DockTabInfo& tab, us
166173
tab.bounds.height
167174
};
168175

176+
#if ES_FEATURE_SDF_FONT
169177
SDFFont* font = ctx->getDefaultFont();
170178
if (font) {
171179
renderer.drawTextInBounds(tab.title, textBounds, *font,
172180
theme.typography.fontSizeSmall, textColor,
173181
HAlign::Left, VAlign::Center);
174182
}
183+
#elif ES_FEATURE_BITMAP_FONT
184+
BitmapFont* font = ctx->getDefaultBitmapFont();
185+
if (font) {
186+
renderer.drawTextInBounds(tab.title, textBounds, *font,
187+
theme.typography.fontSizeSmall, textColor,
188+
HAlign::Left, VAlign::Center);
189+
}
190+
#endif
175191

176192
if (tab.closable) {
177193
glm::vec4 closeColor = tab.closeHovered

0 commit comments

Comments
 (0)