cb6d9e61d1
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
88 lines
2.4 KiB
C++
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
|