#include
#include
#include
/* game loop
*
* description:
* a game loop that updates the game state at fixed time intervals while also rendering as fast as possible.
*
* remarks:
* all time units are seconds
*
* design:
* the fundamental idea is that during the previous iteration (PI) time has passed. Now during the current iteration (CI),
* based on the PI's duration, we retroactively apply updates until we have "caught up" our state.
*
* right before a new iteration commences PI becomes CI, and we are now in the new CI.
*
* author:
* cuppajoeman (2023)
*/
// All time is measured in seconds
double time_elapsed_since_start_of_program = 0;
// N iterations per second
double update_rate_hz = 60.0d;
// 1/N seconds per iteration
double time_between_state_update = 1.0d / update_rate_hz;
double time_elapsed_since_last_state_update = 0;
bool quit_requested = false;
void update(double time_since_last_update) {
printf("doing update\n");
}
void render() {
//printf("doing rendering\n");
}
int main() {
if (!glfwInit()) {
exit(EXIT_FAILURE);
}
bool first_iteration = true;
bool first_update = true;
double time_at_start_of_iteration_last_iteration = -1.0d;
double duration_of_last_iteration = -1.0d;
while (!quit_requested) {
double time_at_start_of_iteration = glfwGetTime(); // (T)
if (first_iteration) {
// The last few lines of this iteration are next loops last iteration.
first_iteration = false;
time_at_start_of_iteration_last_iteration = time_at_start_of_iteration; // (C)
time_elapsed_since_last_state_update = time_at_start_of_iteration; // (F): Pretend an update has occurred at time 0 for bootstrapping purposes
continue;
}
if (time_at_start_of_iteration >= 10) {
quit_requested = true;
}
// Note that this measures how long it takes for the code to start at (T) and arrive back at (T)
// (G): Due to (C) tesli == 0 on the second iteration
duration_of_last_iteration = time_at_start_of_iteration - time_at_start_of_iteration_last_iteration;
// None of the updates that could have happened during the last iteration have been applied
// This is because last iteration, we retroactively applied last last iterations updates
time_elapsed_since_last_state_update += duration_of_last_iteration;
// since the value of teslsu is only updated by (E), this would always be false, but (F) bootstraps the process
bool enough_time_for_updates = time_elapsed_since_last_state_update >= time_between_state_update;
// Due to the (G), an update could only happen starting from the 3rd iteration
if (enough_time_for_updates) {
// retroactively apply updates that should have occurred during previous iterations
double time_remaining_to_fit_updates = time_elapsed_since_last_state_update;
bool enough_time_to_fit_update = true;
while (enough_time_to_fit_update) {
update(time_between_state_update);
time_remaining_to_fit_updates -= time_between_state_update;
enough_time_to_fit_update = time_remaining_to_fit_updates >= time_between_state_update ;
}
time_elapsed_since_last_state_update = time_remaining_to_fit_updates;
}
render();
// With respect to the start of the next iteration, the code down here is previous iteration.
time_at_start_of_iteration_last_iteration = time_at_start_of_iteration;
}
glfwTerminate();
exit(EXIT_SUCCESS);
}