Added centralized SDL initialization

This commit is contained in:
OmniaX-Dev 2026-04-01 10:20:33 +02:00
parent 23e69bfdfc
commit f0f644102b
13 changed files with 189 additions and 53 deletions

1
other/TODO.txt Normal file
View file

@ -0,0 +1 @@
Add Color constants to ostd::Color

View file

@ -1 +1 @@
2040
2041

View file

@ -1,19 +0,0 @@
[0.2.1958]
Added ostd::OutputHandlerBase::tab() virtual function
Added ogfx::WindowBaseOutputHandler class
[0.2.1936]
Added JsonFile class to handle Json files
Added MidiParser class to parse Midi files
[0.2.1923]
Added MacOS support
[0.1.1823]
Added more Builtin signals
[0.1.1818]
Added ostd::String::fixedLength(...) method, with corresponding 'new_fixedLength' version.
Added "KeyboardController" class to <Console.hpp> (implemented in <Keyboard.cpp>) to handle
keypresses in the console in a cross-platform way
Added helper functions in ostd::Utils for dealing with raw arrays

View file

@ -20,15 +20,11 @@
#include "Window.hpp"
#include "../../ostd/utils/Time.hpp"
#include "io/IOHandlers.hpp"
#include "string/String.hpp"
#include <SDL2/SDL_render.h>
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_keycode.h>
#include <SDL3/SDL_mouse.h>
namespace ogfx
{
const Uint32 REDRAW_EVENT = SDL_RegisterEvents(1);
WindowCore::~WindowCore(void)
{
__on_window_destroy();
@ -36,21 +32,18 @@ namespace ogfx
SDL_DestroyCursor(m_cursor_Arrow);
SDL_DestroyRenderer(m_renderer);
SDL_DestroyWindow(m_window);
SDL_Quit();
TTF_Quit();
SDLSysten::release();
}
void WindowCore::initialize(int32_t width, int32_t height, const ostd::String& title)
{
if (m_initialized) return;
SDLSysten::acquire();
m_windowWidth = width;
m_windowHeight = height;
m_title = title;
if (!SDL_Init(SDL_INIT_VIDEO))
{
printf( "SDL could not initialize! Error: %s\n", SDL_GetError() );
exit(1);
}
setBlockingEventsRefreshFPS(DefaultBlockingEventsFPS);
m_window = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SDL_WINDOW_RESIZABLE);
m_renderer = SDL_CreateRenderer(m_window, nullptr);
SDL_SetWindowMinimumSize(m_window, m_windowWidth, m_windowHeight);
@ -60,6 +53,13 @@ namespace ogfx
m_cursor_Arrow = SDL_CreateSystemCursor(SDL_SystemCursor::SDL_SYSTEM_CURSOR_DEFAULT);
m_cursor_IBeam = SDL_CreateSystemCursor(SDL_SystemCursor::SDL_SYSTEM_CURSOR_TEXT);
m_wout.attachWindow(*this);
m_wout.setFontSize(22);
m_wout.setConsoleMaxCharacters({ 1000, 1000 });
m_wout.setConsolePosition({ 5, 5 });
m_wout.setWrapMode(ogfx::GraphicsWindowOutputHandler::eWrapMode::NewLine);
m_wout.setDefaultForegroundColor({ 255, 255, 255, 255 });
m_initialized = true;
m_running = true;
@ -81,6 +81,12 @@ namespace ogfx
__on_window_init(width, height, title);
}
void WindowCore::mainLoop(void)
{
if (isInitialized())
__main_loop();
}
void WindowCore::close(void)
{
__on_window_close();
@ -136,6 +142,24 @@ namespace ogfx
SDL_DestroySurface(appIcon);
}
void WindowCore::setBlockingEventsRefreshFPS(uint32_t fps)
{
if (fps == 0 || fps > MaxBlockingEventsFPS)
{
setBlockingEventsRefreshFPS(DefaultBlockingEventsFPS);
return;
}
m_blockingEventsDelay = static_cast<int>(std::floor((1.0 / (double)fps) * 1000));
}
void WindowCore::requestRedraw(void)
{
SDL_Event e{};
SDL_zero(e);
e.type = REDRAW_EVENT;
SDL_PushEvent(&e);
}
MouseEventData WindowCore::get_mouse_state(void)
{
float mx = 0, my = 0;
@ -159,7 +183,7 @@ namespace ogfx
if (isBlockingEventsEnabled())
{
if (SDL_WaitEventTimeout(&event, 16))
if (SDL_WaitEventTimeout(&event, m_blockingEventsDelay))
__handle_event(event);
}
else
@ -169,9 +193,26 @@ namespace ogfx
}
}
void WindowCore::before_render(void)
{
SDL_SetRenderDrawColor(m_renderer, getClearColor().r, getClearColor().g, getClearColor().b, getClearColor().a);
if (m_refreshScreen)
SDL_RenderClear(m_renderer);
wout().beginFrame();
}
void WindowCore::after_render(void)
{
SDL_RenderPresent(m_renderer);
}
void WindowCore::__handle_event(SDL_Event& event)
{
if (event.type == SDL_EVENT_QUIT)
if (event.type == REDRAW_EVENT)
{
//Doesn't need to do anything, the event exists just to make SDL_WaitEventTimeout() return early
}
else if (event.type == SDL_EVENT_QUIT)
{
close();
}
@ -254,13 +295,11 @@ namespace ogfx
void GraphicsWindow::__main_loop(void)
{
handle_events();
SDL_SetRenderDrawColor(m_renderer, getClearColor().r, getClearColor().g, getClearColor().b, getClearColor().a);
if (m_refreshScreen)
SDL_RenderClear(m_renderer);
before_render();
m_fixedUpdateTImer.update();
onUpdate();
onRender();
SDL_RenderPresent(m_renderer);
after_render();
m_frameTimeAcc += m_fpsUpdateClock.restart(ostd::eTimeUnits::Seconds);
m_frameCount++;
m_fpsUpdateTimer.update();
@ -299,10 +338,10 @@ namespace ogfx
while (isRunning())
{
handle_events();
SDL_SetRenderDrawColor(m_renderer, getClearColor().r, getClearColor().g, getClearColor().b, getClearColor().a);
SDL_RenderClear(m_renderer);
before_render();
onRedraw(m_gfx);
m_gfx.drawString("Hello World", { 100, 100 }, { 255, 0, 0 });
SDL_RenderPresent(m_renderer);
after_render();
}
}

View file

@ -20,13 +20,13 @@
#pragma once
#include <SDL3/SDL_events.h>
#include <ogfx/utils/SDLInclude.hpp>
#include <ostd/utils/Signals.hpp>
#include <ostd/utils/Time.hpp>
#include <ostd/io/IOHandlers.hpp>
#include <ogfx/gui/Events.hpp>
#include <ogfx/render/BasicRenderer.hpp>
#include <ogfx/gui/WindowOutputHandler.hpp>
namespace ogfx
{
@ -38,13 +38,15 @@ namespace ogfx
virtual ~WindowCore(void);
inline WindowCore(int32_t width, int32_t height, const ostd::String& title) { initialize(width, height, title); }
void initialize(int32_t width, int32_t height, const ostd::String& title);
inline void mainLoop(void) { if (isInitialized()) __main_loop(); }
void mainLoop(void);
void close(void);
void setSize(int32_t width, int32_t height);
void setTitle(const ostd::String& title);
void setCursor(eCursor cursor);
void enableResizable(bool enable = true);
void setIcon(const ostd::String& iconFilePath);
void setBlockingEventsRefreshFPS(uint32_t fps);
void requestRedraw(void);
inline bool isInitialized(void) const { return m_initialized; }
inline bool isRunning(void) const { return m_running; }
@ -60,10 +62,14 @@ namespace ogfx
inline SDL_Renderer* getSDLRenderer(void) { return m_renderer; }
inline void enableBlockingEvents(bool enable = true) { m_blockingEvents = enable; }
inline bool isBlockingEventsEnabled(void) const { return m_blockingEvents; }
inline ostd::ConsoleOutputHandler& out(void) { return m_out; }
inline GraphicsWindowOutputHandler& wout(void) { return m_wout; }
protected:
MouseEventData get_mouse_state(void);
virtual void handle_events(void);
virtual void before_render(void);
virtual void after_render(void);
inline virtual void __on_event(SDL_Event& event) { }
inline virtual void __on_window_init(int32_t width, int32_t height, const ostd::String& title) { }
inline virtual void __on_window_destroy(void) { }
@ -76,6 +82,8 @@ namespace ogfx
protected:
SDL_Window* m_window { nullptr };
SDL_Renderer* m_renderer { nullptr };
ostd::ConsoleOutputHandler m_out;
GraphicsWindowOutputHandler m_wout;
private:
ostd::Color m_clearColor { 10, 10, 10, 255 };
@ -83,15 +91,21 @@ namespace ogfx
int32_t m_windowWidth { 0 };
int32_t m_windowHeight { 0 };
ostd::String m_title { "" };
int32_t m_blockingEventsDelay { 33 };
bool m_running { false };
bool m_initialized { false };
bool m_visible { true };
bool m_blockingEvents { false };
bool m_resizeable { true };
bool m_refreshScreen { true };
SDL_Cursor* m_cursor_IBeam { nullptr };
SDL_Cursor* m_cursor_Arrow { nullptr };
public:
inline static constexpr int32_t MaxBlockingEventsFPS { 240 };
inline static constexpr int32_t DefaultBlockingEventsFPS { 30 };
};
class GraphicsWindow : public WindowCore
{
@ -124,7 +138,6 @@ namespace ogfx
ostd::Timer m_fpsUpdateClock;
uint64_t m_frameTimeAcc { 0 };
int32_t m_frameCount { 0 };
bool m_refreshScreen { true };
};
namespace gui
{
@ -139,6 +152,7 @@ namespace ogfx
inline virtual void onDestroy(void) { }
inline virtual void onClose(void) { }
inline virtual void onSDLEvent(SDL_Event& event) { }
inline virtual void onRedraw(BasicRenderer2D& gfx) { }
protected:
void __on_window_init(int32_t width, int32_t height, const ostd::String& title) override;
@ -148,8 +162,7 @@ namespace ogfx
void __main_loop(void) override;
private:
ogfx::BasicRenderer2D m_gfx;
ostd::ConsoleOutputHandler m_out;
BasicRenderer2D m_gfx;
};
}
}

View file

@ -26,6 +26,7 @@ namespace ogfx
{
using namespace ostd;
GraphicsWindowOutputHandler::GraphicsWindowOutputHandler(void)
{
}

View file

@ -23,6 +23,24 @@
namespace ogfx
{
TTFRenderer::SignalHandler::SignalHandler(TTFRenderer& parent) : m_parent(parent)
{
enableSignals();
connectSignal(ostd::tBuiltinSignals::BeforeSDLShutdown);
setTypeName("ostd::GraphicsWindowOutputHandler::SignalHandler");
validate();
}
void TTFRenderer::SignalHandler::handleSignal(ostd::tSignal& signal)
{
if (signal.ID == ostd::tBuiltinSignals::BeforeSDLShutdown)
{
m_parent.closeFont();
}
}
TTFRenderer::~TTFRenderer(void)
{
closeFont();
@ -179,12 +197,6 @@ namespace ogfx
{
if (TTFRenderer::m_initialized) return set_error_state(tErrors::NoError);
if (renderer == nullptr) return set_error_state(tErrors::NullRenderer);
if (!TTF_Init())
{
print_ttf_error("TTF_Init");
SDL_Quit();
return set_error_state(tErrors::FailedToLoad);
}
m_renderer = renderer;
TTFRenderer::m_initialized = true;
return set_error_state(tErrors::NoError);

View file

@ -28,6 +28,15 @@ namespace ogfx
{
class TTFRenderer
{
private: class SignalHandler : public ostd::BaseObject
{
public:
SignalHandler(TTFRenderer& parent);
void handleSignal(ostd::tSignal& signal) override;
private:
TTFRenderer& m_parent;
};
public: struct tErrors
{
inline static constexpr int32_t NoError = 0;
@ -68,6 +77,7 @@ namespace ogfx
private:
ostd::ConsoleOutputHandler m_out;
SignalHandler m_sigHndl { *this };
bool m_initialized { false };
bool m_fontOpen { false };
TTF_Font* m_font { nullptr };

View file

@ -21,6 +21,8 @@
#pragma once
#include <ostd/utils/Defines.hpp>
#include <ostd/io/Logger.hpp>
#include <ostd/utils/Signals.hpp>
#include <SDL3/SDL.h>
#include <ogfx/vendor/sdl3_gfx/SDL3_gfxPrimitives.h>
@ -29,3 +31,55 @@
#include <SDL3/SDL_surface.h>
#include <SDL3/SDL_rect.h>
#include <SDL3/SDL_render.h>
namespace ogfx
{
class SDLSysten
{
public:
static inline void acquire(void)
{
if (s_refCount == 0)
init_sdl();
s_refCount++;
}
static inline void release(void)
{
s_refCount--;
if (s_refCount == 0)
shutdown_sdl();
}
private:
static inline void init_sdl(void)
{
if (!SDL_Init(SDL_INIT_VIDEO))
{
OX_FATAL("SDL could not initialize! Error: %s\n", SDL_GetError());
exit(ErrorSDLInitFailed);
}
if (!TTF_Init())
{
OX_FATAL("SDL_ttf could not initialize! Error: %s\n", SDL_GetError());
SDL_Quit();
exit(ErrorSDLTTFInitFailed);
}
}
static inline void shutdown_sdl(void)
{
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::BeforeSDLShutdown, ostd:: tSignalPriority::RealTime);
TTF_Quit();
SDL_Quit();
}
private:
inline static int s_refCount { 0 };
public:
inline static constexpr int32_t ErrorSDLInitFailed { 1 };
inline static constexpr int32_t ErrorSDLTTFInitFailed { 2 };
};
}

View file

@ -45,3 +45,11 @@
#include <ostd/utils/Signals.hpp>
#include <ostd/utils/Time.hpp>
namespace ostd
{
inline void initialize(void)
{
ostd::SignalHandler::init(true);
}
}

View file

@ -31,6 +31,8 @@ namespace ostd
SignalHandler::m_delegatedSignals.reserve(SignalHandler::__DELEGATED_SIGNALS_BUFFER_START_SIZE);
SignalHandler::m_onGuiEventRecievers.clear();
SignalHandler::m_onGuiEventRecievers.reserve(SignalHandler::__SIGNAL_BUFFER_START_SIZE);
SignalHandler::m_beforeSDLShutdownRecievers.clear();
SignalHandler::m_beforeSDLShutdownRecievers.reserve(SignalHandler::__SIGNAL_BUFFER_START_SIZE);
m_initialized = true;
}
@ -71,6 +73,8 @@ namespace ostd
sig_list = &m_windowClosedRecievers;
else if (signal_id == tBuiltinSignals::OnGuiEvent)
sig_list = &m_onGuiEventRecievers;
else if (signal_id == tBuiltinSignals::BeforeSDLShutdown)
sig_list = &m_beforeSDLShutdownRecievers;
else if (signal_id > tBuiltinSignals::CustomSignalBase)
sig_list = &m_customRecievers;
if (sig_list == nullptr)
@ -110,6 +114,8 @@ namespace ostd
m_windowClosedRecievers.push_back({ &object, signal_id });
else if (signal_id == tBuiltinSignals::OnGuiEvent)
m_onGuiEventRecievers.push_back({ &object, signal_id });
else if (signal_id == tBuiltinSignals::BeforeSDLShutdown)
m_beforeSDLShutdownRecievers.push_back({ &object, signal_id });
else if (signal_id > tBuiltinSignals::CustomSignalBase)
m_customRecievers.push_back({ &object, signal_id });
else

View file

@ -45,6 +45,8 @@ namespace ostd
inline static constexpr uint32_t OnGuiEvent = 0x2001;
inline static constexpr uint32_t BeforeSDLShutdown = 0x3001;
inline static constexpr uint32_t WindowResized = 0x1001;
inline static constexpr uint32_t WindowClosed = 0x1002;
/*********************/
@ -106,6 +108,7 @@ namespace ostd
inline static std::vector<tSignalObjPair> m_windowResizedRecievers;
inline static std::vector<tSignalObjPair> m_windowClosedRecievers;
inline static std::vector<tSignalObjPair> m_onGuiEventRecievers;
inline static std::vector<tSignalObjPair> m_beforeSDLShutdownRecievers;
/************************************/
inline static constexpr uint16_t __SIGNAL_BUFFER_START_SIZE { 128 };

View file

@ -34,6 +34,8 @@
* ListBox
* ComboBox
* TreeView
* Save/Open File Dialogs (and folder dialogs)
* Tab Panel
*/
#include <ogfx/ogfx.hpp>
@ -58,11 +60,17 @@ class Window : public ogfx::gui::Window
}
}
void onRedraw(ogfx::BasicRenderer2D& gfx) override
{
wout().fg(ostd::Color { 255, 0, 0 }).p("Hello ").fg(ostd::Color { 0, 0, 255 }).p("World");
}
private:
};
int main(int argc, char** argv)
{
ostd::initialize();
Window window;
window.initialize(800, 600, "OmniaFramework - Test Window");
window.setClearColor({ 0, 0, 0 });