From 200968a2abb9a02c41caaf2ef28e8b1fba548f29 Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Tue, 30 Jun 2026 19:42:23 -0700 Subject: [PATCH] Test out an optional render callback --- examples/core/core_basic_window.c | 31 +++++++++++--------------- src/platforms/rcore_desktop_glfw.c | 28 ++++++++++++++++++++++++ src/raylib.h | 1 + src/rcore.c | 35 ++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 18 deletions(-) diff --git a/examples/core/core_basic_window.c b/examples/core/core_basic_window.c index c1009fc76..b43662d2e 100644 --- a/examples/core/core_basic_window.c +++ b/examples/core/core_basic_window.c @@ -28,6 +28,18 @@ #include "raylib.h" +bool RunFrame(void) +{ + if (WindowShouldClose()) + return false; + + ClearBackground(RAYWHITE); + + DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY); + + return true; +} + //------------------------------------------------------------------------------------ // Program main entry point //------------------------------------------------------------------------------------ @@ -44,24 +56,7 @@ int main(void) //-------------------------------------------------------------------------------------- // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key - { - // Update - //---------------------------------------------------------------------------------- - // TODO: Update your variables here - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(RAYWHITE); - - DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY); - - EndDrawing(); - //---------------------------------------------------------------------------------- - } + RunGameLoop(RunFrame); // De-Initialization //-------------------------------------------------------------------------------------- diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index 55b92ac79..f776a10e4 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -1432,6 +1432,33 @@ static void DeallocateWrapper(void *block, void *user) RL_FREE(block); } +void WindowRefreshCallback(GLFWwindow* window) +{ + if (window != platform.handle || CORE.Window.updateCallback == NULL) + { + return; + } + + CORE.Window.updateCallback(); + + rlDrawRenderBatchActive(); + SwapScreenBuffer(); + CORE.Time.current = GetTime(); + CORE.Time.draw = CORE.Time.current - CORE.Time.previous; + CORE.Time.previous = CORE.Time.current; + + SwapScreenBuffer(); // Copy back buffer to front buffer (screen) + + // Frame time control system + CORE.Time.current = GetTime(); + CORE.Time.draw = CORE.Time.current - CORE.Time.previous; + CORE.Time.previous = CORE.Time.current; + + CORE.Time.frame = CORE.Time.update + CORE.Time.draw; + + CORE.Time.frameCounter++; +} + // Initialize platform: graphics, inputs and more int InitPlatform(void) { @@ -1808,6 +1835,7 @@ int InitPlatform(void) glfwSetWindowIconifyCallback(platform.handle, WindowIconifyCallback); glfwSetWindowFocusCallback(platform.handle, WindowFocusCallback); glfwSetDropCallback(platform.handle, WindowDropCallback); + glfwSetWindowRefreshCallback(platform.handle, WindowRefreshCallback); if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) glfwSetWindowContentScaleCallback(platform.handle, WindowContentScaleCallback); // Set input callback events diff --git a/src/raylib.h b/src/raylib.h index e49d6b2f7..c40f1dfc4 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -987,6 +987,7 @@ extern "C" { // Prevents name mangling of functions // Window-related functions RLAPI void InitWindow(int width, int height, const char *title); // Initialize window and OpenGL context RLAPI void CloseWindow(void); // Close window and unload OpenGL context +RLAPI void RunGameLoop(bool(*processFrame)(void)); // (Optional), Run an automatic game loop using the defined callback, calls Begin/EndDrawing for you. RLAPI bool WindowShouldClose(void); // Check if application should close (KEY_ESCAPE pressed or windows close icon clicked) RLAPI bool IsWindowReady(void); // Check if window has been initialized successfully RLAPI bool IsWindowFullscreen(void); // Check if window is currently fullscreen diff --git a/src/rcore.c b/src/rcore.c index 070b8c0c4..be01019d9 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -318,6 +318,8 @@ typedef struct CoreData { char **dropFilepaths; // Store dropped files paths pointers (provided by GLFW) unsigned int dropFileCount; // Count dropped files strings + bool(*updateCallback)(void); // Optional user defined callback to draw a frame + } Window; struct { const char *basePath; // Base path for data storage @@ -737,6 +739,39 @@ void CloseWindow(void) TRACELOG(LOG_INFO, "Window closed successfully"); } +static bool RunLoop = false; + +void ProcessSingleFrame(void) +{ + BeginDrawing(); + RunLoop = CORE.Window.updateCallback(); + EndDrawing(); + +#if defined(SUPPORT_CUSTOM_FRAME_CONTROL) + SwapBuffers(); + PollInputEvents(); +#endif +} + +#if defined(PLATFORM_WEB) +#include +#endif + +void RunGameLoop(bool(*processFrame)(void)) +{ + RunLoop = true; + CORE.Window.updateCallback = processFrame; + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(ProcessSingleFrame, 0, 1); +#else + while (RunLoop) + { + ProcessSingleFrame(); + } +#endif +} + // Check if window has been initialized successfully bool IsWindowReady(void) {