diff options
| author | 3gg <3gg@shellblade.net> | 2026-04-11 16:35:25 -0700 |
|---|---|---|
| committer | 3gg <3gg@shellblade.net> | 2026-04-11 16:35:25 -0700 |
| commit | 896a6ef5959043db5463637d84ed524ae7bade1e (patch) | |
| tree | 65b6cac3b4d2fe4e51eaf0d377f4578eabaf1488 | |
| parent | 879e5af4eb1a8972fc944853a515e1003f94bd7c (diff) | |
Render only if there was an update
| -rw-r--r-- | simloop/include/simloop.h | 1 | ||||
| -rw-r--r-- | simloop/src/simloop.c | 17 | ||||
| -rw-r--r-- | simloop/test/simloop_test.c | 14 |
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). |
| 48 | TEST_CASE(simloop_no_render_frame_cap) { | 48 | TEST_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 | ||
