Created
January 23, 2020 15:37
-
-
Save chrisdill/291c938605c200d079a88d0a7855f31a to your computer and use it in GitHub Desktop.
A fun little test of a SDL2 platform layer for hot code reloading with rayfork
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
INCLUDES="-I../../dependencies/cgltf -I../../dependencies/dr_libs -I../../dependencies/jar -I../../dependencies/miniaudio -I../../dependencies/par -I../../dependencies/stb -I../../dependencies/tinyobjloader-c -I../../examples/dependencies/ -I../../examples/dependencies/sokol -I../../rayfork" | |
if [ "$(uname)" = "Darwin" ] | |
then | |
FLAGS="-g -D_DEFAULT_SOURCE -ObjC -fobjc-arc" | |
LIBRARIES="-framework Cocoa" | |
else | |
FLAGS="-g -D_DEFAULT_SOURCE" | |
LIBRARIES="-lGL -lm -lpthread -ldl -lrt -lX11" | |
fi | |
mkdir -p bin | |
pushd bin | |
mkdir -p hot_code_reloading | |
pushd hot_code_reloading | |
echo -e '\n' | |
echo Building hot_code_reloading example | |
#gcc -o hot_code_reloading ../../examples/hot_code_reloading/sdl_main.c ../../examples/hot_code_reloading/game.c ../../examples/dependencies/glad/glad.c $FLAGS $INCLUDES $LIBRARIES -I/usr/include/SDL2/ -L/usr/lib/ -lSDL2; | |
gcc -c -fpic -o hot_code_reloading_dynamic.o ../../examples/hot_code_reloading/game.c -I../../examples/hot_code_reloading/ $FLAGS $INCLUDES $LIBRARIES #/EXPORT:game_init /EXPORT:game_update /EXPORT:game_refresh | |
#gcc -c -fpic -o glad.o ../../examples/dependencies/glad/glad.c -I../../examples/hot_code_reloading/ $FLAGS $INCLUDES $LIBRARIES #/EXPORT:game_init /EXPORT:game_update /EXPORT:game_refresh | |
gcc -shared hot_code_reloading_dynamic.o glad.o -o hot_code_reloading_dynamic.so | |
popd | |
popd |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// In this file we only initialise the window using sdl | |
#include <SDL2/SDL.h> | |
#include <assert.h> | |
void on_init(void); | |
void on_frame(void); | |
#include "game.h" | |
//Functions we call from the dll | |
typedef void (*game_init_func_t)(game_data* game_data); | |
typedef void (*game_refresh_func_t)(game_data* game_data); | |
typedef void (*game_update_func_t)(void); | |
//Stubs for when we the dll functions are not loaded | |
void game_init_stub(game_data* it) {} | |
void game_refresh_stub(game_data* it) {} | |
void game_update_stub(void) {} | |
typedef struct sdl_game_code sdl_game_code; | |
struct sdl_game_code | |
{ | |
void* game_code_dll; | |
game_init_func_t game_init; | |
game_refresh_func_t game_refresh; | |
game_update_func_t game_update; | |
bool is_valid; | |
}; | |
sdl_game_code game_code; | |
game_data game; | |
SDL_bool CopyFile(const char* source_dll_name, const char* temp_dll_name) | |
{ | |
SDL_RWops *source = SDL_RWFromFile(source_dll_name, "r"); | |
SDL_RWops *target = SDL_RWFromFile(temp_dll_name, "w"); | |
// Read source into buffer | |
Sint64 size = SDL_RWsize(source); | |
void * buffer = SDL_calloc(1, size); | |
SDL_RWread(source, buffer, size, 1); | |
// Write buffer to target | |
SDL_RWwrite(target, buffer, size, 1); | |
printf("File copied successfully.\n"); | |
SDL_RWclose(source); | |
SDL_RWclose(target); | |
SDL_free(buffer); | |
return SDL_TRUE; | |
} | |
sdl_game_code sdl_load_game_code(const char* source_dll_name, const char* temp_dll_name) | |
{ | |
sdl_game_code result = {0}; | |
assert(CopyFile(source_dll_name, temp_dll_name)); | |
result.game_code_dll = SDL_LoadObject(source_dll_name); | |
if (result.game_code_dll == NULL) | |
{ | |
printf("SDL_LoadObject failed: %s\n", SDL_GetError()); | |
} | |
assert(result.game_code_dll); | |
result.game_init = (game_init_func_t) SDL_LoadFunction(result.game_code_dll, "game_init"); | |
result.game_update = (game_update_func_t) SDL_LoadFunction(result.game_code_dll, "game_update"); | |
result.game_refresh = (game_refresh_func_t) SDL_LoadFunction(result.game_code_dll, "game_refresh"); | |
assert(result.game_init && result.game_update && result.game_refresh); | |
result.is_valid = true; | |
return result; | |
} | |
void sdl_unload_game_code(sdl_game_code* game_code) | |
{ | |
if (game_code->game_code_dll) | |
{ | |
SDL_UnloadObject(game_code->game_code_dll); | |
game_code->game_code_dll = NULL; | |
} | |
game_code->is_valid = false; | |
game_code->game_init = game_init_stub; | |
game_code->game_update = game_update_stub; | |
game_code->game_refresh = game_refresh_stub; | |
} | |
void on_init(void) | |
{ | |
game_code = sdl_load_game_code("./hot_code_reloading_dynamic.so", "./hot_code_reloading_temp.so"); | |
assert(game_code.is_valid); | |
game.alloc = malloc; | |
game.free = free; | |
game.screen_width = 800; | |
game.screen_height = 450; | |
game_code.game_init(&game); | |
} | |
int main(int argc, char *argv[]) | |
{ | |
// -------------------------- | |
// Initialization | |
// -------------------------- | |
SDL_bool running = SDL_TRUE; | |
if (SDL_Init(SDL_INIT_VIDEO) != 0) | |
{ | |
fprintf(stderr, "SDL_Init Error: %s\n", SDL_GetError()); | |
return EXIT_FAILURE; | |
} | |
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); | |
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); | |
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); | |
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); | |
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32); | |
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); | |
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); | |
// 3.3 core mode | |
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); | |
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); | |
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); | |
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); | |
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); | |
SDL_Window *window = SDL_CreateWindow("SDL PLATFORM LAYER!", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 450, | |
SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | | |
SDL_WINDOW_RESIZABLE); | |
if (window == NULL) | |
{ | |
fprintf(stderr, "SDL_CreateWindow Error: %s\n", SDL_GetError()); | |
return EXIT_FAILURE; | |
} | |
SDL_GLContext context = SDL_GL_CreateContext(window); | |
if (context == NULL) | |
{ | |
fprintf(stderr, "SDL_CreateContext Error: %s\n", SDL_GetError()); | |
return EXIT_FAILURE; | |
} | |
on_init(); | |
while (running) | |
{ | |
// Update | |
SDL_Event event; | |
while (SDL_PollEvent(&event)) | |
{ | |
switch (event.type) | |
{ | |
case SDL_QUIT: | |
running = SDL_FALSE; | |
case SDL_WINDOWEVENT: | |
{ | |
if (event.window.event == SDL_WINDOWEVENT_CLOSE) | |
{ | |
running = SDL_FALSE; | |
} | |
else if (event.window.event == SDL_WINDOWEVENT_RESIZED) | |
{ | |
rf_gl_viewport(0, 0, event.window.data1, event.window.data2); | |
} | |
break; | |
} | |
case SDL_KEYDOWN: | |
if (event.key.keysym.sym == SDLK_ESCAPE) | |
{ | |
running = SDL_FALSE; | |
} | |
// // When the user presses R we try to hot reload the code. | |
if (event.key.keysym.sym == SDLK_r) | |
{ | |
sdl_unload_game_code(&game_code); | |
game_code = sdl_load_game_code("./hot_code_reloading_dynamic.so", "./hot_code_reloading_temp.so"); | |
game_code.game_refresh(&game); | |
} | |
} | |
} | |
if (game_code.is_valid) | |
{ | |
game_code.game_update(); | |
} | |
SDL_GL_SwapWindow(window); | |
} | |
// Cleanup | |
SDL_GL_DeleteContext(context); | |
SDL_DestroyWindow(window); | |
SDL_Quit(); | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I was interested in the idea of the platform layer being seperate from the game but the example for rayfork only works on windows. I thought it would be cool to try a layer with SDL2. Mostly converting win32 calls to similar SDL2 versions.
I compile glad.c and game.c as seperate objects then link them into one shared library, hot_code_reloading_dynamic.so.
This can be improved further. I think there might be a way to skip compiling the individual object files first but I am not a expert in compiling. Also adding better error checking and making it work with .dlls as well so the SDL2 layer can work on Windows as well as Linux.