208 lines
5.9 KiB
C
208 lines
5.9 KiB
C
#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 <errno.h>
|
|
#include <math.h>
|
|
#include <pthread.h>
|
|
#include <raylib.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
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(int argc, char **argv) {
|
|
if (argc != 2) {
|
|
printf("No config provided\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
FILE *file = fopen(argv[1], "r");
|
|
if (file == NULL) {
|
|
printf("File not found");
|
|
return EXIT_FAILURE;
|
|
}
|
|
int cam_lock = -1;
|
|
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 = 0;
|
|
char line[1024];
|
|
fgets(line, 1024, file);
|
|
while (fgets(line, 1024, file)) {
|
|
printf("%s", line);
|
|
float mass, radius, x, y, vx, vy, draw_radius, charge;
|
|
char name[32];
|
|
sscanf(line, "%f, %f, {%f, %f}, {%f, %f}, %f, %f, %31s", &mass, &radius, &x,
|
|
&y, &vx, &vy, &draw_radius, &charge, name);
|
|
|
|
universe.bodies[universe.num_bodies] = (mass_body_t){
|
|
.mass = mass,
|
|
.radius = radius / EARTH_RADIUS,
|
|
.position = (Vector2){x * UA / EARTH_RADIUS, y * UA / EARTH_RADIUS},
|
|
.speed = (Vector2){vx / EARTH_RADIUS, vy / EARTH_RADIUS},
|
|
.draw_radius = draw_radius / EARTH_RADIUS,
|
|
.charge = charge};
|
|
|
|
memcpy((void *)&universe.bodies[universe.num_bodies].name, (void *)&name,
|
|
32);
|
|
universe.num_bodies++;
|
|
}
|
|
|
|
fclose(file);
|
|
|
|
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:
|
|
v_scale *= 1.26;
|
|
break;
|
|
case KEY_O:
|
|
v_scale /= 1.26;
|
|
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;
|
|
case KEY_ONE:
|
|
cam_lock = 1;
|
|
break;
|
|
case KEY_TWO:
|
|
cam_lock = 2;
|
|
break;
|
|
case KEY_THREE:
|
|
cam_lock = 3;
|
|
break;
|
|
case KEY_FOUR:
|
|
cam_lock = 4;
|
|
break;
|
|
case KEY_FIVE:
|
|
cam_lock = 5;
|
|
break;
|
|
case KEY_SIX:
|
|
cam_lock = 6;
|
|
break;
|
|
case KEY_SEVEN:
|
|
cam_lock = 7;
|
|
break;
|
|
case KEY_EIGHT:
|
|
cam_lock = 8;
|
|
break;
|
|
case KEY_NINE:
|
|
cam_lock = 9;
|
|
break;
|
|
case KEY_ZERO:
|
|
cam_lock = 0;
|
|
break;
|
|
case KEY_F:
|
|
cam_lock = -1;
|
|
}
|
|
} 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++;
|
|
}
|
|
|
|
BeginDrawing();
|
|
ClearBackground(RAYWHITE);
|
|
for (unsigned int i = 0; i < universe.num_bodies; i++) {
|
|
Vector2 local_offset = canvas_offset;
|
|
if (cam_lock != -1) {
|
|
local_offset = vec2_scale(universe.bodies[cam_lock].position, -1);
|
|
}
|
|
Vector2 scaled_offset = vec2_scale(local_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;
|
|
if (draw_radius < 2) {
|
|
draw_radius = 2;
|
|
}
|
|
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;
|
|
}
|