#include #include static uint64_t ddt_from_fps(int fps) { static constexpr double NANOSECONDS = 1e9; return (fps == 0) ? 0 : (uint64_t)(NANOSECONDS / (double)fps); } Simloop simloop_make(const SimloopArgs* args) { assert(args); assert(args->update_fps > 0); return (Simloop){ .frame = 0, .update = (SimloopTimeline){.ddt = ddt_from_fps(args->update_fps), .last_step = args->timer->start_time}, .render = (SimloopTimeline){ .ddt = ddt_from_fps(args->max_render_fps), .last_step = args->timer->start_time}, .timer = args->timer, }; } static time_delta time_elapsed(const Simloop* sim, time_point t) { assert(sim); return time_diff(sim->timer->start_time, t); } static int step_update(const Simloop* sim, SimloopTimeline* timeline) { assert(sim); assert(timeline); assert(timeline->ddt > 0); const time_delta dt = time_diff(timeline->last_step, sim->timer->last_tick); const time_delta steps = dt / timeline->ddt; timeline->last_step = time_add(timeline->last_step, dt); return (int)steps; } static bool step_render(const Simloop* sim, SimloopTimeline* timeline) { assert(sim); assert(timeline); bool render = false; if (timeline->ddt > 0) { render = step_update(sim, timeline) > 0; } else { timeline->last_step = sim->timer->last_tick; render = true; } return render; } void simloop_update(Simloop* sim, SimloopOut* out) { assert(sim); assert(out); const int new_frames = step_update(sim, &sim->update); out->updates_pending = new_frames; out->should_render = step_render(sim, &sim->render) || (sim->frame == 0); // Trigger an initial render on the first frame. sim->frame += new_frames; out->frame = sim->frame; out->render_elapsed = time_elapsed(sim, sim->render.last_step); out->update_elapsed = time_elapsed(sim, sim->update.last_step); out->update_dt = sim->update.ddt; }