Started work on Font Glyph Atlas
This commit is contained in:
parent
15d9d1265f
commit
20c40d87e4
11 changed files with 383 additions and 21 deletions
3
.clangd
3
.clangd
|
|
@ -1,2 +1,3 @@
|
|||
CompileFlags:
|
||||
CompilationDatabase: bin
|
||||
CompilationDatabase: bin
|
||||
Add: ["--target=x86_64-w64-mingw32"]
|
||||
|
|
@ -95,6 +95,7 @@ list(APPEND OGFX_SOURCE_FILES
|
|||
# render
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/render/BasicRenderer.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/render/PixelRenderer.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/render/FontGlyphAtlas.cpp
|
||||
|
||||
# resources
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/resources/Image.cpp
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
2056
|
||||
2057
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ namespace ogfx
|
|||
gfx.drawRoundRect({ getGlobalPosition(), getSize() }, m_borderColor, m_borderRadius, m_borderWidth);
|
||||
gfx.drawRoundRect({ getGlobalContentPosition(), m_checkSize }, getCheckBorderColor(), m_checkBorderRadius, m_checkBorderWidth);
|
||||
if (isChecked())
|
||||
gfx.fillRoundRect({ getGlobalContentPosition() + 5, m_checkSize - 10 }, getCheckBoxColor(), m_checkBorderRadius / 2);
|
||||
gfx.fillRoundRect({ getGlobalContentPosition() + 5, m_checkSize - 10 }, getCheckBoxColor(), m_checkBorderRadius / 2.0f);
|
||||
gfx.drawString(getText(), getGlobalContentPosition() + ostd::Vec2 { m_checkSize.x + m_spacing, 0 }, getTextColor(), getFontSize());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "BasicRenderer.hpp"
|
||||
#include "../gui/Window.hpp"
|
||||
#include "../resources/UbuntuMonoRegularTTF.hpp"
|
||||
#include "../gui/Window.hpp"
|
||||
|
||||
#define COLOR_CAST(ostd_color) std::bit_cast<SDL_FColor>(ostd_color.getNormalizedColor())
|
||||
#define QUAD_INDICES_ARR { 0, 1, 2, 2, 3, 0 }
|
||||
|
|
@ -60,10 +61,17 @@ namespace ogfx
|
|||
m_window = &window;
|
||||
if (m_initialized) return set_error_state(tErrors::NoError);
|
||||
init_arrays();
|
||||
loadDefaultFont(20);
|
||||
m_fontGlyphAtlas.init(*this);
|
||||
m_initialized = true;
|
||||
return set_error_state(tErrors::NoError);
|
||||
}
|
||||
|
||||
SDL_Renderer* BasicRenderer2D::getSDLRenderer(void) const
|
||||
{
|
||||
return m_window != nullptr ? m_window->getSDLRenderer() : nullptr;
|
||||
}
|
||||
|
||||
void BasicRenderer2D::flushBatch(void)
|
||||
{
|
||||
if (!m_initialized || m_vertexCount == 0)
|
||||
|
|
|
|||
|
|
@ -20,10 +20,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <ogfx/render/FontUtils.hpp>
|
||||
#include <ogfx/utils/Animation.hpp>
|
||||
#include <ostd/math/Geometry.hpp>
|
||||
#include <ostd/data/Color.hpp>
|
||||
#include <ogfx/resources/Image.hpp>
|
||||
#include <ostd/io/IOHandlers.hpp>
|
||||
#include <ogfx/render/FontGlyphAtlas.hpp>
|
||||
|
||||
namespace ogfx
|
||||
{
|
||||
|
|
@ -56,6 +58,7 @@ namespace ogfx
|
|||
BasicRenderer2D(void) = default;
|
||||
~BasicRenderer2D(void);
|
||||
int32_t init(WindowCore& window);
|
||||
SDL_Renderer* getSDLRenderer(void) const;
|
||||
void flushBatch(void);
|
||||
void endFrame(void);
|
||||
void pushClippingRect(const ostd::Rectangle& rect, bool additive = false);
|
||||
|
|
@ -70,11 +73,12 @@ namespace ogfx
|
|||
inline uint32_t getDrawCallCount(void) { return m_drawCallCount; }
|
||||
inline bool hasOpenFont(void) { return m_fontOpen; }
|
||||
inline TTF_Font* getSDLFont(void) { return m_font; }
|
||||
inline bool isValid(void) { return m_initialized && m_fontOpen && (m_font != nullptr || m_fontFromMemory); }
|
||||
inline bool isValid(void) const { return m_initialized && m_fontOpen && (m_font != nullptr || m_fontFromMemory); }
|
||||
inline int32_t geterrorState(void) { return m_errorState; }
|
||||
inline int32_t getFontSize(void) { return m_fontSize; }
|
||||
inline WindowCore& getWindow(void) { return *m_window; }
|
||||
inline bool isInitialized(void) { return m_initialized; }
|
||||
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 drawAnimation(const Animation& anim, const ostd::Vec2& position, const ostd::Vec2& size = { 0, 0 });
|
||||
|
|
@ -138,6 +142,7 @@ namespace ogfx
|
|||
int32_t m_errorState { tErrors::NoError };
|
||||
int32_t m_fontSize { DefaultFontSize };
|
||||
bool m_fontFromMemory { false };
|
||||
FontGlyphAtlas m_fontGlyphAtlas;
|
||||
|
||||
inline static constexpr int32_t DefaultFontSize { 16 };
|
||||
};
|
||||
|
|
|
|||
224
src/ogfx/render/FontGlyphAtlas.cpp
Normal file
224
src/ogfx/render/FontGlyphAtlas.cpp
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
OmniaFramework - A collection of useful functionality
|
||||
Copyright (C) 2025 OmniaX-Dev
|
||||
|
||||
This file is part of OmniaFramework.
|
||||
|
||||
OmniaFramework is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OmniaFramework is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OmniaFramework. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "FontGlyphAtlas.hpp"
|
||||
#include "BasicRenderer.hpp"
|
||||
|
||||
#define DEBUG(n) std::cout << (int)n << "\n";
|
||||
|
||||
namespace ogfx
|
||||
{
|
||||
FontGlyphAtlas FontGlyphAtlas::init(BasicRenderer2D& renderer)
|
||||
{
|
||||
m_renderer = &renderer;
|
||||
m_uvs.reserve(4096);
|
||||
for (int32_t i = 0; i < FontGlyphAtlas::MaxAtlasCount; i++)
|
||||
m_atlases[i] = nullptr;
|
||||
m_currentAtlasCount = 0;
|
||||
create_new_atlas();
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool FontGlyphAtlas::rasterize_glyph(const ostd::String& glyphStr, TTF_Font* font, uint32_t fontSize)
|
||||
{
|
||||
DEBUG(1);
|
||||
std::cout << (uint64_t)font << "\n";
|
||||
if (!font || m_currentAtlasCount <= 0)
|
||||
return false;
|
||||
|
||||
DEBUG(2);
|
||||
// 1. Extract codepoint from the ostd::String
|
||||
auto cps = glyphStr.getUTF8Codepoints();
|
||||
if (cps.size() != 1)
|
||||
return false; // must be exactly one character
|
||||
|
||||
DEBUG(3);
|
||||
uint32_t codepoint = cps[0];
|
||||
|
||||
// 2. Convert the ostd::String to UTF-8 for SDL_ttf
|
||||
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)
|
||||
return false;
|
||||
|
||||
DEBUG(4);
|
||||
int gw = surf->w;
|
||||
int gh = surf->h;
|
||||
|
||||
// 4. Get current atlas
|
||||
SDL_Texture* atlas = m_atlases[m_currentAtlasCount - 1];
|
||||
|
||||
// 5. Shelf packing: move to next row if needed
|
||||
if (m_penX + gw > int(AtlasTextureDimension))
|
||||
{
|
||||
m_penX = 0;
|
||||
m_penY += m_rowHeight;
|
||||
m_rowHeight = 0;
|
||||
}
|
||||
|
||||
// 6. If still doesn't fit → create new atlas
|
||||
if (m_penY + gh > int(AtlasTextureDimension))
|
||||
{
|
||||
SDL_DestroySurface(surf);
|
||||
|
||||
if (!create_new_atlas())
|
||||
return false; // no more atlases available
|
||||
|
||||
atlas = m_atlases[m_currentAtlasCount - 1];
|
||||
m_penX = 0;
|
||||
m_penY = 0;
|
||||
m_rowHeight = 0;
|
||||
}
|
||||
|
||||
DEBUG(5);
|
||||
// 7. Upload glyph bitmap into atlas
|
||||
SDL_Rect dstRect { m_penX, m_penY, gw, gh };
|
||||
SDL_UpdateTexture(atlas, &dstRect, surf->pixels, surf->pitch);
|
||||
SDL_DestroySurface(surf);
|
||||
|
||||
// 8. Compute UVs
|
||||
float u0 = float(m_penX) / float(AtlasTextureDimension);
|
||||
float v0 = float(m_penY) / float(AtlasTextureDimension);
|
||||
float u1 = float(m_penX + gw) / float(AtlasTextureDimension);
|
||||
float v1 = float(m_penY + gh) / float(AtlasTextureDimension);
|
||||
|
||||
GlyphUV uv;
|
||||
uv.atlas = atlas;
|
||||
uv.uvs[0] = { u0, v0 };
|
||||
uv.uvs[1] = { u1, v0 };
|
||||
uv.uvs[2] = { u1, v1 };
|
||||
uv.uvs[3] = { u0, v1 };
|
||||
|
||||
// 9. Store in hashmap
|
||||
GlyphKey key { codepoint, uint64_t(font), fontSize };
|
||||
m_uvs[key] = uv;
|
||||
|
||||
// 10. Advance shelf packing cursor
|
||||
m_penX += gw;
|
||||
m_rowHeight = std::max(m_rowHeight, gh);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FontGlyphAtlas::create_new_atlas(void)
|
||||
{
|
||||
// 1. Check if we can create another atlas
|
||||
if (m_currentAtlasCount >= int(MaxAtlasCount))
|
||||
return false;
|
||||
|
||||
if (!m_renderer)
|
||||
return false;
|
||||
|
||||
SDL_Renderer* sdlRenderer = m_renderer->getSDLRenderer();
|
||||
if (!sdlRenderer)
|
||||
return false;
|
||||
|
||||
// 2. Create the texture
|
||||
SDL_Texture* tex = SDL_CreateTexture(
|
||||
sdlRenderer,
|
||||
SDL_PIXELFORMAT_RGBA8888,
|
||||
SDL_TEXTUREACCESS_STREAMING,
|
||||
AtlasTextureDimension,
|
||||
AtlasTextureDimension
|
||||
);
|
||||
|
||||
if (!tex)
|
||||
return false;
|
||||
|
||||
// 3. Set blend mode (important for alpha glyphs)
|
||||
SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND);
|
||||
|
||||
// 4. Clear the texture to transparent
|
||||
{
|
||||
void* pixels = nullptr;
|
||||
int pitch = 0;
|
||||
if (SDL_LockTexture(tex, nullptr, &pixels, &pitch) == 0)
|
||||
{
|
||||
memset(pixels, 0, pitch * AtlasTextureDimension);
|
||||
SDL_UnlockTexture(tex);
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Store the atlas
|
||||
m_atlases[m_currentAtlasCount] = tex;
|
||||
m_currentAtlasCount++;
|
||||
|
||||
// 6. Reset packing cursor for this new atlas
|
||||
m_penX = 0;
|
||||
m_penY = 0;
|
||||
m_rowHeight = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FontGlyphAtlas::save_atlas_png(int atlasIndex, const char* filename)
|
||||
{
|
||||
if (atlasIndex < 0 || atlasIndex >= m_currentAtlasCount)
|
||||
return false;
|
||||
|
||||
SDL_Texture* tex = m_atlases[atlasIndex];
|
||||
if (!tex)
|
||||
return false;
|
||||
|
||||
// --- 1. Query texture properties (SDL3 way) ---
|
||||
SDL_PropertiesID props = SDL_GetTextureProperties(tex);
|
||||
if (!props)
|
||||
return false;
|
||||
|
||||
int width = (int)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_WIDTH_NUMBER, 0);
|
||||
int height = (int)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_HEIGHT_NUMBER, 0);
|
||||
Uint32 format = (Uint32)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_FORMAT_NUMBER, SDL_PIXELFORMAT_RGBA32);
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
return false;
|
||||
|
||||
// --- 2. Create a surface to receive the pixels ---
|
||||
SDL_Surface* surf = SDL_CreateSurface(width, height, SDL_PIXELFORMAT_RGBA32);
|
||||
if (!surf)
|
||||
return false;
|
||||
|
||||
// --- 3. Lock texture and copy pixels ---
|
||||
void* pixels = nullptr;
|
||||
int pitch = 0;
|
||||
|
||||
if (!SDL_LockTexture(tex, nullptr, &pixels, &pitch))
|
||||
{
|
||||
SDL_DestroySurface(surf);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy row-by-row (pitch may differ)
|
||||
uint8_t* dst = static_cast<uint8_t*>(surf->pixels);
|
||||
uint8_t* src = static_cast<uint8_t*>(pixels);
|
||||
|
||||
for (int y = 0; y < height; y++)
|
||||
memcpy(dst + y * surf->pitch, src + y * pitch, width * 4);
|
||||
|
||||
SDL_UnlockTexture(tex);
|
||||
|
||||
// --- 4. Save PNG ---
|
||||
bool ok = (IMG_SavePNG(surf, filename) == 0);
|
||||
|
||||
SDL_DestroySurface(surf);
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
84
src/ogfx/render/FontGlyphAtlas.hpp
Normal file
84
src/ogfx/render/FontGlyphAtlas.hpp
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
OmniaFramework - A collection of useful functionality
|
||||
Copyright (C) 2025 OmniaX-Dev
|
||||
|
||||
This file is part of OmniaFramework.
|
||||
|
||||
OmniaFramework is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OmniaFramework is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OmniaFramework. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ostd/string/String.hpp>
|
||||
#include <ostd/math/Geometry.hpp>
|
||||
#include <ogfx/utils/SDLInclude.hpp>
|
||||
|
||||
namespace ogfx
|
||||
{
|
||||
class BasicRenderer2D;
|
||||
class FontGlyphAtlas
|
||||
{
|
||||
public: struct GlyphUV
|
||||
{
|
||||
ostd::Vec2 uvs[4];
|
||||
SDL_Texture* atlas { nullptr };
|
||||
};
|
||||
struct GlyphKey
|
||||
{
|
||||
uint32_t codepoint;
|
||||
uint64_t fontID;
|
||||
uint32_t pixelSize;
|
||||
|
||||
bool operator==(const GlyphKey& other) const noexcept
|
||||
{
|
||||
return codepoint == other.codepoint &&
|
||||
fontID == other.fontID &&
|
||||
pixelSize == other.pixelSize;
|
||||
}
|
||||
};
|
||||
struct GlyphKeyHasher
|
||||
{
|
||||
inline size_t operator()(const GlyphKey& k) const noexcept
|
||||
{
|
||||
uint64_t v = 0;
|
||||
v |= uint64_t(k.codepoint);
|
||||
v |= uint64_t(k.fontID) << 32;
|
||||
v |= uint64_t(k.pixelSize) << 48;
|
||||
return std::hash<uint64_t>()(v);
|
||||
}
|
||||
};
|
||||
public:
|
||||
inline FontGlyphAtlas(void) { }
|
||||
inline FontGlyphAtlas(BasicRenderer2D& renderer) { init(renderer); }
|
||||
FontGlyphAtlas init(BasicRenderer2D& renderer);
|
||||
bool save_atlas_png(int atlasIndex, const char* filename);
|
||||
|
||||
public:
|
||||
bool rasterize_glyph(const ostd::String& glyphStr, TTF_Font* font, uint32_t fontSize);
|
||||
bool create_new_atlas(void);
|
||||
|
||||
public:
|
||||
inline static constexpr uint32_t AtlasTextureDimension { 8192 };
|
||||
inline static constexpr uint32_t MaxAtlasCount { 16 };
|
||||
|
||||
private:
|
||||
std::unordered_map<GlyphKey, GlyphUV, GlyphKeyHasher> m_uvs;
|
||||
SDL_Texture* m_atlases[FontGlyphAtlas::MaxAtlasCount];
|
||||
int32_t m_currentAtlasCount { 0 };
|
||||
BasicRenderer2D* m_renderer { nullptr };
|
||||
int32_t m_penX { 0 };
|
||||
int32_t m_penY { 0 };
|
||||
int32_t m_rowHeight { 0 };
|
||||
};
|
||||
}
|
||||
|
|
@ -646,7 +646,54 @@ namespace ostd
|
|||
return str;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> String::decodeUTF8(const ostd::String& s)
|
||||
{
|
||||
std::vector<uint32_t> out;
|
||||
const char* p = s.m_data.data();
|
||||
const char* end = p + s.m_data.size();
|
||||
|
||||
while (p < end)
|
||||
out.push_back(utf8_next(p, end));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
uint32_t String::utf8_next(const char*& p, const char* end)
|
||||
{
|
||||
uint8_t c = static_cast<uint8_t>(*p++);
|
||||
|
||||
// ASCII fast path
|
||||
if (c < 0x80)
|
||||
return c;
|
||||
|
||||
// 2-byte sequence
|
||||
if ((c >> 5) == 0x6) {
|
||||
uint32_t cp = (c & 0x1F) << 6;
|
||||
cp |= (static_cast<uint8_t>(*p++) & 0x3F);
|
||||
return cp;
|
||||
}
|
||||
|
||||
// 3-byte sequence
|
||||
if ((c >> 4) == 0xE) {
|
||||
uint32_t cp = (c & 0x0F) << 12;
|
||||
cp |= (static_cast<uint8_t>(*p++) & 0x3F) << 6;
|
||||
cp |= (static_cast<uint8_t>(*p++) & 0x3F);
|
||||
return cp;
|
||||
}
|
||||
|
||||
// 4-byte sequence
|
||||
if ((c >> 3) == 0x1E) {
|
||||
uint32_t cp = (c & 0x07) << 18;
|
||||
cp |= (static_cast<uint8_t>(*p++) & 0x3F) << 12;
|
||||
cp |= (static_cast<uint8_t>(*p++) & 0x3F) << 6;
|
||||
cp |= (static_cast<uint8_t>(*p++) & 0x3F);
|
||||
return cp;
|
||||
}
|
||||
|
||||
// Invalid byte → return replacement character
|
||||
return 0xFFFD;
|
||||
}
|
||||
|
||||
String operator+(const cpp_string& str1, const String& str)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ namespace ostd
|
|||
inline operator std::filesystem::path() const { return cpp_str(); }
|
||||
inline String& clr(void) { m_data = ""; return *this; }
|
||||
inline String& set(const cpp_string& str) { m_data = str; return *this; }
|
||||
inline std::vector<uint32_t> getUTF8Codepoints(void) const { return decodeUTF8(m_data); }
|
||||
|
||||
inline auto begin(void) { return m_data.begin(); }
|
||||
inline auto end(void) { return m_data.end(); }
|
||||
|
|
@ -174,9 +175,13 @@ namespace ostd
|
|||
static String getHexStr(uint64_t value, bool prefix = true, uint8_t nbytes = 1);
|
||||
static String getBinStr(uint64_t value, bool prefix = true, uint8_t nbytes = 1);
|
||||
static String duplicateChar(unsigned char c, uint16_t count);
|
||||
static std::vector<uint32_t> decodeUTF8(const ostd::String& s);
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, const String& val);
|
||||
|
||||
private:
|
||||
static uint32_t utf8_next(const char*& p, const char* end);
|
||||
|
||||
private:
|
||||
ostd::cpp_string m_data;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -30,20 +30,6 @@ class Window : public ogfx::gui::Window
|
|||
inline Window(void) { }
|
||||
inline void onInitialize(void) override
|
||||
{
|
||||
test.loadFromFile("./test.png", m_gfx);
|
||||
ogfx::Animation::AnimationData ad;
|
||||
ad.backwards = false;
|
||||
ad.columns = 9;
|
||||
ad.rows = 4;
|
||||
ad.frame_width = 256;
|
||||
ad.frame_height = 256;
|
||||
ad.length = 36;
|
||||
ad.random = false;
|
||||
ad.still = false;
|
||||
ad.speed = 0;
|
||||
m_anim.create(ad);
|
||||
m_anim.setSpriteSheet(test);
|
||||
|
||||
m_panel1.setSize(300, 140);
|
||||
m_panel1.setPosition(350, 50);
|
||||
m_panel1.setMousePressedCallback([&](const ogfx::gui::Event& event) -> void {
|
||||
|
|
@ -131,6 +117,9 @@ class Window : public ogfx::gui::Window
|
|||
|
||||
setTheme(m_theme);
|
||||
|
||||
m_gfx.getFontGlyphAtlas().rasterize_glyph("A", m_gfx.getSDLFont(), 30);
|
||||
m_gfx.getFontGlyphAtlas().save_atlas_png(0, "./atlas.png");
|
||||
|
||||
// std::cout << m_theme.get<ostd::String>("panel.titlebarType", "", {}, {}) << " \n";
|
||||
}
|
||||
|
||||
|
|
@ -167,8 +156,6 @@ class Window : public ogfx::gui::Window
|
|||
ogfx::gui::widgets::CheckBox m_check1 { *this };
|
||||
ostd::Stylesheet m_theme;
|
||||
ostd::Vec2 pos { 0, 0 };
|
||||
ogfx::Image test;
|
||||
ogfx::Animation m_anim;
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
|
|
|
|||
Loading…
Reference in a new issue