rework to context: now there's engine and user code copies, renaming of fields, most things that shouldn't be there are hidden
This commit is contained in:
@ -57,7 +57,7 @@ static void load_game_object(void) {
|
||||
|
||||
handle = new_handle;
|
||||
|
||||
if (ctx.game.tick_count != 0)
|
||||
if (ctx.game.frame_number != 0)
|
||||
log_info("Game object was reloaded\n");
|
||||
|
||||
return;
|
||||
@ -84,7 +84,7 @@ static void watcher_callback(XWATCHER_FILE_EVENT event,
|
||||
switch(event) {
|
||||
case XWATCHER_FILE_MODIFIED:
|
||||
SDL_LockMutex(lock);
|
||||
last_tick_modified = ctx.game.tick_count;
|
||||
last_tick_modified = ctx.game.frame_number;
|
||||
loaded_after_modification = false;
|
||||
SDL_UnlockMutex(lock);
|
||||
break;
|
||||
@ -129,7 +129,7 @@ bool game_object_try_reloading(void) {
|
||||
|
||||
/* only load the modified library after some time, as compilers make a lot of modifications */
|
||||
SDL_LockMutex(lock);
|
||||
if (ctx.game.tick_count - last_tick_modified > MODIFIED_TICKS_MERGED &&
|
||||
if (ctx.game.frame_number - last_tick_modified > MODIFIED_TICKS_MERGED &&
|
||||
!loaded_after_modification) {
|
||||
load_game_object();
|
||||
loaded_after_modification = true;
|
||||
|
@ -48,7 +48,7 @@ static void load_game_object(void) {
|
||||
|
||||
handle = new_handle;
|
||||
|
||||
if (ctx.game.tick_count != 0)
|
||||
if (ctx.game.frame_number != 0)
|
||||
log_info("Game object was reloaded\n");
|
||||
|
||||
return;
|
||||
|
@ -250,23 +250,23 @@ void render(void) {
|
||||
textures_update_atlas(&ctx.texture_cache);
|
||||
|
||||
/* fit rendering context onto the resizable screen */
|
||||
if (ctx.game.window_size_has_changed) {
|
||||
if ((float)ctx.game.window_w / (float)ctx.game.window_h > (float)ctx.base_render_width / (float)ctx.base_render_height) {
|
||||
float ratio = (float)ctx.game.window_h / (float)ctx.base_render_height;
|
||||
if (ctx.window_size_has_changed) {
|
||||
if ((float)ctx.window_dims.x / (float)ctx.window_dims.y > (float)ctx.base_render_width / (float)ctx.base_render_height) {
|
||||
float ratio = (float)ctx.window_dims.y / (float)ctx.base_render_height;
|
||||
int w = (int)((float)ctx.base_render_width * ratio);
|
||||
setup_viewport(
|
||||
ctx.game.window_w / 2 - w / 2,
|
||||
ctx.window_dims.x / 2 - w / 2,
|
||||
0,
|
||||
w,
|
||||
ctx.game.window_h
|
||||
ctx.window_dims.y
|
||||
);
|
||||
} else {
|
||||
float ratio = (float)ctx.game.window_w / (float)ctx.base_render_width;
|
||||
float ratio = (float)ctx.window_dims.x / (float)ctx.base_render_width;
|
||||
int h = (int)((float)ctx.base_render_height * ratio);
|
||||
setup_viewport(
|
||||
0,
|
||||
ctx.game.window_h / 2 - h / 2,
|
||||
ctx.game.window_w,
|
||||
ctx.window_dims.y / 2 - h / 2,
|
||||
ctx.window_dims.x,
|
||||
h
|
||||
);
|
||||
}
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
typedef struct EngineContext {
|
||||
/* user code facing context */
|
||||
Context game_copy;
|
||||
/* engine-side context, copied to `game_copy` before every frame */
|
||||
Context game;
|
||||
|
||||
InputState input;
|
||||
@ -27,6 +29,8 @@ typedef struct EngineContext {
|
||||
/* where the app was run from, used as the root for packs */
|
||||
char *base_dir;
|
||||
|
||||
Vec2i window_dims;
|
||||
|
||||
/* configuration */
|
||||
toml_table_t *config_table;
|
||||
int64_t base_render_width;
|
||||
@ -52,6 +56,7 @@ typedef struct EngineContext {
|
||||
uint8_t audio_stream_channel_count;
|
||||
|
||||
/* main loop machinery */
|
||||
int64_t delta_time; /* preserves real time frame delta with no manipilation */
|
||||
int64_t clocks_per_second;
|
||||
int64_t prev_frame_time;
|
||||
int64_t desired_frametime; /* how long one tick should be */
|
||||
@ -59,10 +64,17 @@ typedef struct EngineContext {
|
||||
int64_t delta_averager_residual;
|
||||
int64_t time_averager[4];
|
||||
|
||||
/* this should be a multiple of the current ticks per second */
|
||||
/* use it to simulate low framerate (e.g. at 60 tps, set to 2 for 30 fps) */
|
||||
/* it can be changed at runtime; any resulting logic anomalies are bugs */
|
||||
uint32_t update_multiplicity;
|
||||
|
||||
SDL_GLContext *gl_context;
|
||||
SDL_Window *window;
|
||||
uint32_t window_id;
|
||||
|
||||
bool is_running;
|
||||
bool window_size_has_changed;
|
||||
bool resync_flag;
|
||||
bool was_successful;
|
||||
} EngineContext;
|
||||
|
@ -194,8 +194,8 @@ void input_state_update(InputState *input) {
|
||||
SDL_GetRelativeMouseState(&input->mouse_relative_position.x,
|
||||
&input->mouse_relative_position.y);
|
||||
|
||||
ctx.game.mouse_window_position = input->mouse_window_position;
|
||||
ctx.game.mouse_relative_position = input->mouse_relative_position;
|
||||
ctx.game.mouse_position = input->mouse_window_position;
|
||||
ctx.game.mouse_movement = input->mouse_relative_position;
|
||||
|
||||
for (size_t i = 0; i < shlenu(input->action_hash); ++i) {
|
||||
Action *action = &input->action_hash[i].value;
|
||||
|
@ -36,8 +36,8 @@ static int event_callback(void *userdata, SDL_Event *event) {
|
||||
|
||||
switch (event->window.event) {
|
||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||
ctx.game.window_w = event->window.data1;
|
||||
ctx.game.window_h = event->window.data2;
|
||||
ctx.window_dims.x = event->window.data1;
|
||||
ctx.window_dims.y = event->window.data2;
|
||||
ctx.resync_flag = true;
|
||||
break;
|
||||
|
||||
@ -59,12 +59,12 @@ static int event_callback(void *userdata, SDL_Event *event) {
|
||||
static void poll_events(void) {
|
||||
SDL_Event e;
|
||||
|
||||
ctx.game.window_size_has_changed = false;
|
||||
ctx.window_size_has_changed = false;
|
||||
|
||||
while (SDL_PollEvent(&e)) {
|
||||
switch (e.type) {
|
||||
case SDL_QUIT:
|
||||
ctx.game.is_running = false;
|
||||
ctx.is_running = false;
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT:
|
||||
@ -73,7 +73,7 @@ static void poll_events(void) {
|
||||
|
||||
switch (e.window.event) {
|
||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||
ctx.game.window_size_has_changed = true;
|
||||
ctx.window_size_has_changed = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -111,6 +111,11 @@ static void APIENTRY opengl_log(GLenum source,
|
||||
#endif
|
||||
|
||||
|
||||
void preserve_persistent_ctx_fields(void) {
|
||||
ctx.game.udata = ctx.game_copy.udata;
|
||||
}
|
||||
|
||||
|
||||
static void main_loop(void) {
|
||||
/*
|
||||
if (!ctx.is_running) {
|
||||
@ -124,7 +129,7 @@ static void main_loop(void) {
|
||||
int64_t current_frame_time = SDL_GetPerformanceCounter();
|
||||
int64_t delta_time = current_frame_time - ctx.prev_frame_time;
|
||||
ctx.prev_frame_time = current_frame_time;
|
||||
ctx.game.delta_time = delta_time;
|
||||
ctx.delta_time = delta_time;
|
||||
|
||||
/* handle unexpected timer anomalies (overflow, extra slow frames, etc) */
|
||||
if (delta_time > ctx.desired_frametime * 8) { /* ignore extra-slow frames */
|
||||
@ -188,24 +193,23 @@ static void main_loop(void) {
|
||||
ctx.resync_flag = false;
|
||||
}
|
||||
|
||||
ctx.game_copy = ctx.game;
|
||||
|
||||
/* finally, let's get to work */
|
||||
int frames = 0;
|
||||
while (ctx.frame_accumulator >= ctx.desired_frametime * ctx.game.update_multiplicity) {
|
||||
while (ctx.frame_accumulator >= ctx.desired_frametime * ctx.update_multiplicity) {
|
||||
frames += 1;
|
||||
for (size_t i = 0; i < ctx.game.update_multiplicity; ++i) {
|
||||
for (size_t i = 0; i < ctx.update_multiplicity; ++i) {
|
||||
/* TODO: disable rendering pushes on not-last ? */
|
||||
render_queue_clear();
|
||||
|
||||
poll_events();
|
||||
|
||||
input_state_update(&ctx.input);
|
||||
|
||||
game_object_tick();
|
||||
preserve_persistent_ctx_fields();
|
||||
|
||||
ctx.frame_accumulator -= ctx.desired_frametime;
|
||||
ctx.game.tick_count = (ctx.game.tick_count % ULLONG_MAX) + 1;
|
||||
ctx.game.frame_number = (ctx.game.frame_number % ULLONG_MAX) + 1;
|
||||
ctx.game.initialization_needed = false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -439,7 +443,7 @@ static bool initialize(void) {
|
||||
goto fail;
|
||||
}
|
||||
ctx.base_render_width = datum_base_render_width.u.i;
|
||||
ctx.game.base_draw_w = (int)ctx.base_render_width;
|
||||
ctx.game.resolution.x = (int)ctx.base_render_width;
|
||||
|
||||
toml_datum_t datum_base_render_height = toml_int_in(game, "base_render_height");
|
||||
if (!datum_base_render_height.ok) {
|
||||
@ -447,7 +451,7 @@ static bool initialize(void) {
|
||||
goto fail;
|
||||
}
|
||||
ctx.base_render_height = datum_base_render_height.u.i;
|
||||
ctx.game.base_draw_h = (int)ctx.base_render_height;
|
||||
ctx.game.resolution.y = (int)ctx.base_render_height;
|
||||
|
||||
ctx.window = SDL_CreateWindow(datum_title.u.s,
|
||||
SDL_WINDOWPOS_CENTERED,
|
||||
@ -503,8 +507,8 @@ static bool initialize(void) {
|
||||
|
||||
/* TODO: */
|
||||
// SDL_GetRendererOutputSize(ctx.renderer, &ctx.window_w, &ctx.window_h);
|
||||
ctx.game.window_w = (int)ctx.base_render_width;
|
||||
ctx.game.window_h = (int)ctx.base_render_height;
|
||||
ctx.window_dims.x = (int)ctx.base_render_width;
|
||||
ctx.window_dims.y = (int)ctx.base_render_height;
|
||||
|
||||
/* add a watcher for immediate updates on window size */
|
||||
SDL_AddEventWatch(event_callback, NULL);
|
||||
@ -532,7 +536,7 @@ static bool initialize(void) {
|
||||
}
|
||||
|
||||
/* you could change this at runtime if you wanted */
|
||||
ctx.game.update_multiplicity = 1;
|
||||
ctx.update_multiplicity = 1;
|
||||
|
||||
#ifndef EMSCRIPTEN
|
||||
/* hook up opengl debugging callback */
|
||||
@ -561,13 +565,13 @@ static bool initialize(void) {
|
||||
}
|
||||
}
|
||||
|
||||
ctx.game.is_running = true;
|
||||
ctx.is_running = true;
|
||||
ctx.resync_flag = true;
|
||||
ctx.clocks_per_second = SDL_GetPerformanceFrequency();
|
||||
ctx.prev_frame_time = SDL_GetPerformanceCounter();
|
||||
ctx.desired_frametime = ctx.clocks_per_second / ctx.ticks_per_second;
|
||||
ctx.frame_accumulator = 0;
|
||||
ctx.game.tick_count = 0;
|
||||
ctx.game.frame_number = 0;
|
||||
|
||||
/* delta time averaging */
|
||||
ctx.delta_averager_residual = 0;
|
||||
@ -772,7 +776,7 @@ int enter_loop(int argc, char **argv) {
|
||||
ctx.was_successful = true;
|
||||
ctx.game.initialization_needed = true;
|
||||
|
||||
while (ctx.game.is_running) {
|
||||
while (ctx.is_running) {
|
||||
if (game_object_try_reloading()) {
|
||||
ctx.game.initialization_needed = true;
|
||||
reset_state();
|
||||
|
@ -273,11 +273,11 @@ void tick_timer(int *value) {
|
||||
}
|
||||
|
||||
void tick_ftimer(float *value) {
|
||||
*value = MAX(*value - ((float)ctx.game.delta_time / (float)ctx.clocks_per_second), 0.0f);
|
||||
*value = MAX(*value - ((float)ctx.delta_time / (float)ctx.clocks_per_second), 0.0f);
|
||||
}
|
||||
|
||||
bool repeat_ftimer(float *value, float at) {
|
||||
*value -= (float)ctx.game.delta_time / (float)ctx.clocks_per_second;
|
||||
*value -= (float)ctx.delta_time / (float)ctx.clocks_per_second;
|
||||
if (*value < 0.0f) {
|
||||
*value += at;
|
||||
return true;
|
||||
|
Reference in New Issue
Block a user