1
0
Fork 0

Refactor engine to make less allocations

This commit is contained in:
Pabloader 2025-12-17 09:53:37 +00:00
parent 307be47251
commit b1f93ce9b1
3 changed files with 96 additions and 83 deletions

View File

@ -106,7 +106,7 @@ async function instantiate(url: string) {
const memory = new WebAssembly.Memory({
initial: 32,
});
const table = new WebAssembly.Table({ initial: 1, element: 'anyfunc' });
const table = new WebAssembly.Table({ initial: 16, element: 'anyfunc' });
let data = new DataView(memory.buffer);
const decoder = new TextDecoder();
let buf = '';

View File

@ -2,13 +2,15 @@
#include <math.h>
#include <memory.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <vec2.h>
#define TYPE_EMPTY 0
#define TYPE_CIRCLE 1
#define TYPE_PLANE 2
#define MAX_BODIES 1000
#define rigid_body_get(idx) (rigid_bodies + (idx))
////////// Types
@ -29,29 +31,34 @@ typedef struct rigid_body_t {
};
// Private
vec2 force;
struct rigid_body_t* prev;
struct rigid_body_t* next;
} rigid_body;
typedef void (*rigid_body_collision_callback_t)(rigid_body* a, rigid_body* b);
typedef size_t rigid_body_index;
typedef void (*rigid_body_collision_callback_t)(rigid_body_index a, rigid_body_index b);
////////// Prototypes
void rigid_body_resolve_collision(rigid_body* rb);
void rigid_body_handle_collision(rigid_body* a, rigid_body* b);
void rigid_body_resolve_collision(rigid_body_index rb);
void rigid_body_handle_collision(rigid_body_index a, rigid_body_index b);
float point_to_line_dist(vec2 point, vec2 line_point, vec2 line_norm);
rigid_body_index rigid_body_find_empty();
////////// Globals
static rigid_body* rigid_body_head = NULL;
static rigid_body* rigid_body_tail = NULL;
static rigid_body* rigid_bodies = NULL;
static size_t rigid_bodies_cap = 0;
static rigid_body_collision_callback_t rigid_body_collision_callback = NULL;
////////// Functions
rigid_body* rigid_body_new(float x, float y, float vx, float vy, float mass) {
rigid_body* rb = malloc(sizeof(rigid_body));
memset(rb, 0, sizeof(rigid_body));
EXPORT(rigid_body_get) rigid_body* _rigid_body_get(rigid_body_index idx) {
return rigid_body_get(idx);
}
size_t rigid_body_new(float x, float y, float vx, float vy, float mass) {
rigid_body_index idx = rigid_body_find_empty();
rigid_body* rb = rigid_body_get(idx);
rb->type = TYPE_EMPTY;
rb->pos.x = x;
rb->pos.y = y;
@ -63,58 +70,37 @@ rigid_body* rigid_body_new(float x, float y, float vx, float vy, float mass) {
rb->force.y = 0;
rb->mass = mass;
rb->prev = NULL;
rb->next = NULL;
if (!rigid_body_head) {
rigid_body_head = rb;
rigid_body_tail = rb;
} else {
rigid_body_tail->next = rb;
rb->prev = rigid_body_tail;
rigid_body_tail = rb;
}
return rb;
return idx;
}
EXPORT(rigid_body_new_circle) rigid_body* rigid_body_new_circle(float x, float y, float vx, float vy, float mass, float radius) {
rigid_body* rb = rigid_body_new(x, y, vx, vy, mass);
EXPORT(rigid_body_new_circle) rigid_body_index rigid_body_new_circle(float x, float y, float vx, float vy, float mass, float radius) {
rigid_body_index idx = rigid_body_new(x, y, vx, vy, mass);
rigid_body* rb = rigid_body_get(idx);
rb->type = TYPE_CIRCLE;
rb->circle.radius = radius;
return rb;
return idx;
}
EXPORT(rigid_body_new_plane) rigid_body* rigid_body_new_plane(float x, float y, float nx, float ny) {
rigid_body* rb = rigid_body_new(x, y, 0, 0, INFINITY);
EXPORT(rigid_body_new_plane) rigid_body_index rigid_body_new_plane(float x, float y, float nx, float ny) {
rigid_body_index idx = rigid_body_new(x, y, 0, 0, INFINITY);
rigid_body* rb = rigid_body_get(idx);
rb->type = TYPE_PLANE;
rb->plane.normal = vec2_normalize((vec2){nx, ny});
return rb;
return idx;
}
EXPORT(rigid_body_free) void rigid_body_free(rigid_body* rb) {
if (rb == rigid_body_head) {
rigid_body_head = rb->next;
}
if (rb == rigid_body_tail) {
rigid_body_tail = rb->prev;
}
if (rb->prev) {
rb->prev->next = rb->next;
}
if (rb->next) {
rb->next->prev = rb->prev;
}
free(rb);
EXPORT(rigid_body_free) void rigid_body_free(rigid_body_index idx) {
memset(rigid_body_get(idx), 0, sizeof(rigid_body));
}
EXPORT(rigid_body_update) void rigid_body_update(rigid_body* rb, float dt) {
rigid_body_resolve_collision(rb);
EXPORT(rigid_body_update) void rigid_body_update(rigid_body_index idx, float dt) {
rigid_body_resolve_collision(idx);
rigid_body* rb = rigid_body_get(idx);
if (!isinf(rb->mass)) {
rb->vel.x += rb->force.x * dt / rb->mass;
@ -129,26 +115,28 @@ EXPORT(rigid_body_update) void rigid_body_update(rigid_body* rb, float dt) {
}
EXPORT(rigid_body_update_all) void rigid_body_update_all(float dt) {
rigid_body* current = rigid_body_head;
while (current) {
rigid_body_update(current, dt);
current = current->next;
for (rigid_body_index idx = 0; idx < rigid_bodies_cap; idx++) {
rigid_body* current = rigid_body_get(idx);
if (current->type == TYPE_EMPTY) {
continue;
}
rigid_body_update(idx, dt);
}
}
EXPORT(rigid_body_add_force) void rigid_body_add_force(rigid_body* rb, float fx, float fy) {
EXPORT(rigid_body_add_force) void rigid_body_add_force(rigid_body_index idx, float fx, float fy) {
rigid_body* rb = rigid_body_get(idx);
rb->force.x += fx;
rb->force.y += fy;
}
EXPORT(rigid_body_add_global_force) void rigid_body_add_global_force(float fx, float fy) {
rigid_body* current = rigid_body_head;
while (current) {
rigid_body_add_force(current, fx, fy);
current = current->next;
for (rigid_body_index idx = 0; idx < rigid_bodies_cap; idx++) {
rigid_body* current = rigid_body_get(idx);
if (current->type == TYPE_EMPTY) {
continue;
}
rigid_body_add_force(idx, fx, fy);
}
}
@ -156,19 +144,20 @@ EXPORT(rigid_body_set_collision_callback) void rigid_body_set_collision_callback
rigid_body_collision_callback = callback;
}
void rigid_body_resolve_collision(rigid_body* rb) {
rigid_body* current = rb->next;
void rigid_body_resolve_collision(rigid_body_index idx) {
rigid_body* rb = rigid_body_get(idx);
int is_static = isinf(rb->mass);
while (current) {
for (rigid_body_index i = idx + 1; i < rigid_bodies_cap; i++) {
rigid_body* current = rigid_body_get(i);
if (!is_static || !isinf(current->mass)) {
rigid_body_handle_collision(rb, current);
rigid_body_handle_collision(idx, i);
}
current = current->next;
}
}
void rigid_body_handle_collision(rigid_body* rb1, rigid_body* rb2) {
void rigid_body_handle_collision(rigid_body_index idx1, rigid_body_index idx2) {
rigid_body* rb1 = rigid_body_get(idx1);
rigid_body* rb2 = rigid_body_get(idx2);
if (rb1->type == TYPE_CIRCLE && rb2->type == TYPE_CIRCLE) {
vec2 d = vec2_sub(rb2->pos, rb1->pos);
float distance = vec2_mag(d);
@ -179,7 +168,7 @@ void rigid_body_handle_collision(rigid_body* rb1, rigid_body* rb2) {
}
if (rigid_body_collision_callback) {
rigid_body_collision_callback(rb1, rb2);
rigid_body_collision_callback(idx1, idx2);
}
vec2 n = vec2_normalize(d);
@ -228,7 +217,7 @@ void rigid_body_handle_collision(rigid_body* rb1, rigid_body* rb2) {
}
if (rigid_body_collision_callback) {
rigid_body_collision_callback(rb1, rb2);
rigid_body_collision_callback(idx1, idx2);
}
vec2 n = rb1->plane.normal;
@ -238,9 +227,9 @@ void rigid_body_handle_collision(rigid_body* rb1, rigid_body* rb2) {
float vn = vec2_dot(rb2->vel, n);
vec2 vt = vec2_sub(rb2->vel, vec2_mul(n, vn));
rb2->vel = vec2_add(vt, vec2_mul(n, -vn));
rb2->vel = vec2_add(vt, vec2_mul(n, -vn));
} else if (rb1->type == TYPE_CIRCLE && rb2->type == TYPE_PLANE) {
rigid_body_handle_collision(rb2, rb1);
rigid_body_handle_collision(idx2, idx1);
}
}
@ -248,3 +237,26 @@ float point_to_line_dist(vec2 p, vec2 line_point, vec2 normal) {
vec2 diff = vec2_sub(p, line_point);
return vec2_dot(diff, normal);
}
rigid_body_index rigid_body_find_empty() {
if (rigid_bodies) {
for (rigid_body_index idx = 0; idx < rigid_bodies_cap; idx++) {
rigid_body* current = rigid_body_get(idx);
if (current->type == TYPE_EMPTY) {
memset(current, 0, sizeof(rigid_body));
return idx;
}
}
size_t new_cap = rigid_bodies_cap * 2;
printf("Reallocate to %zu\n", new_cap);
rigid_bodies = realloc(rigid_bodies, new_cap * sizeof(rigid_body));
memset(rigid_bodies + rigid_bodies_cap, 0, rigid_bodies_cap * sizeof(rigid_body));
rigid_bodies_cap = new_cap;
return rigid_body_find_empty();
} else {
rigid_bodies_cap = 1;
rigid_bodies = malloc(sizeof(rigid_body));
memset(rigid_bodies, 0, sizeof(rigid_body));
return 0;
}
}

View File

@ -30,26 +30,27 @@ namespace Physics {
E.rigid_body_update_all(dt);
}
export function getBody(body: number) {
const type = E.data.getUint8(body);
export function getBody(idx: number) {
const ptr = E.rigid_body_get(idx);
const type = E.data.getUint8(ptr);
const x = E.data.getFloat32(body + 4, true);
const y = E.data.getFloat32(body + 8, true);
const x = E.data.getFloat32(ptr + 4, true);
const y = E.data.getFloat32(ptr + 8, true);
const vx = E.data.getFloat32(body + 12, true);
const vy = E.data.getFloat32(body + 16, true);
const mass = E.data.getFloat32(body + 20, true);
const vx = E.data.getFloat32(ptr + 12, true);
const vy = E.data.getFloat32(ptr + 16, true);
const mass = E.data.getFloat32(ptr + 20, true);
if (type === TYPE_CIRCLE) {
const radius = E.data.getFloat32(body + 24, true);
return { id: body, x, y, vx, vy, mass, radius };
const radius = E.data.getFloat32(ptr + 24, true);
return { id: ptr, x, y, vx, vy, mass, radius };
} else if (type === TYPE_PLANE) {
const nx = E.data.getFloat32(body + 24, true);
const ny = E.data.getFloat32(body + 28, true);
return { id: body, x, y, vx, vy, mass, nx, ny };
const nx = E.data.getFloat32(ptr + 24, true);
const ny = E.data.getFloat32(ptr + 28, true);
return { id: ptr, x, y, vx, vy, mass, nx, ny };
}
return { id: body, x, y, vx, vy, mass };
return { id: ptr, x, y, vx, vy, mass };
}
export function setCollisionCallback(cb: (a: number, b: number) => void) {