#include "game_loop.h" #if defined(__EMSCRIPTEN__) #include #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