Skip to content

Instantly share code, notes, and snippets.

@Lightnet
Last active February 25, 2025 07:15
Show Gist options
  • Save Lightnet/d8bc56c508ccbe839400e3b1654c62f4 to your computer and use it in GitHub Desktop.
Save Lightnet/d8bc56c508ccbe839400e3b1654c62f4 to your computer and use it in GitHub Desktop.
raylib dll and static build options

raylib cmake static dll hotreload

License: MIT

raylib 5.5

raygui 4.0

Information:

Use Grok Beta 3 AI agent to improve the cmake build raylib and raygui example application.

To have two options to build dll or static. The dll is for hot reload while static is not hot reload.

Note it use VS2022 build.

Below is the Grok Beta 3 AI Agent Guide and Set Up. It been clean up to for clean code.

CMakeLists.txt:

How It Works:

Static Mode (USE_DLL_MODE OFF):

  • core.c is compiled into a static library (core.lib), linked into RaylibExample.exe with Raylib (raylib_static).
  • All Raylib and Raygui functions are directly available in the executable.

DLL Mode (USE_DLL_MODE ON):

  • core.c is compiled into a shared library (core.dll), and main.c loads it dynamically using LoadLibraryExA.
  • Function pointers bridge Raylib/Raygui functions from main.c to core.dll.
  • A shadow copy (core_temp_X.dll) is used to avoid locking core.dll, enabling hot reload.

CMakeLists.txt

set(USE_DLL_MODE OFF CACHE BOOL "Build with DLL support (hot reload enabled)" FORCE)

RaylibExample: Static and DLL Hot Reload Setup

Overview

RaylibExample is a C project demonstrating a simple Raylib application with Raygui integration, supporting both static linking and dynamic DLL hot reloading. It features a red background with a clickable "TEST BUTTON" and hot reload capability in DLL mode triggered by pressing 'R'. The project is built with CMake and runs on Windows, leveraging Raylib 5.5 and Raygui 4.0.

Features

  • Static Mode: Links core.c and Raylib statically into a single executable (RaylibExample.exe).
  • DLL Mode: Builds core.c as a dynamic library (core.dll), loaded at runtime with shadow copy hot reloading.
  • Hot Reload: In DLL mode, press 'R' to unload the current DLL, allowing rebuilds of core.dll, and automatically reload a new shadow copy after a short delay.
  • Raygui Integration: Displays a simple GUI button using Raygui’s GuiButton.
  • Cross-Mode Compatibility: Seamlessly switches between static and DLL modes via CMake flags.

Setup Guide

Prerequisites

  • CMake: Version 3.10 or higher.
  • C Compiler: MSVC (Windows) recommended; GCC/MinGW should work with adjustments.
  • Git: To fetch Raylib and Raygui dependencies.

Directory Structure

RaylibExample/
├── src/
│   ├── core.c        # Core functionality (drawing, input, DLL exports)
│   ├── main.c        # Entry point and DLL loading logic
│   └── core.h        # Header with function declarations
├── CMakeLists.txt    # Build configuration
└── README.md         # This guide

Build Instructions

  1. Clone or Prepare the Project

    • Ensure src/core.c, src/main.c, src/core.h, and CMakeLists.txt are in your project root.
  2. Configure CMake

    • Open a terminal in the project root.
    • Create a build directory:
      mkdir build
      cd build
  3. Build Static Mode (USE_DLL_MODE OFF)

    • Configure and build:
      cmake -S .. -B . -DUSE_DLL_MODE=OFF
      cmake --build . --verbose
    • Output: Debug/RaylibExample.exe
  4. Build DLL Mode (USE_DLL_MODE ON)

    • Configure and build:
      cmake -S .. -B . -DUSE_DLL_MODE=ON
      cmake --build . --verbose
    • Output: Debug/RaylibExample.exe and Debug/core.dll
  5. Run

    • Static Mode:
      Debug\RaylibExample.exe
    • DLL Mode:
      Debug\RaylibExample.exe
    • In DLL mode, press 'R' to trigger hot reload, rebuild core.dll, and wait ~1 second for reload.

Hot Reload Workflow (DLL Mode)

  • Run RaylibExample.exe.
  • Press 'R' to unload the current shadow DLL (e.g., core_temp.dll).
  • Rebuild core.dll in another terminal:
    cmake --build build --target core
  • Wait ~1 second; the app reloads a new shadow copy (e.g., core_temp_1.dll).

Function Pointers Explained:

In DLL mode, main.c dynamically loads core.dll and uses function pointers to bridge Raylib and Raygui functions between the executable and DLL.

How Pointers Work

  • Loading: LoadLibraryExA loads core.dll’s shadow copy into memory, returning a handle (HINSTANCE).
  • Function Pointers: GetProcAddress retrieves function addresses from core.dll (e.g., core_execute_loop), stored in variables like core_execute_loop_func.
  • Bridging: core_load_raylib_functions passes pointers to Raylib/Raygui functions (e.g., &InitWindow, &GuiButton) from main.c to core.dll, allowing the DLL to call them.

Example

core_load_raylib_functions_func(&InitWindow, &CloseWindow, ..., &GuiButton, &GuiSetStyle);
  • &InitWindow: Address of Raylib’s InitWindow function in main.c.
  • core.dll stores these in pointers (e.g., raylib_init_window) and calls them as needed.

Expanding Features with Raylib/Raygui

To add more Raylib or Raygui features (e.g., DrawText, GuiLabel):

Adding to core.c

  1. Static Mode: Directly use new functions (e.g., DrawText):
CORE void core_execute_loop() {
   raylib_begin_drawing();
   printf("Drawing frame\n");
   raylib_clear_background(RED);
   DrawText("Hello, Raylib!", 10, 10, 20, WHITE);  // Add Raylib text
   if (raygui_gui_button((Rectangle){ 500, 200, 250, 60 }, "TEST BUTTON")) {
       puts("Button pressed\n");
   }
   raylib_end_drawing();
}
  1. DLL Mode: Add function pointers in core.h and core.c
  • core.h
#if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)
    CORE void core_load_raylib_functions(
        ...,  // Existing parameters
        void (*const in_draw_text)(const char *text, int posX, int posY, int fontSize, Color color)  // Add DrawText
    );
#endif
  • core.c
#if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)
    void (*raylib_draw_text)(const char *text, int posX, int posY, int fontSize, Color color);
    CORE void core_load_raylib_functions(
        ...,  // Existing parameters
        void (*const in_draw_text)(const char *text, int posX, int posY, int fontSize, Color color)
    ) {
        raylib_draw_text = in_draw_text;
        ...
    }
    CORE void core_execute_loop() {
        raylib_begin_drawing();
        printf("Drawing frame\n");
        raylib_clear_background(RED);
        raylib_draw_text("Hello, Raylib!", 10, 10, 20, WHITE);  // Use pointer
        if (raygui_gui_button((Rectangle){ 500, 200, 250, 60 }, "TEST BUTTON")) {
            puts("Button pressed\n");
        }
        raylib_end_drawing();
    }
#endif
  • main.c
core_load_raylib_functions_func(&InitWindow, ..., &DrawText);

Adding to main.c (DLL Mode)

  • Update the call to pass new pointers
core_load_raylib_functions_func(&InitWindow, &CloseWindow, ..., &GuiButton, &GuiSetStyle, &DrawText);

Notes on Expansion

  • Raylib Functions: Add any Raylib function (e.g., DrawCircle, PlaySound) by extending the function pointer list in core_load_raylib_functions.
  • Raygui Controls: Add Raygui controls (e.g., GuiLabel) similarly by including them in the pointer list.
  • Synchronization: Ensure main.c and core.c agree on the function pointer signatures to avoid runtime errors.

This setup is now extensible—add features as needed following this pattern!

Credit:

# Minimum CMake version required to build this project
cmake_minimum_required(VERSION 3.10)
# Define the project name and language (C)
project(RaylibExample C)
# Set C standard to C11 and make it required
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
# Configure output directories for all build types
# Ensures binaries, libraries, and archives go to consistent locations in the build directory
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
# Specific output directories for Debug build type
# Keeps Debug builds organized in a Debug subdirectory
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${PROJECT_BINARY_DIR}/Debug")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${PROJECT_BINARY_DIR}/Debug")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${PROJECT_BINARY_DIR}/Debug")
# Disable shared library builds by default (favor static linking unless specified)
# This ensures Raylib and other dependencies are statically linked unless overridden
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Default to static libs" FORCE)
# Toggle between static and DLL modes (hot reload enabled in DLL mode)
# USE_DLL_MODE controls whether the project builds with a dynamic core.dll or static linking
set(USE_DLL_MODE OFF CACHE BOOL "Build with DLL support (hot reload enabled)" FORCE)
message(STATUS "USE_DLL_MODE: ${USE_DLL_MODE}")
# Configure build settings based on USE_DLL_MODE
if (USE_DLL_MODE)
# Enable DLL mode: Build core as a shared library (core.dll)
set(BUILD_LIBTYPE_SHARED ON CACHE BOOL "Build core as a shared library" FORCE)
add_definitions(-DCORE_USE_LIBTYPE_SHARED) # Define macro for main.c to use DLL logic
add_definitions(-DBUILD_LIBTYPE_SHARED) # Define macro for core.c to export DLL functions
else()
# Static mode: Build core statically into the executable
set(BUILD_LIBTYPE_SHARED OFF CACHE BOOL "Build core statically" FORCE)
remove_definitions(-DCORE_USE_LIBTYPE_SHARED) # Remove DLL-specific macros
remove_definitions(-DBUILD_LIBTYPE_SHARED)
endif()
message(STATUS "BUILD_LIBTYPE_SHARED: ${BUILD_LIBTYPE_SHARED}")
# Fetch external dependencies (Raylib and Raygui) from GitHub
include(FetchContent)
# Declare Raylib dependency
# Downloads Raylib 5.5 from GitHub and makes it available for the build
FetchContent_Declare(
raylib
GIT_REPOSITORY https://github.com/raysan5/raylib.git
GIT_TAG 5.5
)
FetchContent_MakeAvailable(raylib)
# Declare Raygui dependency
# Downloads Raygui 4.0 from GitHub for GUI functionality
FetchContent_Declare(
raygui
GIT_REPOSITORY https://github.com/raysan5/raygui.git
GIT_TAG 4.0
)
FetchContent_MakeAvailable(raygui)
# Define the main executable target (RaylibExample) from main.c
add_executable(${PROJECT_NAME} src/main.c)
# Set include directories for the executable
# Ensures main.c can find headers from project, Raylib, and Raygui
target_include_directories(${PROJECT_NAME} PUBLIC
${CMAKE_SOURCE_DIR}/include # Custom project includes (if any)
${raylib_SOURCE_DIR}/src # Raylib source headers
${raygui_SOURCE_DIR}/src # Raygui source headers
)
# Configure core library based on build mode
if (USE_DLL_MODE)
# DLL mode: Build core.c as a shared library (core.dll)
add_library(core SHARED src/core.c)
target_link_libraries(core PUBLIC raylib_static) # Link core.dll with static Raylib
else()
# Static mode: Build core.c as a static library and link it into the executable
add_library(core STATIC src/core.c)
target_link_libraries(${PROJECT_NAME} PUBLIC core) # Link core into RaylibExample.exe
target_link_libraries(core PUBLIC raylib_static) # Link core with static Raylib
endif()
# Set include directories for the core library
# Ensures core.c can find headers from project, Raylib, and Raygui
target_include_directories(core PUBLIC
${CMAKE_SOURCE_DIR}/include # Custom project includes (if any)
${raylib_SOURCE_DIR}/src # Raylib source headers
${raygui_SOURCE_DIR}/src # Raygui source headers
)
# Set output name for core library (core.dll or core.lib)
set_target_properties(core PROPERTIES OUTPUT_NAME "core")
# Link the executable with static Raylib (always required)
target_link_libraries(${PROJECT_NAME} PUBLIC raylib_static)
# Additional Windows-specific libraries for Raylib
# Required for audio (winmm) and graphics (gdi32)
if (WIN32)
target_link_libraries(${PROJECT_NAME} PUBLIC winmm.lib gdi32.lib)
target_link_libraries(core PUBLIC winmm.lib gdi32.lib)
endif()
# MSVC-specific compile definitions to suppress warnings
if (MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS /wd4267) # Disable deprecated warnings and size_t conversion warnings
endif()
# Post-build step for DLL mode: Copy core.dll to the runtime directory
# Ensures core.dll is available next to RaylibExample.exe for loading
if (USE_DLL_MODE)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG}/core.dll"
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG}"
)
endif()
# Notes:
# - USE_DLL_MODE toggles between static linking (OFF) and DLL hot reloading (ON).
# - BUILD_LIBTYPE_SHARED is set based on USE_DLL_MODE to control core library type.
# - Raylib is built statically (raylib_static) and linked into both core and the executable.
# - Raygui is a single-header library; its implementation is defined in core.c or main.c
# depending on the mode (static: core.c, DLL: main.c).
# - The shadow copy mechanism in main.c (DLL mode) allows rebuilding core.dll without file locking.
// core.c implements core functionality for both static and DLL modes
#include "core.h"
// Raygui implementation is defined only in static mode here
// In DLL mode, main.c provides the implementation for function pointers
#if !defined(CORE_USE_LIBTYPE_SHARED)
#define RAYGUI_IMPLEMENTATION // Define Raygui implementation for static mode
#endif
#include "raygui.h" // Include Raygui after defining implementation (if applicable)
// DLL-specific function pointers and logic
#if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)
// Function pointers for Raylib and Raygui functions, loaded dynamically in DLL mode
void (*raylib_init_window)(int width, int height, const char* title);
void (*raylib_close_window)();
bool (*raylib_window_should_close)();
void (*raylib_begin_drawing)();
void (*raylib_end_drawing)();
void (*raylib_clear_background)(Color color);
int (*raylib_get_key_pressed)();
int (*raygui_gui_button)(Rectangle bounds, const char *text);
void (*raygui_gui_set_style)(int control, int property, int value);
// Loads Raylib and Raygui functions from main.c into the DLL
CORE void core_load_raylib_functions(
void (*const in_init_window)(int width, int height, const char* title),
void (*const in_close_window)(),
bool (*const in_window_should_close)(),
void (*const in_begin_drawing)(),
void (*const in_end_drawing)(),
void (*const in_clear_background)(Color color),
int (*const in_get_key_pressed)(),
int (*const in_gui_button)(Rectangle bounds, const char *text),
void (*const in_gui_set_style)(int control, int property, int value)
) {
printf("Loading Raylib functions into DLL\n");
raylib_init_window = in_init_window; // Assign window init function
raylib_close_window = in_close_window; // Assign window close function
raylib_window_should_close = in_window_should_close; // Assign close check
raylib_begin_drawing = in_begin_drawing; // Assign drawing start
raylib_end_drawing = in_end_drawing; // Assign drawing end
raylib_clear_background = in_clear_background; // Assign background clear
raylib_get_key_pressed = in_get_key_pressed; // Assign key input
raygui_gui_button = in_gui_button; // Assign GUI button
raygui_gui_set_style = in_gui_set_style; // Assign GUI style setter
}
// Hot reload state variable and getter (DLL-specific)
char core_active_hot_reload = 0; // Tracks if 'R' was pressed for reload
CORE void core_get_value_hot_reload(char* out_index) {
//printf("core_get_value_hot_reload called\n");
*out_index = core_active_hot_reload; // Returns reload state
}
#else
// Static mode: Map Raylib/Raygui functions directly to their implementations
#define raylib_init_window InitWindow
#define raylib_close_window CloseWindow
#define raylib_window_should_close WindowShouldClose
#define raylib_begin_drawing BeginDrawing
#define raylib_end_drawing EndDrawing
#define raylib_clear_background ClearBackground
#define raylib_get_key_pressed GetKeyPressed
#define raygui_gui_button GuiButton
#define raygui_gui_set_style GuiSetStyle
#endif
// Initializes window settings (called after InitWindow in main.c)
CORE void core_init_window(void) {
printf("Setting up window\n");
if (!IsWindowReady()) {
printf("Warning: Window not fully ready, skipping setup\n");
return; // Skip setup if window isn’t initialized
}
printf("Window is ready\n");
SetTargetFPS(60); // Set frame rate to 60 FPS (safe Raylib call)
printf("FPS set to 60\n");
printf("Window setup complete\n");
}
// Main loop iteration: handles input and drawing
CORE void core_execute_loop() {
int key_pressed = raylib_get_key_pressed(); // Get any pressed key
if (key_pressed != 0) {
printf("Key pressed: %d\n", key_pressed); // Log key code
}
#if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)
if (key_pressed == KEY_R) { // Check for 'R' key (Raylib key code 82)
core_active_hot_reload = 1; // Set reload flag for DLL mode
printf("Key pressed 'R' for reload ...\n");
}
#else
if (key_pressed == KEY_R) { // Check for 'R' key in static mode
printf("Key pressed 'R' in static mode (no reload)\n");
}
#endif
raylib_begin_drawing(); // Start drawing frame (Raylib)
//printf("Drawing frame\n");
raylib_clear_background(RED); // Clear background with red (Raylib)
if (raygui_gui_button((Rectangle){ 500, 200, 250, 60 }, "TEST BUTTON ASD")) { // Draw button (Raygui)
puts("Button pressed\n"); // Log button press
}
raylib_end_drawing(); // End drawing frame (Raylib)
}
// Checks if the window should close (e.g., close button clicked)
CORE bool core_window_should_close() {
bool should_close = raylib_window_should_close();
//printf("Window should close: %d\n", should_close);
return should_close;
}
// Cleanup function to close the window
CORE void core_exit() {
printf("Closing window\n");
raylib_close_window(); // Close the window (Raylib)
}
#pragma once
#include <stdbool.h>
#include "raylib.h" // Raylib core header for window, drawing, and input functions
#include "raygui.h" // Raygui header for GUI elements (e.g., GuiButton), included as header-only
// Windows-specific header for DLL mode (BUILD_LIBTYPE_SHARED or CORE_USE_LIBTYPE_SHARED)
// Only included when compiling on Windows and using DLL functionality
#if defined(_WIN32) && (defined(CORE_USE_LIBTYPE_SHARED) || defined(BUILD_LIBTYPE_SHARED))
#define WIN32_LEAN_AND_MEAN // Reduces Windows.h bloat by excluding rarely-used APIs
#define NOGDI // Excludes GDI (Graphics Device Interface) APIs
#define NOUSER // Excludes USER (window management) APIs
#include <windows.h> // Required for __declspec and Windows-specific definitions (_WIN32, _M_X64)
#endif
// Define CORE macro for export/import based on build mode
#if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)
#define CORE __declspec(dllexport) // Export functions from core.dll when building the DLL
#elif defined(_WIN32) && defined(CORE_USE_LIBTYPE_SHARED)
#define CORE __declspec(dllimport) // Import functions from core.dll when using the DLL
#else
#define CORE // No decoration for static mode
#endif
// Core functions available in both static and DLL modes
CORE void core_init_window(void); // Initializes window settings (e.g., FPS)
CORE void core_execute_loop(void); // Main loop iteration (drawing, input handling)
CORE bool core_window_should_close(void); // Checks if the window should close
CORE void core_exit(void); // Cleans up and closes the window
// DLL-specific functions (only available when building or using the DLL)
#if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)
// Loads Raylib and Raygui function pointers into the DLL
CORE void core_load_raylib_functions(
void (*const in_init_window)(int width, int height, const char* title), // Initializes window
void (*const in_close_window)(), // Closes window
bool (*const in_window_should_close)(), // Checks window closure
void (*const in_begin_drawing)(), // Begins frame drawing
void (*const in_end_drawing)(), // Ends frame drawing
void (*const in_clear_background)(Color color), // Clears background
int (*const in_get_key_pressed)(), // Gets pressed key
int (*const in_gui_button)(Rectangle bounds, const char *text), // Draws GUI button
void (*const in_gui_set_style)(int control, int property, int value) // Sets GUI style
);
CORE void core_get_value_hot_reload(char* out_index); // Gets hot reload state
#endif
// main.c serves as the entry point for both static and DLL modes
#include "core.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // For strcpy, strcat
#if defined(CORE_USE_LIBTYPE_SHARED)
#include <libloaderapi.h> // Windows-specific for LoadLibraryExA and GetProcAddress
#include <windows.h> // For CopyFileA, Sleep
#include "raylib.h" // Raylib header for InitWindow and other functions
#define RAYGUI_IMPLEMENTATION // Define Raygui implementation for DLL mode
#include "raygui.h" // Include Raygui with implementation
#endif
int main() {
#if defined(CORE_USE_LIBTYPE_SHARED)
// DLL mode: Load core.dll dynamically and use function pointers with shadow copy
printf("DLL mode enabled\n");
HINSTANCE dll_handle = NULL; // Handle to the loaded DLL (shadow copy)
char dll_path[256] = "core_temp.dll"; // Path to the initial shadow copy of core.dll
void (*core_load_raylib_functions_func)(
void (*const in_init_window)(int width, int height, const char* title),
void (*const in_close_window)(),
bool (*const in_window_should_close)(),
void (*const in_begin_drawing)(),
void (*const in_end_drawing)(),
void (*const in_clear_background)(Color color),
int (*const in_get_key_pressed)(),
int (*const in_gui_button)(Rectangle bounds, const char *text),
void (*const in_gui_set_style)(int control, int property, int value)
); // Function pointer to load Raylib/Raygui functions into DLL
void (*core_init_window_func)(void); // Setup window
void (*core_execute_loop_func)(); // Main loop
void (*core_get_value_hot_reload_func)(char* out_index); // Hot reload state getter
void (*core_exit_func)(); // Cleanup
bool (*core_window_should_close_func)(); // Window close check
char activate_hot_reload = 0; // Hot reload flag in main.c, synced with DLL
int reload_delay = 0; // Delay counter for reload grace period
// Initialize the window in main.c for DLL mode
printf("Initializing window in main\n");
InitWindow(800, 600, "Raylib Example"); // Create 800x600 window
if (!IsWindowReady()) {
printf("Window failed to initialize in main!\n");
exit(1); // Exit if window creation fails
}
printf("Window initialized in main\n");
// Create initial shadow copy of core.dll
if (!CopyFileA("core.dll", dll_path, FALSE)) {
printf("Failed to create shadow copy of core.dll\n");
exit(1);
}
// Load the shadow copy of core.dll
printf("Loading %s\n", dll_path);
dll_handle = LoadLibraryExA(dll_path, NULL, 0); // Load shadow copy
if (dll_handle != NULL) {
printf("DLL loaded successfully\n");
core_load_raylib_functions_func = (void*)GetProcAddress(dll_handle, "core_load_raylib_functions");
if (NULL == core_load_raylib_functions_func) {
printf("Can't call core_load_raylib_functions dll function\n");
exit(1);
} else {
printf("Bridging Raylib functions\n");
// Pass Raylib and Raygui functions to the DLL
core_load_raylib_functions_func(
&InitWindow, &CloseWindow, &WindowShouldClose,
&BeginDrawing, &EndDrawing, &ClearBackground,
&GetKeyPressed, &GuiButton, &GuiSetStyle
);
}
core_init_window_func = (void*)GetProcAddress(dll_handle, "core_init_window");
if (NULL == core_init_window_func) {
printf("Can't call core_init_window dll function\n");
exit(1);
} else {
printf("Calling core_init_window\n");
core_init_window_func(); // Set up window properties
}
core_execute_loop_func = (void*)GetProcAddress(dll_handle, "core_execute_loop");
if (NULL == core_execute_loop_func) {
printf("Can't call core_execute_loop dll function\n");
exit(1);
}
core_get_value_hot_reload_func = (void*)GetProcAddress(dll_handle, "core_get_value_hot_reload");
if (NULL == core_get_value_hot_reload_func) {
printf("Can't call core_get_value_hot_reload dll function\n");
exit(1);
}
core_exit_func = (void*)GetProcAddress(dll_handle, "core_exit");
if (NULL == core_exit_func) {
printf("Can't call core_exit dll function\n");
exit(1);
}
core_window_should_close_func = (void*)GetProcAddress(dll_handle, "core_window_should_close");
if (NULL == core_window_should_close_func) {
printf("Can't call core_window_should_close dll function\n");
exit(1);
}
} else {
printf("Can't load %s\n", dll_path);
exit(1);
}
char temp_dll_path[256]; // Buffer for new temp DLL path
int reload_count = 0; // Counter for unique temp DLL names
#else
// Static mode: Directly call core functions linked into the executable
printf("Static mode (no reload)\n");
InitWindow(800, 600, "Raylib Example"); // Initialize window
if (!IsWindowReady()) {
printf("Window failed to initialize in static mode!\n");
exit(1);
}
printf("Window initialized in static mode\n");
core_init_window(); // Set up window properties
#endif
printf("Entering main loop\n");
int loop_count = 0;
while (1) {
#if defined(CORE_USE_LIBTYPE_SHARED)
core_execute_loop_func(); // Call DLL’s loop function
//printf("Loop iteration %d\n", ++loop_count);
// Check hot reload state from DLL and update local flag
char hot_reload_state = 0;
core_get_value_hot_reload_func(&hot_reload_state); // Fetch reload state
if (hot_reload_state == 1 && activate_hot_reload == 0) {
activate_hot_reload = 1; // Sync local flag with DLL state
reload_delay = 60; // Set delay (e.g., 60 frames ~1 sec at 60 FPS)
printf("Hot reload triggered, waiting for rebuild...\n");
}
if (core_window_should_close_func && core_window_should_close_func()) {
break; // Exit loop if window should close
}
// Handle hot reload with delay instead of blocking
if (activate_hot_reload == 1) {
if (reload_delay > 0) {
reload_delay--; // Decrement delay counter
continue; // Keep loop running to avoid freeze
}
FreeLibrary(dll_handle); // Unload current shadow DLL
printf("Unloaded %s\n", dll_path);
// Create a new unique shadow copy (e.g., core_temp_1.dll, core_temp_2.dll)
sprintf(temp_dll_path, "core_temp_%d.dll", ++reload_count);
if (!CopyFileA("core.dll", temp_dll_path, FALSE)) {
printf("Failed to create new shadow copy %s\n", temp_dll_path);
exit(1);
}
strcpy(dll_path, temp_dll_path); // Update dll_path to new temp file
Sleep(1000); // Wait 1 second for rebuild (adjust as needed)
// Load the new shadow copy
printf("Loading %s\n", dll_path);
dll_handle = LoadLibraryExA(dll_path, NULL, 0);
if (NULL != dll_handle) {
core_load_raylib_functions_func = (void*)GetProcAddress(dll_handle, "core_load_raylib_functions");
if (NULL == core_load_raylib_functions_func) {
printf("Can't call core_load_raylib_functions dll function\n");
exit(1);
} else {
core_load_raylib_functions_func(
&InitWindow, &CloseWindow, &WindowShouldClose,
&BeginDrawing, &EndDrawing, &ClearBackground,
&GetKeyPressed, &GuiButton, &GuiSetStyle
);
}
core_execute_loop_func = (void*)GetProcAddress(dll_handle, "core_execute_loop");
if (NULL == core_execute_loop_func) {
printf("Can't call core_execute_loop dll function\n");
exit(1);
}
core_get_value_hot_reload_func = (void*)GetProcAddress(dll_handle, "core_get_value_hot_reload");
if (NULL == core_get_value_hot_reload_func) {
printf("Can't call core_get_value_hot_reload dll function\n");
exit(1);
}
core_exit_func = (void*)GetProcAddress(dll_handle, "core_exit");
if (NULL == core_exit_func) {
printf("Can't call core_exit dll function\n");
exit(1);
}
core_window_should_close_func = (void*)GetProcAddress(dll_handle, "core_window_should_close");
if (NULL == core_window_should_close_func) {
printf("Can't call core_window_should_close dll function\n");
exit(1);
}
printf("Reloaded %s successfully\n", dll_path);
} else {
printf("Can't load %s\n", dll_path);
exit(1);
}
activate_hot_reload = 0; // Reset reload flag
}
#else
core_execute_loop(); // Call static loop function
//printf("Loop iteration %d\n", ++loop_count);
if (core_window_should_close()) {
break; // Exit loop if window should close
}
#endif
}
#if defined(CORE_USE_LIBTYPE_SHARED)
core_exit_func(); // Call DLL’s cleanup
FreeLibrary(dll_handle); // Free DLL handle
DeleteFileA(dll_path); // Clean up the last shadow copy
#else
core_exit(); // Call static cleanup
#endif
printf("Exiting program\n");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment