From ab09e026b25932e41f3e5bc00cdaffc5a52c2468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C4=83t=C4=83lin=20Gabriel=20Dr=C4=83ghi=C8=9B=C4=83?= Date: Fri, 15 May 2026 13:49:47 +0200 Subject: [PATCH 1/4] Refactor WIP --- include/app/app.h | 18 ++- include/bgem_defaults.h | 19 +++ include/core/debug.h | 40 +++++++ include/core/frame_limiter.h | 59 ++++++++++ include/core/path.h | 32 ++++++ include/core/timer.h | 19 +++ include/platform/platform_egl.h | 48 +++++++- include/platform/platform_init.h | 19 ++- include/platform/platform_window.h | 15 ++- include/renderer/render_loop.h | 23 +++- include/renderer/renderer.h | 61 +++++++++- include/renderer/shader.h | 13 --- include/shader/shader.h | 41 +++++++ include/shader/shader_catalog.h | 20 ++++ include/system/config.h | 32 ++++++ include/system/display.h | 7 +- include/system/system.h | 17 ++- include/window/window.h | 66 +++++++++-- source/CMakeLists.txt | 12 +- source/app/app.c | 19 ++- source/core/CMakeLists.txt | 14 +++ source/{debug_tools => core}/debug.cpp | 0 source/core/frame_limiter.c | 47 ++++++++ .../imgui_backends/CMakeLists.txt | 0 .../imgui_backends/imgui_impl_opengl3.cpp | 0 .../imgui_backends/imgui_impl_opengl3.h | 0 .../imgui_impl_opengl3_loader.h | 0 .../imgui_backends/imgui_impl_sdl3.cpp | 0 .../imgui_backends/imgui_impl_sdl3.h | 0 source/core/path.c | 17 +++ source/core/timer.c | 11 ++ source/debug_tools/CMakeLists.txt | 11 -- source/platform/linux/platform_egl_linux.c | 5 +- source/renderer/CMakeLists.txt | 7 -- source/renderer/render_loop.c | 108 ++++-------------- source/renderer/renderer.c | 56 ++++----- source/shader/CMakeLists.txt | 16 +++ source/{renderer => shader}/shader.c | 50 ++++++-- source/shader/shader_catalog.c | 15 +++ source/system/CMakeLists.txt | 1 + source/system/config.c | 18 +++ source/system/system.c | 6 +- source/window/window.c | 36 ++++-- 43 files changed, 798 insertions(+), 200 deletions(-) create mode 100644 include/bgem_defaults.h create mode 100644 include/core/frame_limiter.h create mode 100644 include/core/path.h create mode 100644 include/core/timer.h delete mode 100644 include/renderer/shader.h create mode 100644 include/shader/shader.h create mode 100644 include/shader/shader_catalog.h create mode 100644 include/system/config.h create mode 100644 source/core/CMakeLists.txt rename source/{debug_tools => core}/debug.cpp (100%) create mode 100644 source/core/frame_limiter.c rename source/{debug_tools => core}/imgui_backends/CMakeLists.txt (100%) rename source/{debug_tools => core}/imgui_backends/imgui_impl_opengl3.cpp (100%) rename source/{debug_tools => core}/imgui_backends/imgui_impl_opengl3.h (100%) rename source/{debug_tools => core}/imgui_backends/imgui_impl_opengl3_loader.h (100%) rename source/{debug_tools => core}/imgui_backends/imgui_impl_sdl3.cpp (100%) rename source/{debug_tools => core}/imgui_backends/imgui_impl_sdl3.h (100%) create mode 100644 source/core/path.c create mode 100644 source/core/timer.c delete mode 100644 source/debug_tools/CMakeLists.txt create mode 100644 source/shader/CMakeLists.txt rename source/{renderer => shader}/shader.c (56%) create mode 100644 source/shader/shader_catalog.c create mode 100644 source/system/config.c diff --git a/include/app/app.h b/include/app/app.h index 850caa9..a85519c 100644 --- a/include/app/app.h +++ b/include/app/app.h @@ -6,6 +6,20 @@ #ifndef APP_H #define APP_H -int bgem_app_init(void); +#include "system/config.h" -#endif // APP_H +/** + * @brief + * Run the application. + * + * @param[in] cfg + * Struct containing the settings + * + * @return + * EXIT_SUCCESS if all the shutdown and clean up routines have been + * completed. EXIT_FAILURE if an error occurred in the middle of + * execution. + */ +int bgem_app_run(bgem_config* cfg); + +#endif /* APP_H */ diff --git a/include/bgem_defaults.h b/include/bgem_defaults.h new file mode 100644 index 0000000..b93bf04 --- /dev/null +++ b/include/bgem_defaults.h @@ -0,0 +1,19 @@ +/* + * MIT License + * Copyright (c) 2026 Cătălin Gabriel Drăghiță + */ + +#ifndef BGEM_DEFAULTS_H +#define BGEM_DEFAULTS_H + +/* Rendering */ +#define BGEM_DEFAULT_RENDER_WIDTH 1920 +#define BGEM_DEFAULT_RENDER_HEIGHT 1080 + +/* Frame pacing */ +#define BGEM_DEFAULT_FRAME_LIMIT 60 + +/* Window mode */ +#define BGEM_DEFAULT_WINDOW_MODE 0 /* 0 - Windowed | 1 - Borderless */ + +#endif /* BGEM_DEFAULTS_H */ diff --git a/include/core/debug.h b/include/core/debug.h index 7e27233..cfdd19a 100644 --- a/include/core/debug.h +++ b/include/core/debug.h @@ -20,11 +20,51 @@ extern "C" { #endif +/** + * @brief + * Initialize the Imgui debug UI + * + * @param[in] window + * The window created by SDL. Must be the main Bluegem window + * + */ void bgem_debug_init(SDL_Window *window); + +/** + * @brief + * Destroy the Imgui context + * + * Must be called after bgem_debug_init() + */ void bgem_debug_shutdown(void); + +/** + * @brief + * On/Off switch to show the UI or not + */ void bgem_debug_toggle(void); + +/** + * @brief + * Show the UI + * + * PROTOTYPE! Just displays Hello world + */ void bgem_debug_newFrame(void); + +/** + * @brief + * Render the debug UI + */ void bgem_debug_render(void); + +/** + * @brief + * Returns the status set by bgem_debug_toggle() + * + * @return + * TRUE if enabled. FALSE if disabled. + */ int bgem_debug_isActive(void); #ifdef __cplusplus diff --git a/include/core/frame_limiter.h b/include/core/frame_limiter.h new file mode 100644 index 0000000..2b32ac9 --- /dev/null +++ b/include/core/frame_limiter.h @@ -0,0 +1,59 @@ +/* + * MIT License + * Copyright (c) 2026 Cătălin Gabriel Drăghiță + */ + +#ifndef FRAME_LIMITER_H +#define FRAME_LIMITER_H + +#include + +typedef struct { + Uint32 target_fps; + double frame_budget; /* seconds per frame (1.0 / target_fps) */ + double app_start; /* timestamp at limiter init */ + double frame_start; /* timestamp at last bgem_frame_limiter_begin() */ + float dt_ms; /* actual duration of the previous frame */ + double elapsed; /* seconds since app_start */ +} bgem_frame_limiter; + +/** + * @brief + * Initialize the frame limiter. + * + * @param[out] fl + * Fill in the struct members. + * + * @param[in] target_fps + * The framerate number to not go above. + */ +void bgem_frame_limiterInit(bgem_frame_limiter *fl, Uint32 target_fps); + +/** + * @brief + * The beginning of the frame. + * + * Placed at the start of the rendering pipepline. It will create a reference point + * to compare to when bgem_frame_limiterEnd() is called. + * + * A `BGEM_MAX_DT_SECONDS` of 100ms is used to avoid comparing big time differences + * bugs after suspend or debug breaks. + * + * @param[in, out] fl + * The struct that contains the current frame time information. + */ +void bgem_frame_limiterBegin(bgem_frame_limiter *fl); + +/** + * @brief + * The end of the frame. + * + * Placed at the end of the rendering pipeline. It will compare with the information + * set from bgem_frame_limiterBegin(), and sleep until it reaches the frame time. + * + * @param[in] fl + * The struct that contains the frame time to compare to. + */ +void bgem_frame_limiterEnd(bgem_frame_limiter *fl); + +#endif /* FRAME_LIMITER_H */ diff --git a/include/core/path.h b/include/core/path.h new file mode 100644 index 0000000..05274f4 --- /dev/null +++ b/include/core/path.h @@ -0,0 +1,32 @@ +/* + * MIT License + * Copyright (c) 2026 Cătălin Gabriel Drăghiță + */ + +#include +#include + +#ifndef PATH_H +#define PATH_H + +/** + * @brief + * Converts the relative path into full path + * + * @param[out] out + * Where to store the full path + * + * @param[in] size + * Size of the character buffer where to store the + * full path + * + * @param[in] relative_path + * The relative path + * + * @return + * FALSE if the output is bigger than the buffer (size). + * TRUE if the output fits in the buffer. + */ +bool bgem_path_relativeToFull(char *out, size_t size, const char *relative_path); + +#endif /* PATH_H */ diff --git a/include/core/timer.h b/include/core/timer.h new file mode 100644 index 0000000..8c86757 --- /dev/null +++ b/include/core/timer.h @@ -0,0 +1,19 @@ +/* + * MIT License + * Copyright (c) 2026 Cătălin Gabriel Drăghiță + */ + +#ifndef TIMER_H +#define TIMER_H + +/** + * @brief + * High precision timer in seconds. + * + * @return + * Time elapsed in seconds. Integer part is the whole seconds, + * and the fractional part are the subsecond reminder. + */ +double bgem_timer_seconds(void); + +#endif /* TIMER_H */ diff --git a/include/platform/platform_egl.h b/include/platform/platform_egl.h index 1b284d9..2b22744 100644 --- a/include/platform/platform_egl.h +++ b/include/platform/platform_egl.h @@ -15,9 +15,55 @@ typedef struct bgem_platform_windowContext bgem_platform_windowContext; /* Create graphics context attached to SDL window */ + +/** + * @brief + * Create an EGL context and attach it to the provided window. + * + * @param[in] window + * The window created by SDL to attatch the EGL context. + * + * @return + * Returns a struct with all the members initialized, ready to be controlled + * by future EGL calls. NULL if a failure occurred. + */ bgem_platform_windowContext* bgem_platform_createContext(SDL_Window *window); + +/** + * @brief + * Call EGL's swap buffer function. + * + * @param[in] platformContext + * The valid window context structure to read from and execute the EGL's swap + * buffer function. + */ void bgem_platform_swapBuffers(bgem_platform_windowContext *platformContext); + +/** + * @brief + * Resize the context created by the Wayland compositor + * + * @param[in] platformContext + * If the window context has a non-null wl_win member, it will be read by the + * Wayland specific function and apply it to the appropriate context to resize. + * + * @param[in] w + * Width in pixels + * + * @param[in] h + * Height in pixels + */ void bgem_platform_waylandResizeSurface(bgem_platform_windowContext *platformContext, int w, int h); + +/** + * @brief + * Destroy the context. + * + * Must be called after a successful bgem_platform_createContext() + * + * @param[in] platformContext + * The struct to clear up. + */ void bgem_platform_destroyContext(bgem_platform_windowContext *platformContext); -#endif //PLATFORM_EGL_H +#endif /* PLATFORM_EGL_H */ diff --git a/include/platform/platform_init.h b/include/platform/platform_init.h index 3f0a6a1..07c72db 100644 --- a/include/platform/platform_init.h +++ b/include/platform/platform_init.h @@ -12,7 +12,24 @@ typedef enum { BGEM_INSTANCE_LOCK_ERROR, } bgem_instance_lockStatus; +/** + * @brief + * Lock the instance so only one at a time can be opened + * + * @return + * `BGEM_INSTANCE_LOCK_OK` if the lock has been executed successfully. + * `BGEM_INSTANCE_LOCK_ALREADY_RUNNING` if the new instance detects + * there is already another one opened, and `BGEM_INSTANCE_LOCK_ERROR` + * if the instance lock could not be set. + */ bgem_instance_lockStatus bgem_platform_instanceLock(void); + +/** + * @brief + * Unlock the instance. + * + * This is done during termination and cleanup procedures. + */ void bgem_platform_instanceUnlock(void); -#endif // PLATFORM_INIT_H +#endif /* PLATFORM_INIT_H */ diff --git a/include/platform/platform_window.h b/include/platform/platform_window.h index 7641e48..e984563 100644 --- a/include/platform/platform_window.h +++ b/include/platform/platform_window.h @@ -6,6 +6,19 @@ #ifndef PLATFORM_WINDOW_H #define PLATFORM_WINDOW_H +/** + * @brief + * Brings the window forward. + * + * This only works in Windows. macOS already handles this with Launch + * Services. Wayland cannot control window status for now. + * + * NOTE: This is paired with the instance locking mechanism, hence the + * MessageBox in Linux will warn about the windows being "already opened" + * which is not really consistent with what the function is intended to do, + * at least on Linux + * + */ void bgem_platform_windowBringForward(void); -#endif // PLATFORM_WINDOW_H +#endif /* PLATFORM_WINDOW_H */ diff --git a/include/renderer/render_loop.h b/include/renderer/render_loop.h index f9251af..23d3ea9 100644 --- a/include/renderer/render_loop.h +++ b/include/renderer/render_loop.h @@ -7,7 +7,26 @@ #define RENDER_LOOP_H #include "window/window.h" +#include "system/config.h" -int bgem_renderer_loop(bgem_window_handle *wh); +/** + * @brief + * Makes everything move. + * + * TODO: The funcion name might not match the intended purpose. + * + * TODO: A failure return value is missing. + * + * @param[in] wh + * The window to control in the loop. Sends commands to the window and + * the context inside it. + * + * @param[in] cfg + * The struct with the current program configuration. + * + * @return + * EXIT_SUCCESS when the loop is ended. + */ +int bgem_renderer_loop(bgem_window_handle *wh, bgem_config *cfg); -#endif // RENDER_LOOP_H +#endif /* RENDER_LOOP_H */ diff --git a/include/renderer/renderer.h b/include/renderer/renderer.h index af4c6d8..dea1516 100644 --- a/include/renderer/renderer.h +++ b/include/renderer/renderer.h @@ -7,11 +7,66 @@ #define RENDERER_H #include "window/window.h" +#include "system/config.h" +/** + * @brief + * Sets a new client area size to compute the viewport area + * + * @param[in] w + * Width in pixels + * + * @param[in] h + * Height in pixels + */ void bgem_renderer_setWindowSize(int w, int h); -void bgem_renderer_init(void); + +/** + * @brief + * Initialization routine for rendering + * + * Loads shaders, creates the FBO, the fullscreen triangle, and the blit + * shader. + * + * @param[in] cfg + * Reads the interal resolution settings + */ +void bgem_renderer_init(bgem_config *cfg); + +/** + * @brief + * Perform the rendering. + * + * @param[in] time + * Time elapsed for time dependent shader animations. + */ void bgem_renderer_render(float time); -void bgem_renderer_present(int window_width, int window_height); + +/** + * @brief + * Draw the current FBO to the blit shader + */ +void bgem_renderer_present(void); + +/** + * @brief + * Swap buffers + * + * @param[in] ctx + * Send the buffer swap to the context + */ void bgem_renderer_swap(bgem_platform_windowContext *ctx); -#endif +/** + * @brief + * Destroy all the shaders. + * + * Call this after `bgem_renderer_init()` + * + * TODO: Shaders are created by bgem_renderer_init() because it calls bgem_shader_loadAll(). + * bgem_renderer_destroyAllShaders() calls bgem_shader_destroyAll(). These might not be + * renderer concerned, and might require restructure and a clear separation. Review this. + */ +void bgem_renderer_destroyAllShaders(void); + +#endif /* RENDERER_H */ diff --git a/include/renderer/shader.h b/include/renderer/shader.h deleted file mode 100644 index 54cd523..0000000 --- a/include/renderer/shader.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * MIT License - * Copyright (c) 2026 Cătălin Gabriel Drăghiță - */ - -#ifndef SHADER_H -#define SHADER_H - -#include - -GLuint bgem_shader_createProgram(const char* vertexPath, const char* fragmentPath); - -#endif diff --git a/include/shader/shader.h b/include/shader/shader.h new file mode 100644 index 0000000..6e846db --- /dev/null +++ b/include/shader/shader.h @@ -0,0 +1,41 @@ +/* + * MIT License + * Copyright (c) 2026 Cătălin Gabriel Drăghiță + */ + +#ifndef SHADER_H +#define SHADER_H + +#include + +GLuint bgem_shader_createProgram(const char* vertexPath, const char* fragmentPath); + +/** + * @brief + * Reads the shader list form the catalog, compiles them all + * and stores the GLuint result in a list. + */ +void bgem_shader_loadAll(void); + +/** + * @brief + * Fetch a shader from the catalog. + * + * @param name + * The shader name to fetch. + * + * @retval 0 + * (GL_NONE) Returns zero if no shader is found. + * + * @retval non-zero + * Returns a valid GLuint value of a shader. + */ +GLuint bgem_shader_get(const char *name); + +/** + * @brief + * Clears all the shaders + */ +void bgem_shader_destroyAll(void); + +#endif /* SHADER_H */ diff --git a/include/shader/shader_catalog.h b/include/shader/shader_catalog.h new file mode 100644 index 0000000..62c5f4f --- /dev/null +++ b/include/shader/shader_catalog.h @@ -0,0 +1,20 @@ +/* + * MIT License + * Copyright (c) 2026 Cătălin Gabriel Drăghiță + */ + +#ifndef SHADER_CATALOG_H +#define SHADER_CATALOG_H + +#define BGEM_SHADER_MAX 16 + +typedef struct { + const char *name; + const char *vert; /* relative asset path */ + const char *frag; +} bgem_shader_descriptor; + +extern const bgem_shader_descriptor bgem_shader_catalog[]; +extern const int bgem_shader_catalogCount; + +#endif /* SHADER_CATALOG_H */ diff --git a/include/system/config.h b/include/system/config.h new file mode 100644 index 0000000..3945efd --- /dev/null +++ b/include/system/config.h @@ -0,0 +1,32 @@ +/* + * MIT License + * Copyright (c) 2026 Cătălin Gabriel Drăghiță + */ + +#ifndef CONFIG_H +#define CONFIG_H + +#include + +typedef struct bgem_config { + int frame_limit; + int render_width; + int render_height; + bool fullscreen; +} bgem_config; + + +/** + * @brief + * WIP: Load configuration data + * + * Right now, it only loads the defined defaults in + * bgem_defaults.h. Later implementation will read from + * a user config file, along with checks. + * + * @return + * Stores current configuration data into a struct + */ +bgem_config bgem_config_load(void); // stub for now + +#endif /* CONFIG_H */ diff --git a/include/system/display.h b/include/system/display.h index 46e5d97..977cba4 100644 --- a/include/system/display.h +++ b/include/system/display.h @@ -6,6 +6,11 @@ #ifndef DISPLAY_H #define DISPLAY_H +/** + * @brief + * TODO: This function retreives the display modes and makes it + * available for the application. Currently it is a STUB. + */ void bgem_system_getDisplayModes(void); -#endif // DISPLAY_H +#endif /* DISPLAY_H */ diff --git a/include/system/system.h b/include/system/system.h index 8e1e039..444dd32 100644 --- a/include/system/system.h +++ b/include/system/system.h @@ -6,6 +6,21 @@ #ifndef SYSTEM_H #define SYSTEM_H +/** + * @brief + * Initializes and runs the program. + * + * Initialization routines are performed, like checking closure status to decide + * wheither to run repair and diagnostics routines. Initialize the graphics subsystem + * and check compatibility. Read and fill in current host system information settings. + * And execute the main application program loop. + * + * @return + * EXIT_SUCCESS is returned when all clean up and closing + * procedures are executed without problems. EXIT_FAILURE is returned when a function, + * in the middle of execution, did not meet the expected requirement or a failure has + * occurred. + */ int bgem_system_start(void); -#endif // SYSTEM_H +#endif /* SYSTEM_H */ diff --git a/include/window/window.h b/include/window/window.h index e46397d..34991e5 100644 --- a/include/window/window.h +++ b/include/window/window.h @@ -7,19 +7,65 @@ #define WINDOW_H #include "platform/platform_egl.h" +#include "system/config.h" -typedef enum bgem_window_mode { - BGEM_DEFAULT, - BGEM_WINDOWED, - BGEM_FULLSCREEN -} bgem_window_mode; - +/** + * @brief + * This structure represents the whole window, acting as a handle. + * + * The handle is passed to the window and rendering functions to + * perform rendering operations into its graphics context, and + * retrieve and change window settings. + * + * Must be freed with free() after being assigned. + */ typedef struct bgem_window_handle { - SDL_Window* window; - bgem_platform_windowContext* window_ctx; + SDL_Window* window; /**< Used to send and receive window status and set new parameters */ + bgem_platform_windowContext* window_ctx; /**< Used with rendering functions to display the UI */ + bool fullscreen; } bgem_window_handle; -bgem_window_handle* bgem_window_createWindow(bgem_window_mode wm); -int bgem_window_createContext(bgem_window_handle* wh); +/** + * @brief + * Generates the window and creates the graphics context. + * + * By design, all the content in the client area is custom rendered, + * hence the requirement of the graphics context with the window. + * + * @param[in] cfg + * Takes in the fullscreen status flag and decides if to launch the + * program in fullscreen (borderless) or windowed mode. + * + * @return + * bgem_window_handle* on success, NULL on failure. + */ +bgem_window_handle* bgem_window_createWindow(bgem_config *cfg); + +/** + * @brief + * Resize the contents with the new information + * + * Extracts window size pixel data, and it uses it for changing the + * context size. + * + * @param[in] wh + * The window handle to read and apply the new size information. + * + * @param[in] event + * The current SDL event when SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED was sent + * to read the new client area pixel size data. + * + * TODO: Review these descriptions. I didn't feel very confident with that last one + */ +void bgem_window_handleResize(bgem_window_handle *wh, SDL_Event *event); + +/** + * @brief + * Toggles between borderless or windowed. + * + * @param[in] wh + * Reads the `fullscreen` member and swiches its status. + */ +void bgem_window_toggleFullscreen(bgem_window_handle *wh); #endif /* WINDOW_H */ diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index cfadbad..d6b51df 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -8,8 +8,9 @@ add_subdirectory(window) add_subdirectory(renderer) add_subdirectory(platform) add_subdirectory(app) -add_subdirectory(debug_tools) add_subdirectory(system) +add_subdirectory(core) +add_subdirectory(shader) if (WIN32 OR LINUX) add_custom_command(TARGET bgem POST_BUILD @@ -30,7 +31,8 @@ target_link_libraries(bgem PRIVATE system app renderer - debug_tools + shader + core platform window # SDL3::SDL3 @@ -78,10 +80,10 @@ if(APPLE) endif() target_sources(bgem PRIVATE - debug_tools/imgui_backends/imgui_impl_sdl3.cpp - debug_tools/imgui_backends/imgui_impl_opengl3.cpp + core/imgui_backends/imgui_impl_sdl3.cpp + core/imgui_backends/imgui_impl_opengl3.cpp ) target_compile_definitions(bgem PRIVATE - IMGUI_IMPL_OPENGL_ES3 # ← ES3, not ES2 — bgem targets GLES 3.0 + IMGUI_IMPL_OPENGL_ES3 ) diff --git a/source/app/app.c b/source/app/app.c index d2b1ee1..daeef21 100644 --- a/source/app/app.c +++ b/source/app/app.c @@ -11,12 +11,23 @@ #include "app/app.h" #include "core/debug.h" -int bgem_app_init(void) +int bgem_app_run(bgem_config *cfg) { - bgem_window_handle* wh = bgem_window_createWindow(BGEM_DEFAULT); - if(!wh) return EXIT_FAILURE; + int w, h; + bgem_window_handle* wh; - bgem_renderer_loop(wh); + wh = bgem_window_createWindow(cfg); + if (!wh) return EXIT_FAILURE; + + SDL_GetWindowSizeInPixels(wh->window, &w, &h); + bgem_renderer_setWindowSize(w, h); + bgem_renderer_init(cfg); + bgem_debug_init(wh->window); + + bgem_renderer_loop(wh, cfg); + + bgem_debug_shutdown(); + bgem_renderer_destroyAllShaders(); free(wh); return EXIT_SUCCESS; } diff --git a/source/core/CMakeLists.txt b/source/core/CMakeLists.txt new file mode 100644 index 0000000..b91df8e --- /dev/null +++ b/source/core/CMakeLists.txt @@ -0,0 +1,14 @@ +add_library(core + path.c + timer.c + frame_limiter.c + debug.cpp +) + +add_subdirectory(imgui_backends) + +target_include_directories(core PUBLIC + ${PROJECT_SOURCE_DIR}/include +) + +target_link_libraries(core PUBLIC compiler_options imgui_backend SDL3::SDL3) diff --git a/source/debug_tools/debug.cpp b/source/core/debug.cpp similarity index 100% rename from source/debug_tools/debug.cpp rename to source/core/debug.cpp diff --git a/source/core/frame_limiter.c b/source/core/frame_limiter.c new file mode 100644 index 0000000..3483907 --- /dev/null +++ b/source/core/frame_limiter.c @@ -0,0 +1,47 @@ +/* + * MIT License + * Copyright (c) 2026 Cătălin Gabriel Drăghiță + */ + +#include "core/frame_limiter.h" +#include "core/timer.h" + +/* Clamp dt to 100ms — prevents explosion after suspend, breakpoints, etc. */ +#define BGEM_MAX_DT_SECONDS 0.1 + +void bgem_frame_limiterInit(bgem_frame_limiter *fl, Uint32 target_fps) +{ + fl->target_fps = target_fps; + fl->frame_budget = 1.0 / (double)target_fps; + fl->app_start = bgem_timer_seconds(); + fl->frame_start = fl->app_start; + fl->dt_ms = 0.0f; + fl->elapsed = 0.0; +} + +void bgem_frame_limiterBegin(bgem_frame_limiter *fl) +{ + double now = bgem_timer_seconds(); + double raw_dt = now - fl->frame_start; + + if (raw_dt > BGEM_MAX_DT_SECONDS) + raw_dt = BGEM_MAX_DT_SECONDS; + + fl->dt_ms = (float)(raw_dt * 1000.0); + fl->elapsed = now - fl->app_start; + fl->frame_start = now; +} + +void bgem_frame_limiterEnd(bgem_frame_limiter *fl) +{ + double elapsed_this_frame = bgem_timer_seconds() - fl->frame_start; + double remaining = fl->frame_budget - elapsed_this_frame; + + /* Sleep the bulk of the remaining budget, leaving ~2ms for the spin */ + if (remaining > 0.002) + SDL_DelayNS((Uint64)((remaining - 0.002) * 1e9)); + + /* Spin-wait the final fraction for precision */ + while (bgem_timer_seconds() - fl->frame_start < fl->frame_budget) + { /* spin */ } +} diff --git a/source/debug_tools/imgui_backends/CMakeLists.txt b/source/core/imgui_backends/CMakeLists.txt similarity index 100% rename from source/debug_tools/imgui_backends/CMakeLists.txt rename to source/core/imgui_backends/CMakeLists.txt diff --git a/source/debug_tools/imgui_backends/imgui_impl_opengl3.cpp b/source/core/imgui_backends/imgui_impl_opengl3.cpp similarity index 100% rename from source/debug_tools/imgui_backends/imgui_impl_opengl3.cpp rename to source/core/imgui_backends/imgui_impl_opengl3.cpp diff --git a/source/debug_tools/imgui_backends/imgui_impl_opengl3.h b/source/core/imgui_backends/imgui_impl_opengl3.h similarity index 100% rename from source/debug_tools/imgui_backends/imgui_impl_opengl3.h rename to source/core/imgui_backends/imgui_impl_opengl3.h diff --git a/source/debug_tools/imgui_backends/imgui_impl_opengl3_loader.h b/source/core/imgui_backends/imgui_impl_opengl3_loader.h similarity index 100% rename from source/debug_tools/imgui_backends/imgui_impl_opengl3_loader.h rename to source/core/imgui_backends/imgui_impl_opengl3_loader.h diff --git a/source/debug_tools/imgui_backends/imgui_impl_sdl3.cpp b/source/core/imgui_backends/imgui_impl_sdl3.cpp similarity index 100% rename from source/debug_tools/imgui_backends/imgui_impl_sdl3.cpp rename to source/core/imgui_backends/imgui_impl_sdl3.cpp diff --git a/source/debug_tools/imgui_backends/imgui_impl_sdl3.h b/source/core/imgui_backends/imgui_impl_sdl3.h similarity index 100% rename from source/debug_tools/imgui_backends/imgui_impl_sdl3.h rename to source/core/imgui_backends/imgui_impl_sdl3.h diff --git a/source/core/path.c b/source/core/path.c new file mode 100644 index 0000000..12d0ba1 --- /dev/null +++ b/source/core/path.c @@ -0,0 +1,17 @@ +/* + * MIT License + * Copyright (c) 2026 Cătălin Gabriel Drăghiță + */ + +#include +#include + +#include "core/path.h" + +bool bgem_path_relativeToFull(char *out, size_t size, const char *relative_path) +{ + const char* base = SDL_GetBasePath(); + if (!base) return false; + int written = snprintf(out, size, "%s%s", base, relative_path); + return written > 0 && (size_t)written < size; +} diff --git a/source/core/timer.c b/source/core/timer.c new file mode 100644 index 0000000..b0878f9 --- /dev/null +++ b/source/core/timer.c @@ -0,0 +1,11 @@ +/* + * MIT License + * Copyright (c) 2026 Cătălin Gabriel Drăghiță + */ + +#include + +double bgem_timer_seconds(void) +{ + return (double)SDL_GetPerformanceCounter() / (double)SDL_GetPerformanceFrequency(); +} diff --git a/source/debug_tools/CMakeLists.txt b/source/debug_tools/CMakeLists.txt deleted file mode 100644 index 748c205..0000000 --- a/source/debug_tools/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -add_library(debug_tools - debug.cpp -) - -add_subdirectory(imgui_backends) - -target_include_directories(debug_tools PUBLIC - ${PROJECT_SOURCE_DIR}/include -) - -target_link_libraries(debug_tools PUBLIC compiler_options imgui_backend) diff --git a/source/platform/linux/platform_egl_linux.c b/source/platform/linux/platform_egl_linux.c index ccd6444..6eb4087 100644 --- a/source/platform/linux/platform_egl_linux.c +++ b/source/platform/linux/platform_egl_linux.c @@ -86,13 +86,14 @@ bgem_platform_windowContext* bgem_platform_createContext(SDL_Window *window) nativeWindow = (EGLNativeWindowType)x11Window; display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (display == EGL_NO_DISPLAY) return NULL; - } + if (display == EGL_NO_DISPLAY) + return NULL; else { DEBUG_PRINT("Environment: %s\n", driver); return NULL; } + } } if (!eglInitialize(display, NULL, NULL)) return NULL; diff --git a/source/renderer/CMakeLists.txt b/source/renderer/CMakeLists.txt index a3eb2c0..cbc8e75 100644 --- a/source/renderer/CMakeLists.txt +++ b/source/renderer/CMakeLists.txt @@ -1,6 +1,5 @@ add_library(renderer renderer.c - shader.c render_loop.c ) @@ -9,9 +8,3 @@ target_include_directories(renderer PUBLIC ) target_link_libraries(renderer PUBLIC compiler_options SDL3::SDL3) - -if(LINUX) - target_link_libraries(renderer PUBLIC OpenGL::GL OpenGL::EGL) -else() - target_link_libraries(renderer PUBLIC unofficial::angle::libEGL unofficial::angle::libGLESv2) -endif() diff --git a/source/renderer/render_loop.c b/source/renderer/render_loop.c index f49925a..7774f94 100644 --- a/source/renderer/render_loop.c +++ b/source/renderer/render_loop.c @@ -5,132 +5,64 @@ #include #include -#if defined(__APPLE__) || defined(__linux__) -#include -#endif - -#if defined(_WIN32) -#include -#endif #include #include "window/window.h" #include "platform/platform_egl.h" #include "renderer/render_loop.h" -#include "renderer/shader.h" +#include "shader/shader.h" #include "renderer/renderer.h" +#include "core/frame_limiter.h" +#include "system/config.h" +#include "bgem_defaults.h" +#include "core/timer.h" #include "core/debug.h" -static double get_time_seconds(void) -{ -#if defined(_WIN32) - LARGE_INTEGER count; - static LARGE_INTEGER frequency; - static int initialized = 0; - - if (!initialized) - { - QueryPerformanceFrequency(&frequency); - initialized = 1; - } - - QueryPerformanceCounter(&count); - - return (double)count.QuadPart / (double)frequency.QuadPart; - -#elif defined(__APPLE__) || defined(__linux__) - struct timespec ts; - - clock_gettime(CLOCK_MONOTONIC, &ts); - - return ts.tv_sec + ts.tv_nsec / 1000000000.0; - -#endif -} - -int bgem_renderer_loop(bgem_window_handle *wh) +int bgem_renderer_loop(bgem_window_handle *wh, bgem_config *cfg) { int running = 1; SDL_Event event; - int w, h; -#if defined(_WIN32) || defined(__linux__) - bool b = true; -#endif - - SDL_GetWindowSizeInPixels(wh->window, &w, &h); - bgem_renderer_setWindowSize(w, h); - - bgem_renderer_init(); - - bgem_debug_init(wh->window); - - const Uint64 target_fps = 60; - const Uint64 frame_delay = 1000 / target_fps; - - Uint64 frame_start; - Uint64 frame_time; - double startTime = get_time_seconds(); + bgem_frame_limiter limiter; + bgem_frame_limiterInit(&limiter, cfg->frame_limit); while (running) { - frame_start = SDL_GetTicks(); + bgem_frame_limiterBegin(&limiter); + + /* TODO: Move this in a dedicated input module */ while (SDL_PollEvent(&event)) { if (event.type == SDL_EVENT_QUIT) { running = 0; } - if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN) { - running = 0; // Exit on click - } if (event.type == SDL_EVENT_KEY_DOWN) { if (event.key.key == SDLK_B) { bgem_debug_toggle(); } } if (event.type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED) { -#if defined(_WIN32) - w = event.window.data1; - h = event.window.data2; -#elif defined(__linux__) - w = event.window.data1; - h = event.window.data2; - bgem_platform_waylandResizeSurface(wh->window_ctx, w, h); -#elif defined(__APPLE__) - //bgem_platform_getSurfaceSize(wh->window_ctx, &w, &h); - SDL_GetWindowSizeInPixels(wh->window, &w, &h); -#endif - bgem_renderer_setWindowSize(w, h); + bgem_window_handleResize(wh, &event); } -#if defined(_WIN32) || defined(__linux__) - if (event.type == SDL_EVENT_KEY_DOWN) { - if (event.key.key == SDLK_F11) { - SDL_SetWindowFullscreen(wh->window, b); - b = !b; - } + if (event.type == SDL_EVENT_KEY_DOWN) { + if (event.key.key == SDLK_F) { + bgem_window_toggleFullscreen(wh); } -#endif + } } - double current = get_time_seconds(); - float time = (float)(current - startTime); bgem_debug_newFrame(); - bgem_renderer_render(time); + bgem_renderer_render((float)limiter.elapsed); - bgem_renderer_present(w, h); + bgem_renderer_present(); bgem_debug_render(); bgem_renderer_swap(wh->window_ctx); - frame_time = SDL_GetTicks() - frame_start; - if (frame_delay > frame_time) - SDL_Delay((Uint32)(frame_delay - frame_time)); + bgem_frame_limiterEnd(&limiter); + } - bgem_debug_shutdown(); - bgem_platform_destroyContext(wh->window_ctx); - SDL_DestroyWindow(wh->window); - SDL_Quit(); return EXIT_SUCCESS; } diff --git a/source/renderer/renderer.c b/source/renderer/renderer.c index 46d61d8..f6539b3 100644 --- a/source/renderer/renderer.c +++ b/source/renderer/renderer.c @@ -9,8 +9,10 @@ #include #include "renderer/renderer.h" -#include "renderer/shader.h" +#include "shader/shader.h" #include "platform/platform_egl.h" +#include "system/config.h" +#include "bgem_defaults.h" #include "core/debug.h" static GLuint program; @@ -27,8 +29,8 @@ static GLint blit_texLocation; static GLint blit_posLocation; /* Internal renderer resolution */ -static int internal_w = 1920; -static int internal_h = 1080; +static int internal_w = 0; +static int internal_h = 0; /* Cached letterbox viewport */ static struct { @@ -36,6 +38,12 @@ static struct { int window_w, window_h; /* updated via bgem_renderer_setWindowSize() */ } viewport; +void bgem_renderer_initInternalResolution(bgem_config *cfg) +{ + internal_w = cfg->render_width; + internal_h = cfg->render_height; +} + void bgem_renderer_setWindowSize(int w, int h) { viewport.window_w = w; @@ -51,12 +59,10 @@ void bgem_renderer_setWindowSize(int w, int h) viewport.y = (h - viewport.h) / 2; } -void bgem_renderer_init(void) +void bgem_renderer_init(bgem_config *cfg) { - /* PLACEHOLDER! Move this to a dedicated file for handling path resolution */ - const char *basePath = SDL_GetBasePath(); - if (!basePath) - SDL_Log("SDL_GetBasePath failed: %s", SDL_GetError()); + bgem_renderer_initInternalResolution(cfg); + bgem_shader_loadAll(); /* Creste offscreen FBO */ /* Color texture at internal resolution */ @@ -83,32 +89,13 @@ void bgem_renderer_init(void) glBindFramebuffer(GL_FRAMEBUFFER, 0); /* Create `testshader` shader */ - /* PLACEHOLDER! This shader should not be here. */ - char vertexPath[1024]; - snprintf(vertexPath, sizeof(vertexPath), - "%sassets/shaders/testshader/vertex.glsl", basePath); - DEBUG_PRINT("Opening vertex shader at: %s\n", vertexPath); - char fragmentPath[1024]; - snprintf(fragmentPath, sizeof(fragmentPath), - "%sassets/shaders/testshader/fragment.glsl", basePath); - DEBUG_PRINT("Opening fragment shader at: %s\n", fragmentPath); - - program = bgem_shader_createProgram(vertexPath, fragmentPath); + /* TODO: This should not be here */ + program = bgem_shader_get("testshader"); posLocation = glGetAttribLocation(program, "aPos"); timeLocation = glGetUniformLocation(program, "uTime"); /* Create `blit` shader */ - char blit_vert_src[1024]; - snprintf(blit_vert_src, sizeof(blit_vert_src), - "%sassets/shaders/blit/vertex.glsl", basePath); - DEBUG_PRINT("Opening vertex shader at: %s\n", blit_vert_src); - - char blit_frag_src[1024]; - snprintf(blit_frag_src, sizeof(blit_frag_src), - "%sassets/shaders/blit/fragment.glsl", basePath); - DEBUG_PRINT("Opening fragment shader at: %s\n", blit_frag_src); - - blit_program = bgem_shader_createProgram(blit_vert_src, blit_frag_src); + blit_program = bgem_shader_get("blit"); blit_posLocation = glGetAttribLocation(blit_program, "aPos"); blit_texLocation = glGetUniformLocation(blit_program, "uTex"); @@ -143,10 +130,10 @@ void bgem_renderer_render(float time) glBindFramebuffer(GL_FRAMEBUFFER, 0); } -void bgem_renderer_present(int window_width, int window_height) +void bgem_renderer_present(void) { /* Clear the full window (shows letterbox bars in clear color) */ - glViewport(0, 0, window_width, window_height); + glViewport(0, 0, viewport.window_w, viewport.window_h); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); @@ -166,3 +153,8 @@ void bgem_renderer_swap(bgem_platform_windowContext *ctx) { bgem_platform_swapBuffers(ctx); } + +void bgem_renderer_destroyAllShaders(void) +{ + bgem_shader_destroyAll(); +} diff --git a/source/shader/CMakeLists.txt b/source/shader/CMakeLists.txt new file mode 100644 index 0000000..7f39c62 --- /dev/null +++ b/source/shader/CMakeLists.txt @@ -0,0 +1,16 @@ +add_library(shader + shader.c + shader_catalog.c +) + +target_include_directories(shader PUBLIC + ${PROJECT_SOURCE_DIR}/include +) + +target_link_libraries(shader PUBLIC compiler_options SDL3::SDL3) + +if(LINUX) + target_link_libraries(shader PUBLIC OpenGL::GL OpenGL::EGL) +else() + target_link_libraries(shader PUBLIC unofficial::angle::libEGL unofficial::angle::libGLESv2) +endif() diff --git a/source/renderer/shader.c b/source/shader/shader.c similarity index 56% rename from source/renderer/shader.c rename to source/shader/shader.c index 2be53c4..ee87758 100644 --- a/source/renderer/shader.c +++ b/source/shader/shader.c @@ -8,11 +8,14 @@ #include #include -#include "renderer/shader.h" +#include "shader/shader.h" +#include "shader/shader_catalog.h" +#include "core/path.h" #include "core/debug.h" +static GLuint bgem_shader_compiledPrograms[BGEM_SHADER_MAX]; -static char* ReadFile(const char* path) +static char* read_file(const char* path) { FILE* file = fopen(path, "rb"); if (!file) { @@ -32,7 +35,7 @@ static char* ReadFile(const char* path) return buffer; } -static GLuint CompileShader(GLenum type, const char* source) +static GLuint compile_shader(GLenum type, const char* source) { if(!source) { DEBUG_PRINT("File does not exist"); return EXIT_FAILURE; } GLuint shader = glCreateShader(type); @@ -54,8 +57,8 @@ static GLuint CompileShader(GLenum type, const char* source) GLuint bgem_shader_createProgram(const char* vertexPath, const char* fragmentPath) { - char* vertexSource = ReadFile(vertexPath); - char* fragmentSource = ReadFile(fragmentPath); + char* vertexSource = read_file(vertexPath); + char* fragmentSource = read_file(fragmentPath); if (!vertexSource || !fragmentSource) { DEBUG_PRINT("Failed to read shader source path!"); @@ -64,8 +67,8 @@ GLuint bgem_shader_createProgram(const char* vertexPath, const char* fragmentPat return EXIT_FAILURE; } - GLuint vertexShader = CompileShader(GL_VERTEX_SHADER, vertexSource); - GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, fragmentSource); + GLuint vertexShader = compile_shader(GL_VERTEX_SHADER, vertexSource); + GLuint fragmentShader = compile_shader(GL_FRAGMENT_SHADER, fragmentSource); GLuint program = glCreateProgram(); glAttachShader(program, vertexShader); @@ -90,3 +93,36 @@ GLuint bgem_shader_createProgram(const char* vertexPath, const char* fragmentPat return program; } + +void bgem_shader_loadAll(void) +{ + for (int i = 0; bgem_shader_catalog[i].name != NULL; i++) + { + char vertPath[1024]; + char fragPath[1024]; + + bgem_path_relativeToFull(vertPath, sizeof(vertPath), bgem_shader_catalog[i].vert); + bgem_path_relativeToFull(fragPath, sizeof(fragPath), bgem_shader_catalog[i].frag); + + bgem_shader_compiledPrograms[i] = bgem_shader_createProgram(vertPath, fragPath); + } +} + +GLuint bgem_shader_get(const char *name) +{ + for (int i = 0; bgem_shader_catalog[i].name != NULL; i++) + { + if (SDL_strcmp(bgem_shader_catalog[i].name, name) == 0) + return bgem_shader_compiledPrograms[i]; + } + return 0; /* Not found */ +} + +void bgem_shader_destroyAll(void) +{ + for (int i = 0; bgem_shader_catalog[i].name != NULL; i++) + { + glDeleteProgram(bgem_shader_compiledPrograms[i]); + bgem_shader_compiledPrograms[i] = 0; + } +} diff --git a/source/shader/shader_catalog.c b/source/shader/shader_catalog.c new file mode 100644 index 0000000..e811fc4 --- /dev/null +++ b/source/shader/shader_catalog.c @@ -0,0 +1,15 @@ +/* + * MIT License + * Copyright (c) 2026 Cătălin Gabriel Drăghiță + */ + +#include +#include "shader/shader_catalog.h" + +const bgem_shader_descriptor bgem_shader_catalog[] = { + { "blit", "assets/shaders/blit/vertex.glsl", "assets/shaders/blit/fragment.glsl" }, + { "testshader", "assets/shaders/testshader/vertex.glsl", "assets/shaders/testshader/fragment.glsl" }, + { NULL, NULL, NULL } /* End of list */ +}; + +const int bgem_shader_catalogCount = (int)(sizeof(bgem_shader_catalog) / sizeof(bgem_shader_catalog[0])); diff --git a/source/system/CMakeLists.txt b/source/system/CMakeLists.txt index 9984627..6d0479b 100644 --- a/source/system/CMakeLists.txt +++ b/source/system/CMakeLists.txt @@ -1,6 +1,7 @@ add_library(system system.c display.c + config.c ) target_include_directories(system PUBLIC diff --git a/source/system/config.c b/source/system/config.c new file mode 100644 index 0000000..f54a105 --- /dev/null +++ b/source/system/config.c @@ -0,0 +1,18 @@ +/* + * MIT License + * Copyright (c) 2026 Cătălin Gabriel Drăghiță + */ + +#include "system/config.h" +#include "bgem_defaults.h" + +bgem_config bgem_config_load(void) +{ + bgem_config cfg = { + .frame_limit = BGEM_DEFAULT_FRAME_LIMIT, + .render_height = BGEM_DEFAULT_RENDER_HEIGHT, + .render_width = BGEM_DEFAULT_RENDER_WIDTH, + .fullscreen = BGEM_DEFAULT_WINDOW_MODE + }; + return cfg; +} diff --git a/source/system/system.c b/source/system/system.c index d7fe375..142c48d 100644 --- a/source/system/system.c +++ b/source/system/system.c @@ -8,6 +8,7 @@ #include "system/system.h" #include "app/app.h" #include "core/debug.h" +#include "system/config.h" #include "bgem_version.h" #include "platform/platform_init.h" @@ -23,6 +24,8 @@ int bgem_system_start(void) SDL_SetAppMetadata("Project Bluegem", BGEM_VERSION_STRING, "com.bgem.bgem"); + /* Store the current configuration */ + bgem_config cfg = bgem_config_load(); if (SDL_InitSubSystem(SDL_INIT_VIDEO) == 0) { @@ -30,7 +33,8 @@ int bgem_system_start(void) return EXIT_FAILURE; } - if(bgem_app_init()) return EXIT_FAILURE; + if(bgem_app_run(&cfg)) return EXIT_FAILURE; + SDL_Quit(); /* Unlock instance once closing the program */ bgem_platform_instanceUnlock(); diff --git a/source/window/window.c b/source/window/window.c index 1433a15..2ee9c47 100644 --- a/source/window/window.c +++ b/source/window/window.c @@ -3,18 +3,12 @@ * Copyright (c) 2026 Cătălin Gabriel Drăghiță */ -/* - * Creating the window and the rendering context - * and running the loop - */ - #include #include #include "window/window.h" #include "platform/platform_egl.h" -#include "renderer/shader.h" #include "renderer/renderer.h" #include "core/debug.h" #include "bgem.h" @@ -24,9 +18,8 @@ #define VER_RES 1080 #define SCL_DWN 2 // Scale Down using division -bgem_window_handle* bgem_window_createWindow(bgem_window_mode wm) +bgem_window_handle* bgem_window_createWindow(bgem_config *cfg) { - DEBUG_PRINT("Window mode chosen: %d", wm); bgem_window_handle* wh = NULL; SDL_Window *window; @@ -53,6 +46,33 @@ bgem_window_handle* bgem_window_createWindow(bgem_window_mode wm) wh->window = window; wh->window_ctx = bgem_platform_createContext(wh->window); if (!wh->window_ctx) { free(wh); return NULL; } + wh->fullscreen = cfg->fullscreen; + SDL_SetWindowFullscreen(wh->window, wh->fullscreen); return wh; } + +void bgem_window_handleResize(bgem_window_handle *wh, SDL_Event *event) +{ + int w, h; + +#if defined(__linux__) + w = event->window.data1; + h = event->window.data2; + bgem_platform_waylandResizeSurface(wh->window_ctx, w, h); +#elif defined(__APPLE__) + (void)event; /* Silence warning */ + SDL_GetWindowSizeInPixels(wh->window, &w, &h); +#elif defined(_WIN32) + w = event->window.data1; + h = event->window.data2; +#endif + + bgem_renderer_setWindowSize(w, h); +} + +void bgem_window_toggleFullscreen(bgem_window_handle *wh) +{ + wh->fullscreen = !wh->fullscreen; + SDL_SetWindowFullscreen(wh->window, wh->fullscreen); +} From e513a6e803b729305f414e45698885ffd62ec6e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C4=83t=C4=83lin=20Gabriel=20Dr=C4=83ghi=C8=9B=C4=83?= Date: Thu, 21 May 2026 07:16:50 +0200 Subject: [PATCH 2/4] Use path limits defined by the system --- include/core/path.h | 12 ++++++++++++ source/shader/shader.c | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/include/core/path.h b/include/core/path.h index 05274f4..81e1ab8 100644 --- a/include/core/path.h +++ b/include/core/path.h @@ -29,4 +29,16 @@ */ bool bgem_path_relativeToFull(char *out, size_t size, const char *relative_path); +#if defined(_WIN32) + #include + #define BGEM_PATH_MAX MAX_PATH +#else + #include + #if defined(PATH_MAX) + #define BGEM_PATH_MAX PATH_MAX + #else + #define BGEM_PATH_MAX 4096 /* POSIX fallback for filesystems without a fixed limit */ + #endif +#endif + #endif /* PATH_H */ diff --git a/source/shader/shader.c b/source/shader/shader.c index ee87758..81380f4 100644 --- a/source/shader/shader.c +++ b/source/shader/shader.c @@ -98,8 +98,8 @@ void bgem_shader_loadAll(void) { for (int i = 0; bgem_shader_catalog[i].name != NULL; i++) { - char vertPath[1024]; - char fragPath[1024]; + char vertPath[BGEM_PATH_MAX]; + char fragPath[BGEM_PATH_MAX]; bgem_path_relativeToFull(vertPath, sizeof(vertPath), bgem_shader_catalog[i].vert); bgem_path_relativeToFull(fragPath, sizeof(fragPath), bgem_shader_catalog[i].frag); From 780acb976b8945f3674e3e03612e8c43fc6df82e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C4=83t=C4=83lin=20Gabriel=20Dr=C4=83ghi=C8=9B=C4=83?= Date: Thu, 21 May 2026 08:42:23 +0200 Subject: [PATCH 3/4] Error handling --- include/core/debug.h | 13 +++++++ include/core/path.h | 12 ++++--- include/platform/platform_egl.h | 10 +++++- include/renderer/render_loop.h | 5 +-- include/renderer/renderer.h | 10 ++++-- include/shader/shader.h | 4 ++- source/app/app.c | 6 ++-- source/core/path.c | 15 ++++++-- source/platform/linux/platform_egl_linux.c | 19 +++++++++- source/platform/macos/platform_egl_macos.m | 13 ++++++- source/platform/windows/platform_egl_win.c | 11 +++++- source/renderer/render_loop.c | 7 ++-- source/renderer/renderer.c | 15 +++++--- source/shader/shader.c | 40 +++++++++++++++++----- source/system/system.c | 8 ++++- source/window/window.c | 14 +++++--- 16 files changed, 160 insertions(+), 42 deletions(-) diff --git a/include/core/debug.h b/include/core/debug.h index cfdd19a..e1c0568 100644 --- a/include/core/debug.h +++ b/include/core/debug.h @@ -16,6 +16,19 @@ #define DEBUG_PRINT(fmt, ...) do {} while (0) #endif +/** + * @brief + * List of error codes returned by bgem's functions for error handling + */ +typedef enum { + BGEM_OK = 0, /**< Executed successfully */ + BGEM_ERROR_GPU, /**< Graphics or rendering error */ + BGEM_ERROR_PLATFORM, /**< Operating system function error */ + BGEM_ERROR_OOM, /**< Out of memory error */ + BGEM_ERROR_IO, /**< File operation error */ + BGEM_ERROR_NOT_FOUND /**< An asset or file is not available */ +} bgem_result; + #ifdef __cplusplus extern "C" { #endif diff --git a/include/core/path.h b/include/core/path.h index 81e1ab8..a2ec125 100644 --- a/include/core/path.h +++ b/include/core/path.h @@ -3,11 +3,13 @@ * Copyright (c) 2026 Cătălin Gabriel Drăghiță */ +#ifndef PATH_H +#define PATH_H + #include #include -#ifndef PATH_H -#define PATH_H +#include "core/debug.h" /** * @brief @@ -24,10 +26,10 @@ * The relative path * * @return - * FALSE if the output is bigger than the buffer (size). - * TRUE if the output fits in the buffer. + * BGEM_ERROR_BUFFER if the output is bigger than the buffer (size). + * BGEM_OK if the output fits in the buffer. */ -bool bgem_path_relativeToFull(char *out, size_t size, const char *relative_path); +bgem_result bgem_path_relativeToFull(char *out, size_t size, const char *relative_path); #if defined(_WIN32) #include diff --git a/include/platform/platform_egl.h b/include/platform/platform_egl.h index 2b22744..b36baad 100644 --- a/include/platform/platform_egl.h +++ b/include/platform/platform_egl.h @@ -11,6 +11,9 @@ #define PLATFORM_EGL_H #include +#include + +#include "core/debug.h" typedef struct bgem_platform_windowContext bgem_platform_windowContext; @@ -36,8 +39,13 @@ bgem_platform_windowContext* bgem_platform_createContext(SDL_Window *window); * @param[in] platformContext * The valid window context structure to read from and execute the EGL's swap * buffer function. + * + * @return + * EGL_SUCCESS if performed successfully. + * + * TODO: Handle more errors */ -void bgem_platform_swapBuffers(bgem_platform_windowContext *platformContext); +EGLint bgem_platform_swapBuffers(bgem_platform_windowContext *platformContext); /** * @brief diff --git a/include/renderer/render_loop.h b/include/renderer/render_loop.h index 23d3ea9..8c081ec 100644 --- a/include/renderer/render_loop.h +++ b/include/renderer/render_loop.h @@ -25,8 +25,9 @@ * The struct with the current program configuration. * * @return - * EXIT_SUCCESS when the loop is ended. + * BGEM_OK when the loop is ended with no problems. BGEM_ERROR_GPU if a + * failure occurred within the loop. */ -int bgem_renderer_loop(bgem_window_handle *wh, bgem_config *cfg); +bgem_result bgem_renderer_loop(bgem_window_handle *wh, bgem_config *cfg); #endif /* RENDER_LOOP_H */ diff --git a/include/renderer/renderer.h b/include/renderer/renderer.h index dea1516..d53b80e 100644 --- a/include/renderer/renderer.h +++ b/include/renderer/renderer.h @@ -8,6 +8,7 @@ #include "window/window.h" #include "system/config.h" +#include "core/debug.h" /** * @brief @@ -31,7 +32,7 @@ void bgem_renderer_setWindowSize(int w, int h); * @param[in] cfg * Reads the interal resolution settings */ -void bgem_renderer_init(bgem_config *cfg); +bgem_result bgem_renderer_init(bgem_config *cfg); /** * @brief @@ -54,8 +55,13 @@ void bgem_renderer_present(void); * * @param[in] ctx * Send the buffer swap to the context + * + * @return + * EGL_SUCCESS if successful. + * + * TODO: Handle other errors */ -void bgem_renderer_swap(bgem_platform_windowContext *ctx); +EGLint bgem_renderer_swap(bgem_platform_windowContext *ctx); /** * @brief diff --git a/include/shader/shader.h b/include/shader/shader.h index 6e846db..916e01e 100644 --- a/include/shader/shader.h +++ b/include/shader/shader.h @@ -8,6 +8,8 @@ #include +#include "core/debug.h" + GLuint bgem_shader_createProgram(const char* vertexPath, const char* fragmentPath); /** @@ -15,7 +17,7 @@ GLuint bgem_shader_createProgram(const char* vertexPath, const char* fragmentPat * Reads the shader list form the catalog, compiles them all * and stores the GLuint result in a list. */ -void bgem_shader_loadAll(void); +bgem_result bgem_shader_loadAll(void); /** * @brief diff --git a/source/app/app.c b/source/app/app.c index daeef21..b68f8f4 100644 --- a/source/app/app.c +++ b/source/app/app.c @@ -19,12 +19,12 @@ int bgem_app_run(bgem_config *cfg) wh = bgem_window_createWindow(cfg); if (!wh) return EXIT_FAILURE; - SDL_GetWindowSizeInPixels(wh->window, &w, &h); + if(!SDL_GetWindowSizeInPixels(wh->window, &w, &h)) { DEBUG_PRINT("SDL_GetWindowSizeInPixels failed with %s", SDL_GetError()); return EXIT_FAILURE; } bgem_renderer_setWindowSize(w, h); - bgem_renderer_init(cfg); + if(bgem_renderer_init(cfg)) { DEBUG_PRINT("Failed to initialize the renderer."); return EXIT_FAILURE; } bgem_debug_init(wh->window); - bgem_renderer_loop(wh, cfg); + if(bgem_renderer_loop(wh, cfg)) { DEBUG_PRINT("Fatal error occurred!"); return EXIT_FAILURE; } bgem_debug_shutdown(); bgem_renderer_destroyAllShaders(); diff --git a/source/core/path.c b/source/core/path.c index 12d0ba1..00a03fc 100644 --- a/source/core/path.c +++ b/source/core/path.c @@ -7,11 +7,20 @@ #include #include "core/path.h" +#include "core/debug.h" -bool bgem_path_relativeToFull(char *out, size_t size, const char *relative_path) +bgem_result bgem_path_relativeToFull(char *out, size_t size, const char *relative_path) { const char* base = SDL_GetBasePath(); - if (!base) return false; + if (!base) { DEBUG_PRINT("SDL_GetBasePath error: %s", SDL_GetError()); return BGEM_ERROR_IO; } int written = snprintf(out, size, "%s%s", base, relative_path); - return written > 0 && (size_t)written < size; + if(written > 0 && (size_t)written < size) + { + return BGEM_OK; + } + else + { + DEBUG_PRINT("Buffer overflow!"); + return BGEM_ERROR_IO; + } } diff --git a/source/platform/linux/platform_egl_linux.c b/source/platform/linux/platform_egl_linux.c index 6eb4087..a478457 100644 --- a/source/platform/linux/platform_egl_linux.c +++ b/source/platform/linux/platform_egl_linux.c @@ -95,6 +95,10 @@ bgem_platform_windowContext* bgem_platform_createContext(SDL_Window *window) } } } + else + { + return NULL; + } if (!eglInitialize(display, NULL, NULL)) return NULL; @@ -143,6 +147,14 @@ bgem_platform_windowContext* bgem_platform_createContext(SDL_Window *window) if (!eglMakeCurrent(display, surface, surface, context)) return NULL; ctx = (bgem_platform_windowContext*)malloc(sizeof(bgem_platform_windowContext)); + if (!ctx) + { + eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(display, surface); + eglDestroyContext(display, context); + eglTerminate(display); + return NULL; + } ctx->display = display; ctx->surface = surface; @@ -152,9 +164,14 @@ bgem_platform_windowContext* bgem_platform_createContext(SDL_Window *window) return ctx; } -void bgem_platform_swapBuffers(bgem_platform_windowContext *ctx) +EGLint bgem_platform_swapBuffers(bgem_platform_windowContext *ctx) { + /** + * TODO: For now, just fail the program if a failure occurs. + * Implement reinitialization later. + */ eglSwapBuffers(ctx->display, ctx->surface); + return eglGetError(); } void bgem_platform_waylandResizeSurface(bgem_platform_windowContext *ctx, int w, int h) diff --git a/source/platform/macos/platform_egl_macos.m b/source/platform/macos/platform_egl_macos.m index f887cae..aac3280 100644 --- a/source/platform/macos/platform_egl_macos.m +++ b/source/platform/macos/platform_egl_macos.m @@ -80,14 +80,24 @@ }; context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs); + if (context == EGL_NO_CONTEXT) return NULL; surface = eglCreateWindowSurface(display, config, (__bridge void *)metalLayer, NULL); + if (surface == EGL_NO_SURFACE) return NULL; eglMakeCurrent(display, surface, surface, context); ctx = (bgem_platform_windowContext *)malloc(sizeof(bgem_platform_windowContext)); + if (!ctx) + { + eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(display, surface); + eglDestroyContext(display, context); + eglTerminate(display); + return NULL; + } ctx->display = display; ctx->surface = surface; @@ -96,9 +106,10 @@ return ctx; } -void bgem_platform_swapBuffers(bgem_platform_windowContext *ctx) +EGLint bgem_platform_swapBuffers(bgem_platform_windowContext *ctx) { eglSwapBuffers(ctx->display, ctx->surface); + return eglGetError(); } void bgem_platform_destroyContext(bgem_platform_windowContext *ctx) diff --git a/source/platform/windows/platform_egl_win.c b/source/platform/windows/platform_egl_win.c index 3b39d5e..74fe6aa 100644 --- a/source/platform/windows/platform_egl_win.c +++ b/source/platform/windows/platform_egl_win.c @@ -92,6 +92,14 @@ bgem_platform_windowContext* bgem_platform_createContext(SDL_Window *window) return NULL; ctx = (bgem_platform_windowContext*)malloc(sizeof(bgem_platform_windowContext)); + if (!ctx) + { + eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(display, surface); + eglDestroyContext(display, context); + eglTerminate(display); + return NULL; + } ctx->display = display; ctx->surface = surface; @@ -100,9 +108,10 @@ bgem_platform_windowContext* bgem_platform_createContext(SDL_Window *window) return ctx; } -void bgem_platform_swapBuffers(bgem_platform_windowContext *ctx) +EGLint bgem_platform_swapBuffers(bgem_platform_windowContext *ctx) { eglSwapBuffers(ctx->display, ctx->surface); + return eglGetError(); } void bgem_platform_destroyContext(bgem_platform_windowContext *ctx) diff --git a/source/renderer/render_loop.c b/source/renderer/render_loop.c index 7774f94..745388c 100644 --- a/source/renderer/render_loop.c +++ b/source/renderer/render_loop.c @@ -18,9 +18,10 @@ #include "core/timer.h" #include "core/debug.h" -int bgem_renderer_loop(bgem_window_handle *wh, bgem_config *cfg) +bgem_result bgem_renderer_loop(bgem_window_handle *wh, bgem_config *cfg) { int running = 1; + int status = BGEM_OK; SDL_Event event; bgem_frame_limiter limiter; @@ -58,11 +59,11 @@ int bgem_renderer_loop(bgem_window_handle *wh, bgem_config *cfg) bgem_debug_render(); - bgem_renderer_swap(wh->window_ctx); + if(bgem_renderer_swap(wh->window_ctx) != EGL_SUCCESS) { status = BGEM_ERROR_GPU; running = 0; } bgem_frame_limiterEnd(&limiter); } - return EXIT_SUCCESS; + return status; } diff --git a/source/renderer/renderer.c b/source/renderer/renderer.c index f6539b3..32c5010 100644 --- a/source/renderer/renderer.c +++ b/source/renderer/renderer.c @@ -59,10 +59,10 @@ void bgem_renderer_setWindowSize(int w, int h) viewport.y = (h - viewport.h) / 2; } -void bgem_renderer_init(bgem_config *cfg) +bgem_result bgem_renderer_init(bgem_config *cfg) { bgem_renderer_initInternalResolution(cfg); - bgem_shader_loadAll(); + if(bgem_shader_loadAll()) { DEBUG_PRINT("Failed loading shaders"); return BGEM_ERROR_IO; } /* Creste offscreen FBO */ /* Color texture at internal resolution */ @@ -84,18 +84,23 @@ void bgem_renderer_init(bgem_config *cfg) GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) + { DEBUG_PRINT("FBO incomplete: 0x%x\n", status); + return BGEM_ERROR_GPU; + } glBindFramebuffer(GL_FRAMEBUFFER, 0); /* Create `testshader` shader */ /* TODO: This should not be here */ program = bgem_shader_get("testshader"); + if (!program) { DEBUG_PRINT("Shader 'testshader' not found"); return BGEM_ERROR_IO; } posLocation = glGetAttribLocation(program, "aPos"); timeLocation = glGetUniformLocation(program, "uTime"); /* Create `blit` shader */ blit_program = bgem_shader_get("blit"); + if (!blit_program) { DEBUG_PRINT("Shader 'blit' not found"); return BGEM_ERROR_IO; } blit_posLocation = glGetAttribLocation(blit_program, "aPos"); blit_texLocation = glGetUniformLocation(blit_program, "uTex"); @@ -111,6 +116,8 @@ void bgem_renderer_init(bgem_config *cfg) glGenBuffers(1, &blit_vbo); glBindBuffer(GL_ARRAY_BUFFER, blit_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + return BGEM_OK; } void bgem_renderer_render(float time) @@ -149,9 +156,9 @@ void bgem_renderer_present(void) glDrawArrays(GL_TRIANGLES, 0, 3); } -void bgem_renderer_swap(bgem_platform_windowContext *ctx) +EGLint bgem_renderer_swap(bgem_platform_windowContext *ctx) { - bgem_platform_swapBuffers(ctx); + return bgem_platform_swapBuffers(ctx); } void bgem_renderer_destroyAllShaders(void) diff --git a/source/shader/shader.c b/source/shader/shader.c index 81380f4..6fffd12 100644 --- a/source/shader/shader.c +++ b/source/shader/shader.c @@ -23,13 +23,17 @@ static char* read_file(const char* path) return NULL; } - fseek(file, 0, SEEK_END); + if(fseek(file, 0, SEEK_END) != 0) { fclose(file); return NULL; } long size = ftell(file); + if (size == -1) { fclose(file); return NULL;} rewind(file); char* buffer = malloc(size + 1); - fread(buffer, 1, size, file); - buffer[size] = 0; + if (!buffer) { fclose(file); return NULL; } + + size_t read = fread(buffer, 1, size, file); + if (read != (size_t)size) { free(buffer); fclose(file); return NULL; } + buffer[read] = '\0'; fclose(file); return buffer; @@ -37,7 +41,7 @@ static char* read_file(const char* path) static GLuint compile_shader(GLenum type, const char* source) { - if(!source) { DEBUG_PRINT("File does not exist"); return EXIT_FAILURE; } + if(!source) { DEBUG_PRINT("File does not exist"); return GL_NONE; } GLuint shader = glCreateShader(type); glShaderSource(shader, 1, &source, NULL); glCompileShader(shader); @@ -50,6 +54,8 @@ static GLuint compile_shader(GLenum type, const char* source) char log[512]; glGetShaderInfoLog(shader, 512, NULL, log); DEBUG_PRINT("Shader compile error:\n%s\n", log); + glDeleteShader(shader); + return GL_NONE; } return shader; @@ -64,12 +70,20 @@ GLuint bgem_shader_createProgram(const char* vertexPath, const char* fragmentPat DEBUG_PRINT("Failed to read shader source path!"); free(vertexSource); free(fragmentSource); - return EXIT_FAILURE; + return GL_NONE; } GLuint vertexShader = compile_shader(GL_VERTEX_SHADER, vertexSource); GLuint fragmentShader = compile_shader(GL_FRAGMENT_SHADER, fragmentSource); + if (!vertexShader || !fragmentShader) { + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + free(vertexSource); + free(fragmentSource); + return GL_NONE; + } + GLuint program = glCreateProgram(); glAttachShader(program, vertexShader); glAttachShader(program, fragmentShader); @@ -83,6 +97,11 @@ GLuint bgem_shader_createProgram(const char* vertexPath, const char* fragmentPat char log[512]; glGetProgramInfoLog(program, 512, NULL, log); DEBUG_PRINT("Program link error:\n%s\n", log); + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + free(vertexSource); + free(fragmentSource); + return GL_NONE; } glDeleteShader(vertexShader); @@ -94,18 +113,21 @@ GLuint bgem_shader_createProgram(const char* vertexPath, const char* fragmentPat return program; } -void bgem_shader_loadAll(void) +bgem_result bgem_shader_loadAll(void) { for (int i = 0; bgem_shader_catalog[i].name != NULL; i++) { char vertPath[BGEM_PATH_MAX]; char fragPath[BGEM_PATH_MAX]; - bgem_path_relativeToFull(vertPath, sizeof(vertPath), bgem_shader_catalog[i].vert); - bgem_path_relativeToFull(fragPath, sizeof(fragPath), bgem_shader_catalog[i].frag); + if(bgem_path_relativeToFull(vertPath, sizeof(vertPath), bgem_shader_catalog[i].vert)) { return BGEM_ERROR_IO; } + if(bgem_path_relativeToFull(fragPath, sizeof(fragPath), bgem_shader_catalog[i].frag)) { return BGEM_ERROR_IO; } bgem_shader_compiledPrograms[i] = bgem_shader_createProgram(vertPath, fragPath); } + /* TODO: This doesn't make sense. Look for other solutions */ + //if(bgem_shader_compiledPrograms[0] == (GLuint)0) { DEBUG_PRINT("ERROR: There are no programs in the list."); return BGEM_ERROR_IO; } + return BGEM_OK; } GLuint bgem_shader_get(const char *name) @@ -115,7 +137,7 @@ GLuint bgem_shader_get(const char *name) if (SDL_strcmp(bgem_shader_catalog[i].name, name) == 0) return bgem_shader_compiledPrograms[i]; } - return 0; /* Not found */ + return GL_NONE; /* Not found */ } void bgem_shader_destroyAll(void) diff --git a/source/system/system.c b/source/system/system.c index 142c48d..748cc54 100644 --- a/source/system/system.c +++ b/source/system/system.c @@ -33,11 +33,17 @@ int bgem_system_start(void) return EXIT_FAILURE; } - if(bgem_app_run(&cfg)) return EXIT_FAILURE; + if(bgem_app_run(&cfg)) goto cleanup; SDL_Quit(); /* Unlock instance once closing the program */ bgem_platform_instanceUnlock(); return EXIT_SUCCESS; + +cleanup: + SDL_Quit(); + bgem_platform_instanceUnlock(); + return EXIT_FAILURE; + } diff --git a/source/window/window.c b/source/window/window.c index 2ee9c47..7842419 100644 --- a/source/window/window.c +++ b/source/window/window.c @@ -24,8 +24,9 @@ bgem_window_handle* bgem_window_createWindow(bgem_config *cfg) SDL_Window *window; SDL_DisplayID display = SDL_GetPrimaryDisplay(); + if(display == 0) { DEBUG_PRINT("SDL_GetPrimaryDisplay error: %s", SDL_GetError()); return NULL; } float scale = SDL_GetDisplayContentScale(display); - if (scale <= 0.0f) scale = 1.0f; + if(scale <= 0.0f) { scale = 1.0f; DEBUG_PRINT("SDL_GetPrimaryDisplay error: %s", SDL_GetError()); return NULL; } int win_w = (int)((HOR_RES / SCL_DWN) * scale); int win_h = (int)((VER_RES / SCL_DWN) * scale); @@ -43,11 +44,14 @@ bgem_window_handle* bgem_window_createWindow(bgem_config *cfg) wh = (bgem_window_handle*)malloc(sizeof(bgem_window_handle)); + if (!wh) { SDL_DestroyWindow(window); return NULL; } wh->window = window; + wh->window_ctx = bgem_platform_createContext(wh->window); - if (!wh->window_ctx) { free(wh); return NULL; } + if (!wh->window_ctx) { SDL_DestroyWindow(window); free(wh); return NULL; } + wh->fullscreen = cfg->fullscreen; - SDL_SetWindowFullscreen(wh->window, wh->fullscreen); + if(!SDL_SetWindowFullscreen(wh->window, wh->fullscreen)) { DEBUG_PRINT("SDL_SetWindowFullscreen error: %s", SDL_GetError()); } return wh; } @@ -62,7 +66,7 @@ void bgem_window_handleResize(bgem_window_handle *wh, SDL_Event *event) bgem_platform_waylandResizeSurface(wh->window_ctx, w, h); #elif defined(__APPLE__) (void)event; /* Silence warning */ - SDL_GetWindowSizeInPixels(wh->window, &w, &h); + if(!SDL_GetWindowSizeInPixels(wh->window, &w, &h)) { DEBUG_PRINT("SDL_GetWindowSizeInPixels error: %s", SDL_GetError()); } #elif defined(_WIN32) w = event->window.data1; h = event->window.data2; @@ -74,5 +78,5 @@ void bgem_window_handleResize(bgem_window_handle *wh, SDL_Event *event) void bgem_window_toggleFullscreen(bgem_window_handle *wh) { wh->fullscreen = !wh->fullscreen; - SDL_SetWindowFullscreen(wh->window, wh->fullscreen); + if(!SDL_SetWindowFullscreen(wh->window, wh->fullscreen)) { DEBUG_PRINT("SDL_SetWindowFullscreen error: %s", SDL_GetError()); } } From 44431063eef7c89acf227171fec994a3053e2203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C4=83t=C4=83lin=20Gabriel=20Dr=C4=83ghi=C8=9B=C4=83?= Date: Thu, 21 May 2026 13:25:31 +0200 Subject: [PATCH 4/4] Isolate debug functions under a compiler flag --- include/core/debug.h | 18 ++++++++++++++++++ source/app/app.c | 4 ++-- source/renderer/render_loop.c | 6 +++--- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/include/core/debug.h b/include/core/debug.h index e1c0568..e8325e6 100644 --- a/include/core/debug.h +++ b/include/core/debug.h @@ -33,6 +33,7 @@ typedef enum { extern "C" { #endif +#ifdef DEBUG /** * @brief * Initialize the Imgui debug UI @@ -80,6 +81,23 @@ void bgem_debug_render(void); */ int bgem_debug_isActive(void); +#define BGEM_DEBUG_INIT(window) bgem_debug_init(window) +#define BGEM_DEBUG_SHUTDOWN() bgem_debug_shutdown() +#define BGEM_DEBUG_TOGGLE() bgem_debug_toggle() +#define BGEM_DEBUG_NEWFRAME() bgem_debug_newFrame() +#define BGEM_DEBUG_RENDER() bgem_debug_render() +#define BGEM_DEBUG_ISACTIVE() bgem_debug_isActive() + +#else +#define BGEM_DEBUG_INIT(window) ((void)0) +#define BGEM_DEBUG_SHUTDOWN() ((void)0) +#define BGEM_DEBUG_TOGGLE() ((void)0) +#define BGEM_DEBUG_NEWFRAME() ((void)0) +#define BGEM_DEBUG_RENDER() ((void)0) +#define BGEM_DEBUG_ISACTIVE() ((void)0) + +#endif + #ifdef __cplusplus } #endif diff --git a/source/app/app.c b/source/app/app.c index b68f8f4..386716e 100644 --- a/source/app/app.c +++ b/source/app/app.c @@ -22,11 +22,11 @@ int bgem_app_run(bgem_config *cfg) if(!SDL_GetWindowSizeInPixels(wh->window, &w, &h)) { DEBUG_PRINT("SDL_GetWindowSizeInPixels failed with %s", SDL_GetError()); return EXIT_FAILURE; } bgem_renderer_setWindowSize(w, h); if(bgem_renderer_init(cfg)) { DEBUG_PRINT("Failed to initialize the renderer."); return EXIT_FAILURE; } - bgem_debug_init(wh->window); + BGEM_DEBUG_INIT(wh->window); if(bgem_renderer_loop(wh, cfg)) { DEBUG_PRINT("Fatal error occurred!"); return EXIT_FAILURE; } - bgem_debug_shutdown(); + BGEM_DEBUG_SHUTDOWN(); bgem_renderer_destroyAllShaders(); free(wh); return EXIT_SUCCESS; diff --git a/source/renderer/render_loop.c b/source/renderer/render_loop.c index 745388c..c87c4bb 100644 --- a/source/renderer/render_loop.c +++ b/source/renderer/render_loop.c @@ -38,7 +38,7 @@ bgem_result bgem_renderer_loop(bgem_window_handle *wh, bgem_config *cfg) } if (event.type == SDL_EVENT_KEY_DOWN) { if (event.key.key == SDLK_B) { - bgem_debug_toggle(); + BGEM_DEBUG_TOGGLE(); } } if (event.type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED) { @@ -51,13 +51,13 @@ bgem_result bgem_renderer_loop(bgem_window_handle *wh, bgem_config *cfg) } } - bgem_debug_newFrame(); + BGEM_DEBUG_NEWFRAME(); bgem_renderer_render((float)limiter.elapsed); bgem_renderer_present(); - bgem_debug_render(); + BGEM_DEBUG_RENDER(); if(bgem_renderer_swap(wh->window_ctx) != EGL_SUCCESS) { status = BGEM_ERROR_GPU; running = 0; }