#define _POSIX_C_SOURCE 200809L #include "consts.h" #include "gravity.h" #include "magnetism.h" #include "mechanics.h" #include "objects.h" #include "vec_utils.h" #include #include #include #include #include #include #include #include int center_x_text(const char *text, int width, int size) { return (width - MeasureText(text, size)) / 2; } static inline int center_y_text(int height, int size) { return (height - size) / 2; } void *physics(void *args) { universe_t *uni = (universe_t *)args; struct timespec next_step; clock_gettime(CLOCK_MONOTONIC, &next_step); while (true) { next_step.tv_sec += LOOP_TIMESTEP / 1000000000LL; next_step.tv_nsec += LOOP_TIMESTEP % 1000000000LL; if (next_step.tv_nsec >= 1000000000L) { next_step.tv_nsec -= 1000000000L; next_step.tv_sec++; } gravity(uni); magnetism(uni); mechanics(uni); struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); if (now.tv_sec > next_step.tv_sec || (now.tv_sec == next_step.tv_sec && now.tv_nsec > next_step.tv_nsec)) { next_step = now; // An overrun starts a fresh schedule, without catch-up steps. } // Sleep only until the deadline; processing time is already included. while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_step, NULL) == EINTR) { } } } int main(void) { float v_scale = 1; Vector2 canvas_offset = {0, 0}; pthread_t physics_thread; const char *welcome_text = "Welcome to Fucked Physics!"; universe_t universe = {0, NULL}; universe.bodies = malloc(1024 * sizeof(mass_body_t)); universe.num_bodies = 7; universe.bodies[0] = (mass_body_t){330432.0f, 696340 / RT, {0, 0}, {0, 0}, 600, 0, "Sun"}; universe.bodies[1] = (mass_body_t){ 0.055f, 2439.7 / RT, {0.387 * UA / RT, 0}, {0, -38.86 / RT}, 80, 0, "Mercury"}; universe.bodies[2] = (mass_body_t){ 0.815f, 6051.8 / RT, {0.723 * UA / RT, 0}, {0, -34.79 / RT}, 190, 0, "Venus"}; universe.bodies[3] = (mass_body_t){ 1.0f, 1.0f, {1 * UA / RT, 0}, {0, -29.29 / RT}, 200, 0, "Earth"}; universe.bodies[4] = (mass_body_t){ 0.107f, 3389.5 / RT, {1.524 * UA / RT, 0}, {0, -21.97 / RT}, 106, 0, "Mars"}; universe.bodies[5] = (mass_body_t){ 317.83f, 69911 / RT, {5.203 * UA / RT, 0}, {0, -12.43 / RT}, 400, 0, "Jupiter"}; universe.bodies[6] = (mass_body_t){ 95.159f, 58232 / RT, {9.582 * UA / RT, 0}, {0, -9.11 / RT}, 300, 0, "Saturn"}; SetConfigFlags(FLAG_WINDOW_RESIZABLE); InitWindow(800, 450, "Fucked Physics"); SetTargetFPS(120); pthread_create(&physics_thread, NULL, physics, (void *)&universe); while (!WindowShouldClose()) { int key_pressed = 0; do { key_pressed = GetKeyPressed(); switch (key_pressed) { case KEY_I: if (v_scale >= 0.1) { v_scale += 0.1; } else { v_scale += 0.01; } break; case KEY_O: if (v_scale > 0.1) { v_scale -= 0.1; } else if (v_scale > 0.01) { v_scale -= 0.01; } break; case KEY_LEFT: canvas_offset.x += 100; break; case KEY_RIGHT: canvas_offset.x -= 100; break; case KEY_UP: canvas_offset.y += 100; break; case KEY_DOWN: canvas_offset.y -= 100; break; } } while (key_pressed != 0); if (universe.num_bodies < 1024 && (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsMouseButtonDown(MOUSE_RIGHT_BUTTON))) { Vector2 mouse_pos = vec2_scale( transform_to_center(vec2_scale(GetMousePosition(), -1)), -1); mouse_pos = vec2_scale(mouse_pos, 1 / v_scale); universe.bodies[universe.num_bodies] = (mass_body_t){100000.0f, 0.1, mouse_pos, {0, 0}, 10, 0, ""}; snprintf(universe.bodies[universe.num_bodies].name, sizeof(universe.bodies[universe.num_bodies].name), "Body %u", universe.num_bodies + 1); universe.num_bodies++; } if (canvas_offset.x + GetRenderWidth() * 0.5 / v_scale > GetRenderWidth() * 50) { canvas_offset.x = -GetRenderWidth() * 0.5 / v_scale + GetRenderWidth() * 50; } else if (canvas_offset.x - GetRenderWidth() * 0.5 / v_scale < -GetRenderWidth() * 50) { canvas_offset.x = GetRenderWidth() * 0.5 / v_scale - GetRenderWidth() * 50; } if (canvas_offset.y + GetRenderHeight() * 0.5 / v_scale > GetRenderHeight() * 50) { canvas_offset.y = -GetRenderHeight() * 0.5 / v_scale + GetRenderHeight() * 50; } else if (canvas_offset.y - GetRenderHeight() * 0.5 / v_scale < -GetRenderHeight() * 50) { canvas_offset.y = GetRenderHeight() * 0.5 / v_scale - GetRenderHeight() * 50; } BeginDrawing(); ClearBackground(RAYWHITE); for (unsigned int i = 0; i < universe.num_bodies; i++) { Vector2 scaled_offset = vec2_scale(canvas_offset, v_scale); Vector2 body_position = vec2_scale(universe.bodies[i].position, v_scale); body_position = vec2_sum(body_position, scaled_offset); body_position = transform_to_center(body_position); float draw_radius = universe.bodies[i].draw_radius * v_scale; DrawCircleV(body_position, draw_radius, (Color){((256 / universe.num_bodies) * i) % 256 / 2, 255 * (i % 2) / 2, 255 * (i % 2) * (i % 3) / 2, 255}); // Keep labels readable at every zoom level. DrawText(universe.bodies[i].name, (int)(body_position.x + draw_radius + 6), (int)(body_position.y - 8), 16, BLACK); } DrawText(welcome_text, center_x_text(welcome_text, GetRenderWidth(), 20), center_y_text(GetRenderHeight(), 20), 20, BLACK); EndDrawing(); } CloseWindow(); return EXIT_SUCCESS; }