Refactor engine to make less allocations
This commit is contained in:
parent
307be47251
commit
b1f93ce9b1
|
|
@ -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 = '';
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue