aboutsummaryrefslogtreecommitdiff
path: root/simloop/test/simloop_test.c
blob: 9f11e861769b42be54309ca3efe4672b16d47ffa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <simloop.h>

#include <test.h>
#include <timer.h>

/// At time/frame 0:
///   1. An initial render is always triggered.
///   2. No update is triggered (not enough time passed).
TEST_CASE(simloop_initial_render) {
  Timer   timer   = {};
  Simloop simloop = simloop_make(
      &(SimloopArgs){.update_fps = 10, .max_render_fps = 0, .timer = &timer});
  SimloopOut simout;

  simloop_update(&simloop, &simout);

  TEST_TRUE(simout.should_render);
  TEST_TRUE(!simout.should_update);
  TEST_EQUAL(simout.frame, 0);
}

/// The initial render is not re-triggered if there is a render frame rate cap
/// and time does not advance.
TEST_CASE(simloop_initial_render_not_retriggered) {
  Timer   timer   = {};
  Simloop simloop = simloop_make(
      &(SimloopArgs){.update_fps = 10, .max_render_fps = 10, .timer = &timer});
  SimloopOut simout;

  simloop_update(&simloop, &simout);

  TEST_TRUE(simout.should_render);
  TEST_TRUE(!simout.should_update);
  TEST_EQUAL(simout.frame, 0);

  for (int i = 0; i < 10; i++) {
    // Note that time does not advance.
    simloop_update(&simloop, &simout);
    TEST_TRUE(!simout.should_render);
    TEST_TRUE(!simout.should_update);
    TEST_EQUAL(simout.frame, 0);
  }
}

/// A simulation loop with no render frame cap:
///   1. Updates based on the desired update frame rate.
///   2. Renders at every loop (provided there are updates).
TEST_CASE(simloop_no_render_frame_cap) {
  constexpr int    UPDATE_FPS    = 10;
  const time_delta EXPECT_UPDATE = sec_to_time_delta(1.0 / (double)UPDATE_FPS);
  const time_delta STEP          = sec_to_time_delta(1);
  const time_delta SIM_TIME_SEC  = sec_to_time_delta(30);

  Timer      timer   = {};
  Simloop    simloop = simloop_make(&(SimloopArgs){
         .update_fps = UPDATE_FPS, .max_render_fps = 0, .timer = &timer});
  SimloopOut simout;

  for (time_delta t = 0; t < SIM_TIME_SEC; t += STEP) {
    timer_advance(&timer, t);
    simloop_update(&simloop, &simout);
    const bool expect_update = (t > 0) && ((t % EXPECT_UPDATE) == 0);
    // A render is still expected at time 0.
    TEST_EQUAL(simout.should_render, (t == 0) || expect_update);
    TEST_EQUAL(simout.should_update, expect_update);
  }
}

/// A simulation loop with a render frame cap:
///   1. Updates based on the desired update frame rate.
///   2. Renders based on the desired render frame rate.
TEST_CASE(simloop_with_render_frame_cap) {
  constexpr int    UPDATE_FPS    = 10;
  constexpr int    RENDER_FPS    = 5;
  const time_delta EXPECT_UPDATE = sec_to_time_delta(1.0 / (double)UPDATE_FPS);
  const time_delta EXPECT_RENDER = sec_to_time_delta(1.0 / (double)RENDER_FPS);
  const time_delta STEP          = sec_to_time_delta(0.1);
  const time_delta SIM_TIME_SEC  = sec_to_time_delta(30);

  Timer      timer   = {};
  Simloop    simloop = simloop_make(&(SimloopArgs){
         .update_fps = UPDATE_FPS, .max_render_fps = RENDER_FPS, .timer = &timer});
  SimloopOut simout;

  for (time_delta t = 0; t < SIM_TIME_SEC; t += STEP) {
    timer_advance(&timer, t);
    simloop_update(&simloop, &simout);
    // A render is still expected at time 0.
    TEST_EQUAL(simout.should_render, (t % EXPECT_RENDER) == 0);
    TEST_EQUAL(simout.should_update, (t > 0) && ((t % EXPECT_UPDATE) == 0));
  }
}

int main() { return 0; }