summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAmin Mesbah <mesbahamin@gmail.com>2017-11-12 23:48:23 -0800
committerAmin Mesbah <mesbahamin@gmail.com>2017-11-12 23:48:23 -0800
commitc2c55a82dd0020e95fbdb6818c867b6bc119f04f (patch)
tree053c20d230c67320a684f967bebc22b3b6895071 /src
parent90d407e2bf9dbd0ab624e8d66b0f65b1faec2443 (diff)
parentbf8ce781521b7eac2f95ea01895175ca661f2c3b (diff)
downloadohsp-c2c55a82dd0020e95fbdb6818c867b6bc119f04f.zip
ohsp-c2c55a82dd0020e95fbdb6818c867b6bc119f04f.tar.gz
Merge branch 'features/live-reload'
Diffstat (limited to 'src')
-rw-r--r--src/game.c20
-rw-r--r--src/game.h4
-rw-r--r--src/platform_sdl.c23
-rw-r--r--src/platform_sdl.h13
-rw-r--r--src/util_linux.h78
5 files changed, 125 insertions, 13 deletions
diff --git a/src/game.c b/src/game.c
index b43f8c9..015f6a3 100644
--- a/src/game.c
+++ b/src/game.c
@@ -62,19 +62,19 @@ void game_update(struct GameState *game_state, struct GameControllerInput game_i
game_state->thrust_vector01.angle = atan2f(game_input.left_stick_y, game_input.left_stick_x);
game_state->thrust_vector01.length = hypotf(game_input.left_stick_x, game_input.left_stick_y);
- printf("(lx: %f, ly: %f, thrust_a: %f, thrust_l: %f)\n",
- game_input.left_stick_x,
- game_input.left_stick_y,
- game_state->thrust_vector01.angle,
- game_state->thrust_vector01.length);
+ //printf("(lx: %f, ly: %f, thrust_a: %f, thrust_l: %f)\n",
+ // game_input.left_stick_x,
+ // game_input.left_stick_y,
+ // game_state->thrust_vector01.angle,
+ // game_state->thrust_vector01.length);
game_state->thrust_vector02.angle = atan2f(game_input.right_stick_y, game_input.right_stick_x);
game_state->thrust_vector02.length = hypotf(game_input.right_stick_x, game_input.right_stick_y);
- printf("(rx: %f, ry: %f, thrust_a: %f, thrust_l: %f)\n",
- game_input.right_stick_x,
- game_input.right_stick_y,
- game_state->thrust_vector02.angle,
- game_state->thrust_vector02.length);
+ //printf("(rx: %f, ry: %f, thrust_a: %f, thrust_l: %f)\n",
+ // game_input.right_stick_x,
+ // game_input.right_stick_y,
+ // game_state->thrust_vector02.angle,
+ // game_state->thrust_vector02.length);
game_state->thrust_vector_sum = vec2d_add(
game_state->thrust_vector01.angle,
diff --git a/src/game.h b/src/game.h
index a3bb5de..52d0654 100644
--- a/src/game.h
+++ b/src/game.h
@@ -63,6 +63,10 @@ struct OffscreenBuffer
unsigned int pitch;
};
+// TODO: Consider using the #define trick from HMH
+typedef void (game_update_t)(struct GameState*, struct GameControllerInput, int, int);
+typedef void (game_render_t)(struct OffscreenBuffer*, float, struct GameState*);
+
void game_init(struct GameState *game_state, int field_width, int field_height);
void game_update(struct GameState *game_state, struct GameControllerInput game_input, int field_width, int field_height);
void game_render(struct OffscreenBuffer *buffer, float dt, struct GameState *game_state);
diff --git a/src/platform_sdl.c b/src/platform_sdl.c
index 2c01a69..28ac0ff 100644
--- a/src/platform_sdl.c
+++ b/src/platform_sdl.c
@@ -1,6 +1,9 @@
#include "platform_sdl.h"
-#include "game.h"
+#ifdef __linux__
+#include "util_linux.h"
+#elif __WIN32
+#endif
#include <stdbool.h>
#include <stdio.h>
@@ -243,6 +246,8 @@ int main(int argc, char *argv[])
struct GameControllerInput controller_input = {0};
+ struct SDLGameCode game_code = load_game_code(GAME_LIB_PATH);
+
while (running)
{
uint64_t current_ms = (SDL_GetPerformanceCounter() * SECOND) / SDL_GetPerformanceFrequency();
@@ -251,6 +256,18 @@ int main(int argc, char *argv[])
lag += elapsed_ms;
//printf("%" PRIu64 ", %" PRIu64 ", %f\n", elapsed_ms, lag, MS_PER_UPDATE);
+ time_t last_write_time = file_get_modified_time(GAME_LIB_PATH);
+ bool game_code_has_changed = last_write_time && (last_write_time != game_code.last_write_time);
+ if (game_code_has_changed)
+ {
+ unload_game_code(&game_code);
+ game_code = load_game_code(GAME_LIB_PATH);
+ if (!game_code.is_valid)
+ {
+ // TODO: fall back to backup?
+ }
+ }
+
SDL_Event event;
while (SDL_PollEvent(&event))
{
@@ -278,14 +295,14 @@ int main(int argc, char *argv[])
{
while (lag >= MS_PER_UPDATE)
{
- game_update(&game_state, controller_input, buffer.width, buffer.height);
+ game_code.game_update(&game_state, controller_input, buffer.width, buffer.height);
//printf("\t%" PRIu64 ", %f\n", lag, MS_PER_UPDATE);
lag -= MS_PER_UPDATE;
}
}
clear_screen(&global_back_buffer, COLOR_BACKGROUND);
- game_render(&buffer, lag/SECOND, &game_state);
+ game_code.game_render(&buffer, lag/SECOND, &game_state);
sdl_update_window(renderer, &global_back_buffer);
if (elapsed_ms <= MS_PER_FRAME)
{
diff --git a/src/platform_sdl.h b/src/platform_sdl.h
index e33835e..bcb8ad5 100644
--- a/src/platform_sdl.h
+++ b/src/platform_sdl.h
@@ -1,7 +1,11 @@
#ifndef PLATFORM_SDL_H
#include "SDL.h"
+#include "game.h"
+#include <stdbool.h>
+
+#define GAME_LIB_PATH "./release/game.so"
#define MAX_CONTROLLERS 4
#define DEADZONE_THRESHOLD 9000
@@ -21,5 +25,14 @@ struct SDLWindowDimension
int height;
};
+struct SDLGameCode
+{
+ bool is_valid;
+ void *game_code_library;
+ time_t last_write_time;
+ game_update_t *game_update;
+ game_render_t *game_render;
+};
+
#define PLATFORM_SDL_H
#endif
diff --git a/src/util_linux.h b/src/util_linux.h
new file mode 100644
index 0000000..4040a10
--- /dev/null
+++ b/src/util_linux.h
@@ -0,0 +1,78 @@
+#ifndef UTIL_LINUX_H
+#define UTIL_LINUX_H
+
+#include <dlfcn.h>
+#include <sys/stat.h>
+
+
+time_t file_get_modified_time(char *file_path)
+{
+ time_t mtime = 0;
+ struct stat file_status = {0};
+ if (stat(file_path, &file_status) == 0)
+ {
+ //printf("File: %s last modified: %s\n", file_path, ctime(&file_status.st_mtime));
+ mtime = file_status.st_mtime;
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Failed to stat file: %s\n", file_path);
+ }
+ return mtime;
+}
+
+
+void unload_game_code(struct SDLGameCode *game_code)
+{
+ if (!game_code)
+ {
+ printf("Invalid pointer *game_code\n");
+ return;
+ }
+
+ if (game_code->game_code_library)
+ {
+ dlclose(game_code->game_code_library);
+ game_code->game_code_library = 0;
+ }
+ game_code->is_valid = false;
+ game_code->game_update = 0;
+ game_code->game_render = 0;
+}
+
+
+// TODO: Add backup dll in case loading fails
+struct SDLGameCode load_game_code(char *source_lib_path)
+{
+ struct SDLGameCode game_code = {0};
+
+ game_code.last_write_time = file_get_modified_time(source_lib_path);
+ if (game_code.last_write_time)
+ {
+ game_code.game_code_library = dlopen(source_lib_path, RTLD_LAZY);
+ if (game_code.game_code_library)
+ {
+ // NOTE: The C standard (as of C99) distinguishes function pointers
+ // from object pointers (`void *` is an object pointer). Technically it
+ // is undefined behavior to cast between these two pointer types. In
+ // practice, it works on most modern platforms.
+ //
+ // In this case, we are protected by POSIX, which specifies that
+ // function and data pointers must be the same size. We will only ever
+ // be using dlsym on POSIX-compliant platforms.
+ game_code.game_update = (game_update_t *) dlsym(game_code.game_code_library, "game_update");
+ game_code.game_render = (game_render_t *) dlsym(game_code.game_code_library, "game_render");
+ game_code.is_valid = (game_code.game_update && game_code.game_render);
+ }
+ }
+
+ if (!game_code.is_valid)
+ {
+ fprintf(stderr, "ERROR: Game code is not valid: %s\n", dlerror());
+ }
+
+ return game_code;
+}
+
+
+#endif