aboutsummaryrefslogtreecommitdiff
path: root/simloop
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2026-04-11 16:35:25 -0700
committer3gg <3gg@shellblade.net>2026-04-11 16:35:25 -0700
commit896a6ef5959043db5463637d84ed524ae7bade1e (patch)
tree65b6cac3b4d2fe4e51eaf0d377f4578eabaf1488 /simloop
parent879e5af4eb1a8972fc944853a515e1003f94bd7c (diff)
Render only if there was an update
Diffstat (limited to 'simloop')
-rw-r--r--simloop/include/simloop.h1
-rw-r--r--simloop/src/simloop.c17
-rw-r--r--simloop/test/simloop_test.c14
3 files changed, 22 insertions, 10 deletions
diff --git a/simloop/include/simloop.h b/simloop/include/simloop.h
index 6ee3b98..1e5b4e0 100644
--- a/simloop/include/simloop.h
+++ b/simloop/include/simloop.h
@@ -67,6 +67,7 @@ typedef struct Simloop {
67 uint64_t frame; ///< Frame counter. 67 uint64_t frame; ///< Frame counter.
68 Timer* timer; 68 Timer* timer;
69 bool first_iter; 69 bool first_iter;
70 bool updates_since_last_render;
70} Simloop; 71} Simloop;
71 72
72/// Create a simulation loop. 73/// Create a simulation loop.
diff --git a/simloop/src/simloop.c b/simloop/src/simloop.c
index aa2b6b7..606f5ed 100644
--- a/simloop/src/simloop.c
+++ b/simloop/src/simloop.c
@@ -19,6 +19,7 @@ Simloop simloop_make(const SimloopArgs* args) {
19 .last_step = args->timer->start_time}, 19 .last_step = args->timer->start_time},
20 .timer = args->timer, 20 .timer = args->timer,
21 .first_iter = true, 21 .first_iter = true,
22 .updates_since_last_render = false,
22 }; 23 };
23} 24}
24 25
@@ -57,11 +58,19 @@ void simloop_update(Simloop* sim, SimloopOut* out) {
57 assert(sim); 58 assert(sim);
58 assert(out); 59 assert(out);
59 60
60 out->should_update = step_update(sim, &sim->update); 61 // Simulation update.
61 out->should_render = 62 const bool updated = step_update(sim, &sim->update);
62 step_render(sim, &sim->render) || 63 out->should_update = updated;
64 sim->updates_since_last_render = sim->updates_since_last_render || updated;
65 // Simulation render.
66 const bool rendered =
67 (sim->updates_since_last_render && step_render(sim, &sim->render)) ||
63 (sim->first_iter); // Trigger an initial render on the first frame. 68 (sim->first_iter); // Trigger an initial render on the first frame.
64 sim->frame += (out->should_update ? 1 : 0); 69 out->should_render = rendered;
70 sim->updates_since_last_render =
71 sim->updates_since_last_render && !out->should_render;
72 // Loop state update.
73 sim->frame += (updated ? 1 : 0);
65 sim->first_iter = false; 74 sim->first_iter = false;
66 out->frame = sim->frame; 75 out->frame = sim->frame;
67 out->render_elapsed = time_elapsed(sim, sim->render.last_step); 76 out->render_elapsed = time_elapsed(sim, sim->render.last_step);
diff --git a/simloop/test/simloop_test.c b/simloop/test/simloop_test.c
index c79ee32..9f11e86 100644
--- a/simloop/test/simloop_test.c
+++ b/simloop/test/simloop_test.c
@@ -44,7 +44,7 @@ TEST_CASE(simloop_initial_render_not_retriggered) {
44 44
45/// A simulation loop with no render frame cap: 45/// A simulation loop with no render frame cap:
46/// 1. Updates based on the desired update frame rate. 46/// 1. Updates based on the desired update frame rate.
47/// 2. Renders at every loop. 47/// 2. Renders at every loop (provided there are updates).
48TEST_CASE(simloop_no_render_frame_cap) { 48TEST_CASE(simloop_no_render_frame_cap) {
49 constexpr int UPDATE_FPS = 10; 49 constexpr int UPDATE_FPS = 10;
50 const time_delta EXPECT_UPDATE = sec_to_time_delta(1.0 / (double)UPDATE_FPS); 50 const time_delta EXPECT_UPDATE = sec_to_time_delta(1.0 / (double)UPDATE_FPS);
@@ -59,8 +59,10 @@ TEST_CASE(simloop_no_render_frame_cap) {
59 for (time_delta t = 0; t < SIM_TIME_SEC; t += STEP) { 59 for (time_delta t = 0; t < SIM_TIME_SEC; t += STEP) {
60 timer_advance(&timer, t); 60 timer_advance(&timer, t);
61 simloop_update(&simloop, &simout); 61 simloop_update(&simloop, &simout);
62 TEST_TRUE(simout.should_render); 62 const bool expect_update = (t > 0) && ((t % EXPECT_UPDATE) == 0);
63 TEST_EQUAL((t > 0) && ((t % EXPECT_UPDATE) == 0), simout.should_update); 63 // A render is still expected at time 0.
64 TEST_EQUAL(simout.should_render, (t == 0) || expect_update);
65 TEST_EQUAL(simout.should_update, expect_update);
64 } 66 }
65} 67}
66 68
@@ -83,9 +85,9 @@ TEST_CASE(simloop_with_render_frame_cap) {
83 for (time_delta t = 0; t < SIM_TIME_SEC; t += STEP) { 85 for (time_delta t = 0; t < SIM_TIME_SEC; t += STEP) {
84 timer_advance(&timer, t); 86 timer_advance(&timer, t);
85 simloop_update(&simloop, &simout); 87 simloop_update(&simloop, &simout);
86 // Also expecting initial render at t=0. 88 // A render is still expected at time 0.
87 TEST_EQUAL((t % EXPECT_RENDER) == 0, simout.should_render); 89 TEST_EQUAL(simout.should_render, (t % EXPECT_RENDER) == 0);
88 TEST_EQUAL((t > 0) && ((t % EXPECT_UPDATE) == 0), simout.should_update); 90 TEST_EQUAL(simout.should_update, (t > 0) && ((t % EXPECT_UPDATE) == 0));
89 } 91 }
90} 92}
91 93