From 97702f11ea016ca2e395f71f03c3fc3a2ee929ca Mon Sep 17 00:00:00 2001 From: esquizo Date: Sun, 17 May 2026 12:02:56 -0300 Subject: adicionado libphysics --- include/physics.h | 25 +++++++++ libphysics/Makefile | 21 ++++++++ libphysics/_map.c | 20 +++++++ libphysics/aabb.c | 52 ++++++++++++++++++ libphysics/body.c | 81 ++++++++++++++++++++++++++++ libphysics/dat.h | 24 +++++++++ libphysics/event.c | 44 +++++++++++++++ libphysics/test/Makefile | 19 +++++++ libphysics/test/vis.c | 120 +++++++++++++++++++++++++++++++++++++++++ libphysics/tick.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 544 insertions(+) create mode 100644 include/physics.h create mode 100644 libphysics/Makefile create mode 100644 libphysics/_map.c create mode 100644 libphysics/aabb.c create mode 100644 libphysics/body.c create mode 100644 libphysics/dat.h create mode 100644 libphysics/event.c create mode 100644 libphysics/test/Makefile create mode 100644 libphysics/test/vis.c create mode 100644 libphysics/tick.c diff --git a/include/physics.h b/include/physics.h new file mode 100644 index 0000000..8a43915 --- /dev/null +++ b/include/physics.h @@ -0,0 +1,25 @@ +typedef enum { + BTYPE_AABB, + BTYPE_TILEMAP, +} BodyType; + +typedef struct Body Body; +typedef struct CollisionEvent { + Body *body1; + Body *body2; +} CollisionEvent; + +Body *phxnew(BodyType type); +void phxdel(Body *); + +void phxsetmap(int w, int h, int *tiles); + +void phxsetpos(Body *, float x, float y); +void phxsetsize(Body *, float w, float h); +void phxapplyaccel(Body *, float f[2]); + +void phxgetpos(Body *, float pos[2]); +void phxgetsize(Body *, float size[2]); + +int phxnextcollevent(CollisionEvent *ev); +void phxtick(float delta); diff --git a/libphysics/Makefile b/libphysics/Makefile new file mode 100644 index 0000000..cc76e28 --- /dev/null +++ b/libphysics/Makefile @@ -0,0 +1,21 @@ +OBJ=aabb.o\ + body.o\ + event.o\ + _map.o\ + tick.o + +CFLAGS=-I../include -g + +all: libphysics.a + +clean: + rm -f libphysics.a + rm -f $(OBJ) + +libphysics.a: $(OBJ) + ar rcs $@ $^ + +%.o: %.c + $(CC) $< $(CFLAGS) -c -o $@ + +.PHONY: all clean diff --git a/libphysics/_map.c b/libphysics/_map.c new file mode 100644 index 0000000..06d3cad --- /dev/null +++ b/libphysics/_map.c @@ -0,0 +1,20 @@ +#include +#include + +#include +#include + +#include "dat.h" + +int *phxmapbuffer; +int phxmapwidth, phxmapheight; + +void +phxsetmap(int w, int h, int *tiles) +{ + if(phxmapbuffer) + free(phxmapbuffer); + + phxmapbuffer = malloc(w * h * sizeof(phxmapbuffer[0])); + memcpy(phxmapbuffer, tiles, sizeof(phxmapbuffer[0]) * w * h); +} diff --git a/libphysics/aabb.c b/libphysics/aabb.c new file mode 100644 index 0000000..59648c8 --- /dev/null +++ b/libphysics/aabb.c @@ -0,0 +1,52 @@ +#include +#include +#include + +#include "dat.h" + +static void mink(Body *a, Body *b, vec2 min, vec2 max); + +int +phxaabbcheck(Body *a, Body *b) +{ + vec2 min, max; + mink(a, b, min, max); + return min[0] < 0 && max[0] > 0 && min[1] < 0 && max[1] > 0; +} + +void +phxaabbresolv(Body *a, Body *b, vec2 p, vec2 n) +{ + vec2 min, max; + mink(a, b, min, max); + + float hx = fabsf(min[0]) < fabsf(max[0]) ? fabsf(min[0]) : fabsf(max[0]); + float hy = fabsf(min[1]) < fabsf(max[1]) ? fabsf(min[1]) : fabsf(max[1]); + + if(hx < hy) { + n[1] = 0.0; + n[0] = (fabsf(min[0]) < fabsf(max[0]) ? -1.0 : 1.0); + } else { + n[0] = 0; + n[1] = (fabsf(min[1]) < fabsf(max[1]) ? -1.0 : 1.0); + } + + vec2_mul(p, (vec2){ hx, hy }, n); +} + + +void +mink(Body *a, Body *b, vec2 min, vec2 max) +{ + float p[2], s[2]; + + for(int i = 0; i < 2; i++) { + s[i] = a->size[i] + b->size[i]; + p[i] = a->pos[i] - b->pos[i]; + } + + for(int i = 0; i < 2; i++) { + min[i] = p[i] - s[i]; + max[i] = p[i] + s[i]; + } +} diff --git a/libphysics/body.c b/libphysics/body.c new file mode 100644 index 0000000..4ea05bd --- /dev/null +++ b/libphysics/body.c @@ -0,0 +1,81 @@ +#include +#include +#include + +#include "dat.h" + +#define POOL_SIZE 2048 + +Body phxbodypool[POOL_SIZE]; +int phxbodypoolsize; + +static Body *allocbody(void); + +Body * +phxnew(BodyType type) +{ + Body *b; + + if((b = allocbody()) == NULL) + return b; + + b->type = type; + return b; +} + +void +phxdel(Body *b) +{ + b->active = 0; +} + +void +phxsetpos(Body *b, float x, float y) +{ + b->pos[0] = x; + b->pos[1] = y; +} + +void +phxsetsize(Body *b, float w, float h) +{ + b->size[0] = w; + b->size[1] = h; +} + +void +phxgetpos(Body *b, float p[2]) +{ + vec2_dup(p, b->pos); +} + +void +phxgetsize(Body *b, float p[2]) +{ + vec2_dup(p, b->size); +} + +void +phxapplyaccel(Body *b, float a[2]) +{ + vec2_add(b->accel, b->accel, a); +} + +Body * +allocbody(void) +{ + int i; + for(i = 0; i < phxbodypoolsize; i++) { + if(!phxbodypool[i].active) + break; + } + + if(i >= phxbodypoolsize) { + if(phxbodypoolsize == POOL_SIZE) + return NULL; + i = phxbodypoolsize++; + } + + phxbodypool[i].active = 1; + return phxbodypool + i; +} diff --git a/libphysics/dat.h b/libphysics/dat.h new file mode 100644 index 0000000..75869a4 --- /dev/null +++ b/libphysics/dat.h @@ -0,0 +1,24 @@ +typedef struct Body { + BodyType type; + int active; + vec2 pos; + vec2 size; + vec2 vel; + vec2 accel; +} Body; + +void phxmapcollision(Body *); +void phxbodycollision(Body *, Body *); + +int phxaabbcheck(Body *a, Body *b); +void phxcollisionmap(Body *a); +void phxaabbresolv(Body *a, Body *b, vec2 p, vec2 n); + +int phxenqevent(CollisionEvent *ev); +int phxdeqevent(CollisionEvent *ev); + +extern int phxmapwidth, phxmapheight; +extern int *phxmapbuffer; + +extern Body phxbodypool[]; +extern int phxbodypoolsize; diff --git a/libphysics/event.c b/libphysics/event.c new file mode 100644 index 0000000..da836f6 --- /dev/null +++ b/libphysics/event.c @@ -0,0 +1,44 @@ +#include +#include +#include + +#include "dat.h" + +#define EVENT_POOL_SIZE 2048 + +static CollisionEvent event[EVENT_POOL_SIZE]; +static int eventi, evente, events; + +int +phxenqevent(CollisionEvent *ev) +{ + if(events == EVENT_POOL_SIZE) + return 0; + + event[evente] = *ev; + evente = (evente + 1) % EVENT_POOL_SIZE; + events++; + + return 1; +} + +int +phxdeqevent(CollisionEvent *ev) +{ + CollisionEvent *evv; + if(events == 0) + return 0; + + evv = event + eventi; + eventi = (eventi + 1) % EVENT_POOL_SIZE; + + *ev = *evv; + events--; + return 1; +} + +int +phxnextcollevent(CollisionEvent *ev) +{ + return phxdeqevent(ev); +} diff --git a/libphysics/test/Makefile b/libphysics/test/Makefile new file mode 100644 index 0000000..eb1d5cb --- /dev/null +++ b/libphysics/test/Makefile @@ -0,0 +1,19 @@ +CFLAGS=-I../../include -g +LDFLAGS=-L../ -lphysics `pkg-config --libs sdl3` + +all: vis + +clean: + rm -f vis + rm -f vis.o + +vis: ../libphysics.a vis.o + $(CC) $^ $(LDFLAGS) -o $@ + +%.o: %.c + $(CC) $< $(CFLAGS) -c -o $@ + +../libphysics.a: + $(MAKE) -C .. all + +.PHONY: all clean diff --git a/libphysics/test/vis.c b/libphysics/test/vis.c new file mode 100644 index 0000000..d1f3f6f --- /dev/null +++ b/libphysics/test/vis.c @@ -0,0 +1,120 @@ +#include +#include +#include + +#include +#include + +#include "../dat.h" + +#define SBODY 256 + +static void process_events(void); +static void render(void); + +static SDL_Window *window; +static SDL_Renderer *renderer; +static bool running; +static Uint64 old_ticks, new_ticks; + +void +renderrect(vec2 p, vec2 s) +{ + SDL_RenderRect(renderer, &(SDL_FRect){ + .x = p[0] - s[0], + .y = p[1] - s[1], + .w = s[0] * 2.0, + .h = s[1] * 2.0 + }); +} + +int +main() +{ + if(!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)) { + fprintf(stderr, "SDL_Init(): %s\n", SDL_GetError()); + return 1; + } + + if(!SDL_CreateWindowAndRenderer("window", 800, 600, SDL_WINDOW_OPENGL, &window, &renderer)) { + fprintf(stderr, "SDL_CreateWindowAndRenderer: %s\n", SDL_GetError()); + return -1; + } + SDL_SetRenderVSync(renderer, 1); + + #define FLOAT_RAND (2 * (rand() / (float)RAND_MAX) - 1) + + for(int i = 0; i < SBODY; i++) { + Body *b = phxnew(BTYPE_AABB); + assert(b != NULL); + phxsetpos(b, rand() % 800, rand() % 600); + phxsetsize(b, 16.0, 16.0); + phxapplyaccel(b, (float[]){ 100000 * FLOAT_RAND, 100000 * FLOAT_RAND }); + } + + phxsetmap(8, 8, (int[]) { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 1, 0, 0, + 0, 1, 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 1, 1, 0, + 0, 0, 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }); + + running = 1; + old_ticks = SDL_GetTicksNS(); + while(running) { + CollisionEvent event; + double delta; + process_events(); + + new_ticks = SDL_GetTicksNS(); + delta = (new_ticks - old_ticks) / 1000000000.0; + old_ticks = new_ticks; + phxtick(delta); + while(phxnextcollevent(&event)) { + printf("Collision with %p and %p\n", event.body1, event.body2); + } + + render(); + } + + SDL_DestroyWindow(window); + SDL_Quit(); + return 0; +} + +void +process_events() +{ + SDL_Event event; + + while(SDL_PollEvent(&event)) { + switch(event.type) { + case SDL_EVENT_QUIT: + running = false; + break; + } + } +} + +void +render(void) +{ + SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF); + SDL_RenderClear(renderer); + + SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF); + for(int i = 0; i < phxbodypoolsize; i++) { + vec2 p, s; + Body *b = phxbodypool + i; + if(!b->active) + continue; + renderrect(b->pos, b->size); + } + + SDL_RenderPresent(renderer); +} diff --git a/libphysics/tick.c b/libphysics/tick.c new file mode 100644 index 0000000..c6399ab --- /dev/null +++ b/libphysics/tick.c @@ -0,0 +1,138 @@ +#include +#include +#include + +#include "dat.h" + +#define PHX_TICK_TIME (1.0 / 480.0) + +static void tick(void); +static void mapcollision(Body *); +static void bodycollision(Body *); + +#define TILE_SIZE 16 + +void +phxtick(float delta) +{ + static float time; + + time += delta; + if(time >= PHX_TICK_TIME > 0) { + while(time >= PHX_TICK_TIME) { + tick(); + time -= PHX_TICK_TIME; + } + for(int i = 0; i < phxbodypoolsize; i++) { + Body *b = phxbodypool + i; + if(!b->active) + continue; + + b->accel[0] = 0.0; + b->accel[1] = 0.0; + } + } +} + +void +tick(void) +{ + for(int i = 0; i < phxbodypoolsize; i++) { + Body *b = phxbodypool + i; + if(!b->active) + continue; + + vec2_add_scaled(b->vel, b->vel, b->accel, PHX_TICK_TIME); + } + + for(int i = 0; i < phxbodypoolsize; i++) { + Body *b = phxbodypool + i; + if(!b->active) + continue; + + mapcollision(b); + bodycollision(b); + } + + for(int i = 0; i < phxbodypoolsize; i++) { + Body *b = phxbodypool + i; + if(!b->active) + continue; + + vec2_add_scaled(b->pos, b->pos, b->vel, PHX_TICK_TIME); + } +} + +void +mapcollision(Body *a) +{ + int minx, miny, maxx, maxy; + + minx = ((int)(a->pos[0] - a->size[0]) / TILE_SIZE) * TILE_SIZE; + maxx = ((int)(a->pos[0] + a->size[0]) / TILE_SIZE) * TILE_SIZE; + miny = ((int)(a->pos[1] - a->size[1]) / TILE_SIZE) * TILE_SIZE; + maxy = ((int)(a->pos[1] + a->size[1]) / TILE_SIZE) * TILE_SIZE; + + for(int y = miny; y <= maxy + TILE_SIZE; y += TILE_SIZE) + for(int x = minx; x <= maxx + TILE_SIZE; x += TILE_SIZE) { + int tilex = x / (2 * TILE_SIZE); + int tiley = y / (2 * TILE_SIZE); + + if(tilex < 0 || tilex >= phxmapwidth) + continue; + if(tiley < 0 || tiley >= phxmapheight) + continue; + + if(!phxmapbuffer[tilex + tiley * phxmapwidth]) + continue; + + Body b = { + .pos = { + tilex * TILE_SIZE * 2.0, + tiley * TILE_SIZE * 2.0, + }, + .size = { TILE_SIZE, TILE_SIZE }, + }; + + if(phxaabbcheck(a, &b)) { + float p[2], n[2]; + phxaabbresolv(a, &b, p, n); + + vec2_sub(a->pos, a->pos, p); + + if(p[0] != 0.0) { + a->vel[0] = 0; + } else { + a->vel[1] = 0; + } + } + } +} + +void +bodycollision(Body *a) +{ + CollisionEvent event; + for(Body *b = a + 1; b < (a + phxbodypoolsize); b++) { + if(!b->active) + continue; + + if(phxaabbcheck(a, b)) { + float p[2], n[2], rvel[2], j; + phxaabbresolv(a, b, p, n); + + vec2_sub(rvel, a->vel, b->vel); + j = vec2_dot(rvel, n); + + vec2_sub_scaled(a->vel, a->vel, n, 0.5); + vec2_sub_scaled(b->vel, b->vel, n, -0.5); + + vec2_sub_scaled(a->pos, a->pos, p, 0.5); + vec2_sub_scaled(b->pos, b->pos, p, -0.5); + + event.body1 = a; + event.body2 = b; + phxenqevent(&event); + } + } +} -- cgit v1.2.3