Hot reloading: Makefile, inotify, epoll, and splitting .c/.h files

This commit is contained in:
Joseph Ferano 2024-01-09 20:32:12 +07:00
parent 44dc3ccd48
commit a5c6569162
8 changed files with 220 additions and 98 deletions

2
.gitignore vendored
View File

@ -5,3 +5,5 @@
/sprites.o
/dod
/boids
/boids_main
/libboids.so

View File

@ -1,4 +1,4 @@
CFLAGS=-g -fsanitize=address -Wall -Wextra -pedantic -O0
CFLAGS=-g -fsanitize=address -fno-omit-frame-pointer -Wall -Wextra -pedantic -O0
CC=gcc
.PHONY: build clean run all
@ -14,8 +14,11 @@ sprites.o: sprites.c sprites.h lib.h
dod: dod.c ./lib/libraylib.a
$(CC) $(CFLAGS) -Iinclude/ -lm dod.c -o dod ./lib/libraylib.a
boids: boids.c lib.h ./lib/libraylib.a
$(CC) $(CFLAGS) -Iinclude/ -lm boids.c -o boids ./lib/libraylib.a
boids_main: boids_main.c lib.h ./lib/libraylib.a
$(CC) $(CFLAGS) -Iinclude/ -lm $< -o $@ ./lib/libraylib.a
libboids.so: boids_game.c boids_game.h lib.h
$(CC) $(CFLAGS) -Iinclude/ -lm -c $< -o $@
run: all
./main

87
boids.c
View File

@ -1,87 +0,0 @@
#include "include/raylib.h"
#include "include/raymath.h"
#include <stdio.h>
#include <stdlib.h>
#include "lib.h"
#define SCREEN_WIDTH 1024
#define SCREEN_HEIGHT 768
#define TARGET_FPS 60
#define NUM_BOIDS 16
const float max_speed = 5.0f;
const float max_force = 0.05;
typedef struct Boid {
Point position;
Vector2 acceleration;
Vector2 velocity;
} Boid;
int main(void) {
InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Boids");
SetTargetFPS(TARGET_FPS);
Boid *boids = calloc(NUM_BOIDS, sizeof(Boid));
for (int i = 0; i < NUM_BOIDS; i++) {
Boid *boid = &boids[i];
int rand_x = GetRandomValue(0, SCREEN_WIDTH);
int rand_y = GetRandomValue(0, SCREEN_HEIGHT);
boid->position = (Vector2){rand_x, rand_y};
int rand_vx = GetRandomValue(0, 100);
int rand_vy = GetRandomValue(0, 100);
boid->velocity = (Vector2){rand_vx * 0.01f - 0.5f, rand_vy * 0.01f - 0.5f};
boid->velocity = Vector2Scale(boid->velocity, 10.0f);
// int rand_ax = GetRandomValue(0, 100);
// int rand_ay = GetRandomValue(0, 100);
// boid->velocity = (Vector2){rand_ax * 0.01f - 0.5f, rand_ay * 0.01f - 0.5f};
}
PointOption target_pos = {0};
while (!WindowShouldClose()) {
float dt = GetFrameTime();
// Update
if (IsMouseButtonPressed(0)) {
Vector2 mouse_pos = GetMousePosition();
target_pos = (PointOption){.tag = SOME, .some.point = mouse_pos};
}
for (int i = 0; i < NUM_BOIDS; i++) {
Boid *boid = &boids[i];
if (target_pos.tag == SOME) {
Vector2 desired = Vector2Subtract(target_pos.some.point, boid->position);
desired = Vector2Normalize(desired);
desired = Vector2Scale(desired, max_speed);
Vector2 steer = Vector2Subtract(desired, boid->velocity);
steer = Vector2ClampValue(steer, 0.0f, max_force);
boid->acceleration = Vector2Add(boid->acceleration, steer);
}
boid->velocity = Vector2Add(boid->velocity, boid->acceleration);
boid->velocity = Vector2ClampValue(boid->velocity, 0.0f, max_speed);
boid->position = Vector2Add(boid->position, boid->velocity);
}
BeginDrawing();
{
ClearBackground(RAYWHITE);
// You can draw a triangle but you'd need to rotate all 3 vectors, and I don't
// want to get distracted with that
// DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, GREEN);
// DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, GREEN);
for (int i = 0; i < NUM_BOIDS; i++) {
Boid *boid = &boids[i];
DrawCircle(boid->position.x, boid->position.y, 27, BLACK);
DrawCircle(boid->position.x, boid->position.y, 20, GREEN);
}
}
EndDrawing();
}
free(boids);
CloseWindow();
}

102
boids_game.c Normal file
View File

@ -0,0 +1,102 @@
#include <stdlib.h>
#include "include/raylib.h"
#include "include/raymath.h"
#include "boids_game.h"
#include "lib.h"
#define SCREEN_WIDTH 1300
#define SCREEN_HEIGHT 1080
#define NUM_BOIDS 16
typedef struct Boid {
Point position;
Vector2 acceleration;
Vector2 velocity;
} Boid;
typedef struct GameState {
Boid *boids;
PointOption target_pos;
int num_boids;
float max_speed;
float max_force;
} GameState;
GameState *init() {
GameState *state = malloc(sizeof(struct GameApi));
state->num_boids = 16;
state->max_speed = 5.0f;
state->max_force = 0.05;
Boid *boids = malloc(state->num_boids * sizeof(Boid));
state->boids = boids;
for (int i = 0; i < state->num_boids; i++) {
Boid *boid = &boids[i];
int rand_x = GetRandomValue(0, SCREEN_WIDTH);
int rand_y = GetRandomValue(0, SCREEN_HEIGHT);
boid->position = (Vector2){rand_x, rand_y};
int rand_vx = GetRandomValue(0, 100);
int rand_vy = GetRandomValue(0, 100);
boid->velocity = (Vector2){rand_vx * 0.01f - 0.5f, rand_vy * 0.01f - 0.5f};
// boid->velocity = Vector2Scale(boid->velocity, 10.0f);
// int rand_ax = GetRandomValue(0, 100);
// int rand_ay = GetRandomValue(0, 100);
// boid->velocity = (Vector2){rand_ax * 0.01f - 0.5f, rand_ay * 0.01f - 0.5f};
boid->acceleration = (Vector2){0};
}
return state;
}
void finalize(GameState *state) {
(void)state;
}
void reload(GameState *state) {
(void)state;
}
void unload(GameState *state) {
(void)state;
}
void step(GameState *state) {
// Process Input
if (IsMouseButtonPressed(0)) {
Vector2 mouse_pos = GetMousePosition();
state->target_pos = (PointOption){.tag = SOME, .some.point = mouse_pos};
}
// Update
for (int i = 0; i < NUM_BOIDS; i++) {
Boid *boid = &state->boids[i];
if (state->target_pos.tag == SOME) {
Vector2 desired = Vector2Subtract(state->target_pos.some.point, boid->position);
desired = Vector2Normalize(desired);
desired = Vector2Scale(desired, state->max_speed);
Vector2 steer = Vector2Subtract(desired, boid->velocity);
steer = Vector2ClampValue(steer, 0.0f, state->max_force);
boid->acceleration = Vector2Add(boid->acceleration, steer);
}
boid->velocity = Vector2Add(boid->velocity, boid->acceleration);
boid->velocity = Vector2ClampValue(boid->velocity, 0.0f, state->max_speed);
boid->position = Vector2Add(boid->position, boid->velocity);
}
// Update
BeginDrawing();
{
ClearBackground(RAYWHITE);
// You can draw a triangle but you'd need to rotate all 3 vectors, and I don't
// want to get distracted with that
// DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, GREEN);
// DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, GREEN);
for (int i = 0; i < NUM_BOIDS; i++) {
Boid *boid = &state->boids[i];
DrawCircle(boid->position.x, boid->position.y, 27, BLACK);
DrawCircle(boid->position.x, boid->position.y, 20, GREEN);
}
}
EndDrawing();
}

13
boids_game.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
struct GameState;
typedef struct GameApi {
struct GameApi *(*init)();
void (*finalize) (struct GameApi *state);
void (*reload) (struct GameApi *state);
void (*unload) (struct GameApi *state);
void (*step) (struct GameApi *state);
} GameApi;
extern const struct GameApi GAME_API;

79
boids_main.c Normal file
View File

@ -0,0 +1,79 @@
#define _DEFAULT_SOURCE // usleep()
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <sys/epoll.h>
#include <sys/inotify.h>
// #include "inotify-syscalls.h"
#include "include/raylib.h"
#include "include/raymath.h"
#include "boids_game.h"
#define SCREEN_WIDTH 1300
#define SCREEN_HEIGHT 1080
#define TARGET_FPS 60
const char *GAME_LIB = "./libboids.so";
char epoll_buf[1024];
struct Game {
void *handle;
struct GameApi api;
struct GameState *state;
};
#define MAX_EVENTS 1
int main(void) {
int fd = inotify_init();
if (fd < 0) {
fprintf(stderr, "Error initializing inotify\n");
}
int wd;
wd = inotify_add_watch(fd, GAME_LIB, IN_MODIFY);
// create epoll instance
int epollfd = epoll_create1(0);
if (epollfd == -1) {
fprintf(stderr, "Error creating epoll instance\n");
}
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = fd;
// register inotify fd with epoll
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event) == -1) {
fprintf(stderr, "Error adding inotify descriptor to epoll\n");
}
InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Boids");
SetTargetFPS(TARGET_FPS);
struct epoll_event events[MAX_EVENTS];
while (!WindowShouldClose()) {
int nfds = epoll_wait(epollfd, events, MAX_EVENTS, 0);
if (nfds == -1) {
fprintf(stderr, "epoll_wait failed\n");
break;
}
for (int n = 0; n < nfds; ++n) {
if (events[n].data.fd == fd) {
printf("SO has been updated!\n");
read(fd, epoll_buf, sizeof(epoll_buf));
}
}
BeginDrawing();
ClearBackground(BEIGE);
EndDrawing();
}
inotify_rm_watch(fd, wd);
close(fd);
close(epollfd);
CloseWindow();
}

View File

@ -1,12 +1,22 @@
* Bexorg Hours
#+BEGIN: clocktable :scope subtree :maxlevel 2
#+CAPTION: Clock summary at [2024-01-06 Sat 12:28]
| Headline | Time |
|------------+------|
| *Total time* | *0:00* |
#+CAPTION: Clock summary at [2024-01-09 Tue 20:31]
| Headline | Time | |
|----------------------+------+------|
| *Total time* | *3:41* | |
|----------------------+------+------|
| Bexorg Hours | 3:41 | |
| \_ <2024-01-06 Sat> | | 2:10 |
| \_ <2024-01-09 Tue> | | 1:31 |
#+END:
** <2024-01-06 Sat>
:LOGBOOK:
CLOCK: [2024-01-06 Sat 11:00]--[2024-01-06 Sat 13:10] => 2:10
:END:
** <2024-01-09 Tue>
:LOGBOOK:
CLOCK: [2024-01-09 Tue 19:30]--[2024-01-09 Tue 20:31] => 1:01
CLOCK: [2024-01-09 Tue 10:45]--[2024-01-09 Tue 11:15] => 0:30
:END:

8
main.c
View File

@ -6,7 +6,7 @@
#define TEXTURES_BUF_SIZE 16
#define TARGET_FPS 60
#define MAX_KNIGHTS 512
#define MAX_KNIGHTS 10000
#define SCREEN_WIDTH 1300
#define SCREEN_HEIGHT 1080
@ -36,7 +36,7 @@ typedef enum Direction {
// DIR_DOWN_RIGHT = 7,
} Direction;
typedef struct {
typedef struct Knight {
Point position;
Point move_target_point;
u8 look_dir;
@ -45,7 +45,7 @@ typedef struct {
u8 ordered_to_move;
} Knight;
typedef struct {
typedef struct GameState {
int frame_count;
Point camera_position;
@ -59,7 +59,7 @@ typedef struct {
int entity_count;
} GameState;
typedef struct {
typedef struct Assets {
Texture2D *textures;
} Assets;