System info & network

This commit is contained in:
2023-09-26 19:40:16 +02:00
commit 504ba77654
89 changed files with 39577 additions and 0 deletions

17
code/physics/base.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef _PIUMA_PHYSICS_BASE_H_
#define _PIUMA_PHYSICS_BASE_H_
#include "../lib/memory.h"
/* Reassing phy_alloc and phy_free with your own alloc/free functions if you don't
* want to use malloc and free.
*/
extern alloc_t phy_alloc;
extern realloc_t phy_realloc;
extern free_t phy_free;
#define PHY_ALLOC(type, size) (type *)phy_alloc(sizeof(type) * size)
#define PHY_REALLOC(type, ptr, size) (type *)phy_realloc(ptr, sizeof(type) * size)
#define PHY_FREE(ptr) phy_free(ptr)
#endif

28
code/physics/body.cpp Normal file
View File

@@ -0,0 +1,28 @@
#include "body.h"
#include "../lib/geometry.h"
#include <assert.h>
Box phy_aabb_from_body(phy_body *body)
{
Box aabb;
switch(body->shape)
{
case PHY_SHAPE_SPHERE: {
aabb.min = body->position - body->sphere.radius * v3{1,1,1};
aabb.max = body->position + body->sphere.radius * v3{1,1,1};
} break;
case PHY_SHAPE_BOX: {
v3 box[8]; build_cube_vertices(box);
m3 rotoscale = M3(rotation_v3(body->rotation) * scale_v3(body->box.dimensions));
for(u32 i = 0; i < 8; i++)
box[i] = body->position + rotoscale * box[i];
aabb = box_from_point_cloud(box, 8);
} break;
case PHY_SHAPE_MESH: {
assert(false && "Yet to be implemented");
} break;
default: { assert(false && "Unknown shape"); }
}
return aabb;
}

61
code/physics/body.h Normal file
View File

@@ -0,0 +1,61 @@
#ifndef _PIUMA_PHYSICS_OBJECT_H_
#define _PIUMA_PHYSICS_OBJECT_H_
#include "../lib/math.h"
#include "../lib/geometry.h"
enum phy_shape_type
{
PHY_SHAPE_SPHERE,
PHY_SHAPE_BOX,
PHY_SHAPE_MESH,
PHY_SHAPE_COUNT
};
struct phy_sphere
{
f32 radius;
};
struct phy_box
{
v3 dimensions;
};
struct phy_mesh
{
// TODO
};
struct phy_body
{
v3 position;
v3 rotation;
f32 mass;
v3 center_of_mass;
f32 gravity_multiplier;
f32 friction;
f32 bounciness;
// Dynamics
v3 velocity;
v3 angular_velocity;
// Collision
phy_shape_type shape;
union
{
phy_sphere sphere;
phy_box box;
phy_mesh mesh;
};
Box aabb;
};
Box phy_aabb_from_body(phy_body *body);
#endif

336
code/physics/collision.cpp Normal file
View File

@@ -0,0 +1,336 @@
#include "collision.h"
#include "../lib/ds.h"
#include "../lib/geometry.h"
#include <assert.h>
void phy_collisions_broadphase(phy_world *world, phy_body_pair *pair_list, u32 max_pairs, u32 *num_pairs)
{
// Update AABBs
for(u32 i = 0; i < world->bodies_count; i++)
{
phy_body *body = world->bodies + i;
body->aabb = phy_aabb_from_body(body);
}
u32 pairs_count = 0;
for(u32 a = 0; a < world->bodies_count; a++)
{
phy_body *body_a = world->bodies + a;
for(u32 b = a + 1; b < world->bodies_count; b++)
{
phy_body *body_b = world->bodies + b;
if(overlaps(body_a->aabb, body_b->aabb))
{
// Add to list of possible collisions.
if(pairs_count < max_pairs)
{
pair_list[pairs_count] = phy_body_pair{
.body_a = body_a,
.body_b = body_b
};
}
pairs_count++;
}
}
}
if(num_pairs)
*num_pairs = pairs_count;
}
// @Cleanup: put this in the right place
// @Performance: this is probably not a good way of doing this
void project_box_on_axis(phy_body *body, v3 axis, f32 *min, f32 *max)
{
v3 points[8];
build_cube_vertices(points);
m4 transform = translation_v3(body->position) * rotation_v3(body->rotation) * scale_v3(body->box.dimensions);
*min = *max = project_point_on_vector(axis, body->position);
for(int i = 0; i < 8; i++)
{
f32 projected = project_point_on_vector(axis, (transform * V4(points[i], 1)).xyz);
*min = minimum(*min, projected);
*max = maximum(*max, projected);
}
}
f32 axis_range_distance(f32 a_min, f32 a_max, f32 b_min, f32 b_max)
{
f32 a_range = a_max - a_min;
f32 a_center = a_min + a_range / 2;
f32 b_range = b_max - b_min;
f32 b_center = b_min + b_range / 2;
return fabs(a_center - b_center) - (a_range + b_range) / 2;
}
bool sat_box_face_point_collision_test(phy_body *body_a, phy_body *body_b, v3 axis, f32 a_size_on_current_axis, f32 *depth, v3 *furthest_a, v3 *furthest_b)
{
f32 a_middle = project_point_on_vector(axis, body_a->position);
f32 b_middle = project_point_on_vector(axis, body_b->position);
f32 direction = (b_middle - a_middle < 0) ? -1 : 1;
f32 boundary = a_middle + direction * a_size_on_current_axis / 2;
f32 dist = +INFINITY;
v3 point;
v3 points[8]; build_cube_vertices(points);
m4 transform = translation_v3(body_b->position) * rotation_v3(body_b->rotation) * scale_v3(body_b->box.dimensions);
for(int i = 0; i < 8; i++)
{
v3 p = (transform * V4(points[i], 1)).xyz;
f32 projected = project_point_on_vector(axis, p);
f32 curr_dist = direction * (projected - boundary);
if(curr_dist < dist)
{
dist = curr_dist;
point = p;
}
}
if(dist < 0) // Possible collision
{
v3 furthest_point_b = point;
v3 furthest_point_a = point + -dist * -direction * axis;
*depth = -dist * direction;
*furthest_a = furthest_point_a;
*furthest_b = furthest_point_b;
return true;
}
// else Separated on this axis. No collision
return false;
}
bool sat_box_collision_test(phy_body *body_a, phy_body *body_b, phy_collision *res_collision)
{
// Separating axis test
// 3 + 3 = 6 face normals
// 3 * 3 = 9 right angle to pair of edges
v3 axes[15];
m4 a_rotation = rotation_v3(body_a->rotation);
axes[0] = extract_column(a_rotation, 0).xyz;
axes[1] = extract_column(a_rotation, 1).xyz;
axes[2] = extract_column(a_rotation, 2).xyz;
m4 b_rotation = rotation_v3(body_b->rotation);
axes[3] = -extract_column(b_rotation, 0).xyz;
axes[4] = -extract_column(b_rotation, 1).xyz;
axes[5] = -extract_column(b_rotation, 2).xyz;
for(int a = 0; a < 3; a++)
for(int b = 0; b < 3; b++)
{
(axes+6)[3*a + b] = cross(axes[a], axes[b + 3]);
}
phy_collision collision;
collision.body_a = body_a;
collision.body_b = body_b;
collision.depth = +INFINITY;
// Face axes: body a
for(int i = 0; i < 3; i++)
{
v3 axis = axes[i];
f32 depth; v3 furthest_point_a, furthest_point_b;
bool collides = sat_box_face_point_collision_test(body_a, body_b, axis, body_a->box.dimensions.E[i], &depth, &furthest_point_a, &furthest_point_b);
if(!collides)
return false;
if(abs(depth) < abs(collision.depth))
{
collision.depth = depth;
collision.furthest_point_a = furthest_point_a;
collision.furthest_point_b = furthest_point_b;
collision.best_separation_direction = axis;
}
}
// Face axes: body b
for(int i = 0; i < 3; i++)
{
v3 axis = axes[3 + i];
f32 depth; v3 furthest_point_a, furthest_point_b;
bool collides = sat_box_face_point_collision_test(body_b, body_a, axis, body_b->box.dimensions.E[i], &depth, &furthest_point_b, &furthest_point_a);
if(!collides)
return false;
if(abs(depth) < abs(collision.depth))
{
collision.depth = depth;
collision.furthest_point_a = furthest_point_a;
collision.furthest_point_b = furthest_point_b;
collision.best_separation_direction = -axis;
}
}
// @TODO: edge-edge
*res_collision = collision;
return true;
}
void phy_collisions_detection(phy_world *world, phy_body_pair *pair_list, u32 num_pairs, phy_collision *collision_list, u32 max_collisions, u32 *num_collisions)
{
u32 n_collisions = 0;
for(u32 i = 0; i < num_pairs; i++)
{
phy_body *body_a = pair_list[i].body_a;
phy_body *body_b = pair_list[i].body_b;
if(body_b->shape < body_a->shape)
swap(body_b, body_a);
switch(body_a->shape)
{
case PHY_SHAPE_SPHERE:
{
switch(body_b->shape)
{
case PHY_SHAPE_SPHERE:
{
f32 dist = distance(body_a->position, body_b->position);
f32 radius_sum = body_a->sphere.radius + body_b->sphere.radius;
if(dist <= radius_sum)
{
phy_collision collision;
collision.body_a = body_a;
collision.body_b = body_b;
collision.depth = radius_sum - dist;
v3 direction = normalize(body_b->position - body_a->position);
collision.furthest_point_a = body_a->position + (body_a->sphere.radius - collision.depth) * direction;
collision.furthest_point_b = body_b->position + (body_b->sphere.radius - collision.depth) * -direction;
collision.best_separation_direction = direction;
if(n_collisions < max_collisions)
collision_list[n_collisions] = collision;
n_collisions++;
}
} break;
case PHY_SHAPE_BOX:
{
// Use box's cordinate space
m4 box_b_coord_space_transform = rotation_v3(-body_b->rotation) * translation_v3(-body_b->position);
v4 sphere_center4 = box_b_coord_space_transform * V4(body_a->position, 1.0);
v3 sphere_center = sphere_center4.xyz / sphere_center4.w;
Box box = {
.min = -0.5*body_b->box.dimensions,
.max = 0.5*body_b->box.dimensions
};
v3 closest_point;
f32 dist = box_SDF(box, sphere_center, &closest_point);
if(dist - body_a->sphere.radius <= 0)
{
phy_collision collision;
collision.body_a = body_a;
collision.body_b = body_b;
collision.depth = dist - body_a->sphere.radius;
v3 direction = normalize(closest_point - body_a ->position);
collision.furthest_point_a = body_a->position + (body_a->sphere.radius - collision.depth) * direction;
collision.furthest_point_b = body_a->position + body_a->sphere.radius * direction;
collision.best_separation_direction = direction;
if(n_collisions < max_collisions)
collision_list[n_collisions] = collision;
n_collisions++;
}
} break;
case PHY_SHAPE_MESH:
{
assert(false && "Unmanaged PHY_SHAPE pair");
} break;
default:
{
assert(false && "Unmanaged PHY_SHAPE pair");
} break;
}
} break;
case PHY_SHAPE_BOX:
{
switch(body_b->shape)
{
// case PHY_SHAPE_SPHERE: // Already managed
case PHY_SHAPE_BOX:
{
phy_collision collision;
bool collides = sat_box_collision_test(body_a, body_b, &collision);
if(collides)
{
if(n_collisions < max_collisions)
collision_list[n_collisions] = collision;
n_collisions++;
}
} break;
case PHY_SHAPE_MESH:
{
assert(false && "Unmanaged PHY_SHAPE pair");
} break;
default:
{
assert(false && "Unmanaged PHY_SHAPE pair");
} break;
}
} break;
case PHY_SHAPE_MESH:
{
switch(body_b->shape)
{
// case PHY_SHAPE_SPHERE: // Already managed
// case PHY_SHAPE_BOX: // Already managed
case PHY_SHAPE_MESH:
{
assert(false && "Unmanaged PHY_SHAPE pair");
} break;
default:
{
assert(false && "Unmanaged PHY_SHAPE pair");
} break;
}
} break;
default:
{
assert(false && "Unmanaged PHY_SHAPE");
} break;
}
}
*num_collisions = n_collisions;
}
void phy_collisions_resolution(phy_world *world, phy_collision *collision_list, u32 num_collisions)
{
for(u32 i = 0; i < num_collisions; i++)
{
phy_body *body_a = collision_list[i].body_a;
phy_body *body_b = collision_list[i].body_b;
v3 separation_direction = collision_list[i].best_separation_direction;
f32 depth = collision_list[i].depth;
if(body_a->mass != 0) // Not a static body
{
body_a->position += -separation_direction * depth;//-normalize(body_a->velocity) * dot(normalize(body_a->velocity), separation_direction * depth);
body_a->velocity = {0,0,0};//length(body_a->velocity) * separation_direction * body_a->bounciness;
}
if(body_b->mass != 0) // Not a static body
{
body_b->position += separation_direction * depth;//-normalize(body_b->velocity) * dot(normalize(body_b->velocity), separation_direction * depth);
body_b->velocity = {0,0,0};//length(body_a->velocity) * -separation_direction * body_b->bounciness;
}
}
}

35
code/physics/collision.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef _PIUMA_PHYSICS_COLLISION_H_
#define _PIUMA_PHYSICS_COLLISION_H_
#include "world.h"
struct phy_body_pair
{
phy_body *body_a;
phy_body *body_b;
};
struct phy_collision
{
phy_body *body_a;
phy_body *body_b;
f32 depth;
v3 furthest_point_a;
v3 furthest_point_b;
v3 best_separation_direction;
};
// Generates possibile collision pairs and saves it in the memory pointed by pair_list, up to a maximum of max_pairs. The number of possible collisions is returned in num_pairs (might be >= max_pairs).
void phy_collisions_broadphase(phy_world *world, phy_body_pair *pair_list, u32 max_pairs, u32 *num_pairs);
// Generates list of collisions and saves it in the memory pointed by collision_list, up to a maximum of max_pairs. The number of collisions is returned in num_collisions (might be >= max_collisions).
// Uses pair_list (with size num_pairs) as a list of possible collisions (computed with a faster algorithm).
void phy_collisions_detection(phy_world *world, phy_body_pair *pair_list, u32 num_pairs, phy_collision *collision_list, u32 max_collisions, u32 *num_collisions);
// Modifies world state based on collision_list
void phy_collisions_resolution(phy_world *world, phy_collision *collision_list, u32 num_collisions);
#endif

25
code/physics/physics.cpp Normal file
View File

@@ -0,0 +1,25 @@
#include "physics.h"
#include <stdlib.h>
alloc_t phy_alloc = malloc;
realloc_t phy_realloc = realloc;
free_t phy_free = free;
void phy_init()
{
phy_init(malloc, realloc, free);
}
void phy_init(alloc_t alloc, realloc_t realloc, free_t free)
{
phy_alloc = alloc;
phy_realloc = realloc;
phy_free = free;
}
void phy_deinit()
{
}

16
code/physics/physics.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef _PIUMA_PHYSICS_PHYSICS_H_
#define _PIUMA_PHYSICS_PHYSICS_H_
#include "base.h"
#include "body.h"
#include "world.h"
#include "simulation.h"
#include "collision.h"
// Initialization
void phy_init();
void phy_init(alloc_t alloc, realloc_t realloc, free_t free);
void phy_deinit();
#endif

View File

@@ -0,0 +1,40 @@
#include "base.h"
#include "simulation.h"
#include "../lib/geometry.h"
#include "collision.h"
void phy_integrate(phy_world *world, f64 delta_t)
{
for(u32 i = 0; i < world->bodies_count; i++)
{
phy_body *body = world->bodies + i;
body->velocity += world->gravity * body->gravity_multiplier * delta_t;
body->position += body->velocity * delta_t;
body->rotation += body->angular_velocity * delta_t;
}
}
void phy_simulate(phy_world *world, f64 delta_t)
{
// @Performance: Grouping for optimizations (active/inactive, constraints)
phy_integrate(world, delta_t);
u32 max_pairs = 1000; // @Correctness: this should be dynamic and should reuse memory when possible
u32 num_pairs = 0;
phy_body_pair *pair_list = PHY_ALLOC(phy_body_pair, max_pairs);
phy_collisions_broadphase(world, pair_list, max_pairs, &num_pairs);
u32 max_collisions = 1000;
u32 num_collisions = 0;
phy_collision *collision_list = PHY_ALLOC(phy_collision, max_collisions);
phy_collisions_detection(world, pair_list, minimum(max_pairs, num_pairs), collision_list, max_collisions, &num_collisions);
phy_collisions_resolution(world, collision_list, minimum(max_collisions, num_collisions));
PHY_FREE(pair_list);
PHY_FREE(collision_list);
}

View File

@@ -0,0 +1,9 @@
#ifndef _PIUMA_PHYSICS_SIMULATION_H_
#define _PIUMA_PHYSICS_SIMULATION_H_
#include "world.h"
void phy_integrate(phy_world *world, f64 delta_t);
void phy_simulate(phy_world *world, f64 delta_t);
#endif

72
code/physics/world.cpp Normal file
View File

@@ -0,0 +1,72 @@
#include "world.h"
#include "base.h"
phy_world *phy_create_world(v3 gravity)
{
phy_world *world = PHY_ALLOC(phy_world, 1);
world->bodies = NULL;
world->bodies_count = 0;
world->gravity = gravity;
return world;
}
void phy_destroy_world(phy_world *world)
{
PHY_FREE(world->bodies);
world->bodies_count = 0;
}
phy_body_offset phy_new_body(phy_world *world)
{
phy_body_offset offset = world->bodies_count;
world->bodies_count++;
world->bodies = PHY_REALLOC(phy_body, world->bodies, world->bodies_count);
return offset;
}
void phy_body_init_default(phy_body *body)
{
body->position = {0, 0, 0};
body->rotation = {0, 0, 0};
body->mass = 0;
body->center_of_mass = {0, 0, 0};
body->velocity = {0, 0, 0};
body->angular_velocity = {0, 0, 0};
body->gravity_multiplier = 1;
body->friction = 0;
body->bounciness = 1;
}
phy_body_offset phy_create_box(phy_world *world, v3 position, v3 rotation, f32 mass, v3 dimensions)
{
phy_body_offset offset = phy_new_body(world);
phy_body *body = PHY_BODY(world, offset);
phy_body_init_default(body);
body->position = position;
body->rotation = rotation;
body->mass = mass;
body->shape = PHY_SHAPE_BOX;
body->box.dimensions = dimensions;
return offset;
}
phy_body_offset phy_create_sphere(phy_world *world, v3 position, v3 rotation, f32 mass, f32 radius)
{
phy_body_offset offset = phy_new_body(world);
phy_body *body = PHY_BODY(world, offset);
phy_body_init_default(body);
body->position = position;
body->rotation = rotation;
body->mass = mass;
body->shape = PHY_SHAPE_SPHERE;
body->sphere.radius = radius;
return offset;
}

23
code/physics/world.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef _PIUMA_PHYSICS_WORLD_H_
#define _PIUMA_PHYSICS_WORLD_H_
#include "body.h"
struct phy_world
{
phy_body *bodies;
u32 bodies_count;
v3 gravity;
};
typedef u32 phy_body_offset;
#define PHY_BODY(world, offset) (world->bodies + offset)
phy_world *phy_create_world(v3 gravity);
void phy_destroy_world(phy_world *world);
phy_body_offset phy_create_box(phy_world *world, v3 position, v3 rotation, f32 mass, v3 dimensions);
phy_body_offset phy_create_sphere(phy_world *world, v3 position, v3 rotation, f32 mass, f32 radius);
#endif