From d0316cd789d3457af6cdf6ea75f9362dc6e5eeec Mon Sep 17 00:00:00 2001 From: Sebastian Krzyszkowiak Date: Tue, 8 Jan 2019 04:53:13 +0100 Subject: [PATCH] don't use timer for ticking; rely on delta instead Timer was causing an infinite loop in cases where ticking took more time than 1/60 sec. --- src/internal.c | 24 ++++++++---------------- src/internal.h | 1 - src/libsuperderpy.c | 10 ++-------- src/libsuperderpy.h | 3 ++- src/mainloop.c | 25 ++++++------------------- 5 files changed, 18 insertions(+), 45 deletions(-) diff --git a/src/internal.c b/src/internal.c index 06b35fc..5d4f7fa 100644 --- a/src/internal.c +++ b/src/internal.c @@ -87,12 +87,19 @@ SYMBOL_INTERNAL void DrawGamestates(struct Game* game) { SYMBOL_INTERNAL void LogicGamestates(struct Game* game, double delta) { struct Gamestate* tmp = game->_priv.gamestates; + int ticks = floor((game->time + delta) / ALLEGRO_BPS_TO_SECS(60.0)) - floor(game->time / ALLEGRO_BPS_TO_SECS(60.0)); + game->time += delta; if (game->_priv.params.handlers.prelogic) { game->_priv.params.handlers.prelogic(game, delta); } while (tmp) { - if ((tmp->loaded) && (tmp->started) && (!tmp->paused)) { + if ((tmp->loaded) && (tmp->started) && (!tmp->paused) && (!tmp->pending_stop)) { game->_priv.current_gamestate = tmp; + if (tmp->api->tick) { + for (int i = 0; i < ticks; i++) { + tmp->api->tick(game, tmp->data); + } + } tmp->api->logic(game, tmp->data, delta); } tmp = tmp->next; @@ -102,19 +109,6 @@ SYMBOL_INTERNAL void LogicGamestates(struct Game* game, double delta) { } } -SYMBOL_INTERNAL void TickGamestates(struct Game* game) { - struct Gamestate* tmp = game->_priv.gamestates; - while (tmp) { - if ((tmp->loaded) && (tmp->started) && (!tmp->paused)) { - game->_priv.current_gamestate = tmp; - if (tmp->api->tick) { - tmp->api->tick(game, tmp->data); - } - } - tmp = tmp->next; - } -} - SYMBOL_INTERNAL void ReloadGamestates(struct Game* game) { struct Gamestate* tmp = game->_priv.gamestates; ReloadShaders(game, true); @@ -576,7 +570,6 @@ SYMBOL_INTERNAL void PauseExecution(struct Game* game) { return; } game->_priv.paused = true; - al_stop_timer(game->_priv.timer); al_detach_voice(game->audio.v); FreezeGamestates(game); PrintConsole(game, "Engine halted."); @@ -612,7 +605,6 @@ SYMBOL_INTERNAL void ResumeExecution(struct Game* game) { } UnfreezeGamestates(game); al_attach_mixer_to_voice(game->audio.mixer, game->audio.v); - al_resume_timer(game->_priv.timer); game->_priv.paused = false; game->_priv.timestamp = al_get_time(); PrintConsole(game, "Engine resumed."); diff --git a/src/internal.h b/src/internal.h index af32f85..61c6746 100644 --- a/src/internal.h +++ b/src/internal.h @@ -90,7 +90,6 @@ struct ScreenshotThreadData { void SimpleCompositor(struct Game* game, struct Gamestate* gamestates, ALLEGRO_BITMAP* loading_fb); void DrawGamestates(struct Game* game); void LogicGamestates(struct Game* game, double delta); -void TickGamestates(struct Game* game); void EventGamestates(struct Game* game, ALLEGRO_EVENT* ev); void ReloadGamestates(struct Game* game); void FreezeGamestates(struct Game* game); diff --git a/src/libsuperderpy.c b/src/libsuperderpy.c index 1ba82b5..0272c28 100644 --- a/src/libsuperderpy.c +++ b/src/libsuperderpy.c @@ -96,6 +96,8 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char* game->_priv.bsod_cond = al_create_cond(); game->_priv.bsod_mutex = al_create_mutex(); + game->_priv.speed = ALLEGRO_BPS_TO_SECS(60.0); + game->_priv.mutex = al_create_mutex(); game->config.fullscreen = strtol(GetConfigOptionDefault(game, "SuperDerpy", "fullscreen", "1"), NULL, 10); @@ -338,16 +340,9 @@ SYMBOL_EXPORT int libsuperderpy_start(struct Game* game) { al_register_event_source(game->_priv.event_queue, &(game->event_source)); al_clear_to_color(al_map_rgb(0, 0, 0)); - game->_priv.timer = al_create_timer(ALLEGRO_BPS_TO_SECS(60)); // logic timer - if (!game->_priv.timer) { - FatalError(game, true, "Failed to create logic timer."); - return 1; - } - al_register_event_source(game->_priv.event_queue, al_get_timer_event_source(game->_priv.timer)); ReloadShaders(game, false); al_flip_display(); - al_start_timer(game->_priv.timer); { struct Gamestate* tmp = game->_priv.gamestates; @@ -471,7 +466,6 @@ SYMBOL_EXPORT void libsuperderpy_destroy(struct Game* game) { free(game->_priv.garbage->data); game->_priv.garbage = game->_priv.garbage->next; } - al_destroy_timer(game->_priv.timer); Console_Unload(game); al_destroy_display(game->display); al_destroy_user_event_source(&(game->event_source)); diff --git a/src/libsuperderpy.h b/src/libsuperderpy.h index 6ced11c..62afe1f 100644 --- a/src/libsuperderpy.h +++ b/src/libsuperderpy.h @@ -195,10 +195,11 @@ struct Game { char console[5][1024]; unsigned int console_pos; ALLEGRO_EVENT_QUEUE* event_queue; /*!< Main event queue. */ - ALLEGRO_TIMER* timer; /*!< Main LPS (logic) timer. */ bool showconsole; /*!< If true, game console is rendered on screen. */ bool showtimeline; + double speed; /*!< Speed of the game in FPS. 60 == 1x */ + struct { double old_time, fps, time; int frames_done; diff --git a/src/mainloop.c b/src/mainloop.c index 60a1077..8893bf0 100644 --- a/src/mainloop.c +++ b/src/mainloop.c @@ -21,12 +21,6 @@ static inline void HandleEvent(struct Game* game, ALLEGRO_EVENT* ev) { switch (ev->type) { - case ALLEGRO_EVENT_TIMER: - if (ev->timer.source == game->_priv.timer) { - TickGamestates(game); - } - break; - case ALLEGRO_EVENT_DISPLAY_HALT_DRAWING: PauseExecution(game); al_acknowledge_drawing_halt(game->display); @@ -155,23 +149,23 @@ static inline void HandleDebugEvent(struct Game* game, ALLEGRO_EVENT* ev) { } break; case ALLEGRO_KEY_F9: - al_set_timer_speed(game->_priv.timer, ALLEGRO_BPS_TO_SECS(60.0)); + game->_priv.speed = ALLEGRO_BPS_TO_SECS(60.0); game->_priv.showconsole = true; PrintConsole(game, "DEBUG: Gameplay speed: 1.00x"); break; case ALLEGRO_KEY_F10: { - double speed = ALLEGRO_BPS_TO_SECS(al_get_timer_speed(game->_priv.timer)); // inverting + double speed = ALLEGRO_BPS_TO_SECS(game->_priv.speed); // inverting speed -= 10; if (speed < 10) { speed = 10; } - al_set_timer_speed(game->_priv.timer, ALLEGRO_BPS_TO_SECS(speed)); + game->_priv.speed = ALLEGRO_BPS_TO_SECS(speed); game->_priv.showconsole = true; PrintConsole(game, "DEBUG: Gameplay speed: %.2fx", speed / 60.0); } break; case ALLEGRO_KEY_F11: { - double speed = ALLEGRO_BPS_TO_SECS(al_get_timer_speed(game->_priv.timer)); // inverting + double speed = ALLEGRO_BPS_TO_SECS(game->_priv.speed); // inverting speed += 10; if (speed > 600) { speed = 600; } - al_set_timer_speed(game->_priv.timer, ALLEGRO_BPS_TO_SECS(speed)); + game->_priv.speed = ALLEGRO_BPS_TO_SECS(speed); game->_priv.showconsole = true; PrintConsole(game, "DEBUG: Gameplay speed: %.2fx", speed / 60.0); } break; @@ -274,16 +268,13 @@ static inline bool MainloopTick(struct Game* game) { while (tmp) { if (tmp->pending_unload) { PrintConsole(game, "Unloading gamestate \"%s\"...", tmp->name); - al_stop_timer(game->_priv.timer); tmp->loaded = false; tmp->pending_unload = false; game->_priv.current_gamestate = tmp; (*tmp->api->unload)(game, tmp->data); - al_resume_timer(game->_priv.timer); PrintConsole(game, "Gamestate \"%s\" unloaded successfully.", tmp->name); } if (tmp->pending_load) { - al_stop_timer(game->_priv.timer); if (tmp->show_loading) { (*game->_priv.loading.gamestate->api->start)(game, game->_priv.loading.gamestate->data); } @@ -373,7 +364,6 @@ static inline bool MainloopTick(struct Game* game) { game->loading.shown = false; } tmp->show_loading = true; - al_resume_timer(game->_priv.timer); game->_priv.timestamp = al_get_time(); } @@ -394,13 +384,11 @@ static inline bool MainloopTick(struct Game* game) { while (tmp) { if ((tmp->pending_start) && (tmp->loaded)) { PrintConsole(game, "Starting gamestate \"%s\"...", tmp->name); - al_stop_timer(game->_priv.timer); game->_priv.current_gamestate = tmp; tmp->started = true; tmp->pending_start = false; (*tmp->api->start)(game, tmp->data); - al_resume_timer(game->_priv.timer); game->_priv.timestamp = al_get_time(); PrintConsole(game, "Gamestate \"%s\" started successfully.", tmp->name); } @@ -420,8 +408,7 @@ static inline bool MainloopTick(struct Game* game) { double delta = al_get_time() - game->_priv.timestamp; game->_priv.timestamp += delta; - delta *= ALLEGRO_BPS_TO_SECS(al_get_timer_speed(game->_priv.timer) / (1 / 60.f)); - game->time += delta; + delta *= ALLEGRO_BPS_TO_SECS(game->_priv.speed / (1 / 60.f)); #ifdef LIBSUPERDERPY_IMGUI ImGui_ImplAllegro5_NewFrame();