Files
fn_registry/cpp/functions/gamedev/game_loop.cpp
T

88 lines
2.4 KiB
C++

#include "game_loop.h"
#if defined(__EMSCRIPTEN__)
#include <emscripten/emscripten.h>
#endif
namespace fn::game {
namespace {
struct LoopRT {
LoopCfg cfg;
Uint64 last_ticks;
float accumulator;
Uint64 perf_freq;
};
#if defined(__EMSCRIPTEN__)
static LoopRT g_rt;
void em_tick() {
LoopRT& rt = g_rt;
Uint64 now = SDL_GetPerformanceCounter();
float frame_time = (float)((double)(now - rt.last_ticks) / (double)rt.perf_freq);
rt.last_ticks = now;
float cap = rt.cfg.fixed_dt * (float)rt.cfg.max_steps_per_frame;
if (frame_time > cap) frame_time = cap;
rt.accumulator += frame_time;
int steps = 0;
while (rt.accumulator >= rt.cfg.fixed_dt && steps < rt.cfg.max_steps_per_frame) {
if (rt.cfg.on_fixed_update) rt.cfg.on_fixed_update(rt.cfg.user, rt.cfg.fixed_dt);
rt.accumulator -= rt.cfg.fixed_dt;
steps++;
}
float interp = rt.accumulator / rt.cfg.fixed_dt;
if (rt.cfg.on_render) rt.cfg.on_render(rt.cfg.user, interp);
if (rt.cfg.should_quit && rt.cfg.should_quit(rt.cfg.user)) {
emscripten_cancel_main_loop();
}
}
#endif
} // namespace
void loop_run(SDL_Window* /*win*/, const LoopCfg& cfg) {
if (!cfg.on_fixed_update && !cfg.on_render) return;
#if defined(__EMSCRIPTEN__)
g_rt.cfg = cfg;
g_rt.last_ticks = SDL_GetPerformanceCounter();
g_rt.accumulator = 0.0f;
g_rt.perf_freq = SDL_GetPerformanceFrequency();
emscripten_set_main_loop(em_tick, 0, 1);
#else
Uint64 perf_freq = SDL_GetPerformanceFrequency();
Uint64 last = SDL_GetPerformanceCounter();
float accumulator = 0.0f;
for (;;) {
if (cfg.should_quit && cfg.should_quit(cfg.user)) break;
Uint64 now = SDL_GetPerformanceCounter();
float frame_time = (float)((double)(now - last) / (double)perf_freq);
last = now;
float cap = cfg.fixed_dt * (float)cfg.max_steps_per_frame;
if (frame_time > cap) frame_time = cap;
accumulator += frame_time;
int steps = 0;
while (accumulator >= cfg.fixed_dt && steps < cfg.max_steps_per_frame) {
if (cfg.on_fixed_update) cfg.on_fixed_update(cfg.user, cfg.fixed_dt);
accumulator -= cfg.fixed_dt;
steps++;
}
float interp = accumulator / cfg.fixed_dt;
if (cfg.on_render) cfg.on_render(cfg.user, interp);
}
#endif
}
} // namespace fn::game