separate physics logic from game.c
This commit is contained in:
parent
f4d8ec73e7
commit
0716ebd398
@ -20,6 +20,7 @@
|
|||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
|
#include "phys.h"
|
||||||
|
|
||||||
struct exit_callback {
|
struct exit_callback {
|
||||||
app_exit_callback_func *func;
|
app_exit_callback_func *func;
|
||||||
@ -213,7 +214,8 @@ void app_entry_point(void)
|
|||||||
struct mixer_startup_receipt mixer_sr = mixer_startup();
|
struct mixer_startup_receipt mixer_sr = mixer_startup();
|
||||||
struct sound_startup_receipt sound_sr = sound_startup(&work_sr, &asset_cache_sr, &resource_sr);
|
struct sound_startup_receipt sound_sr = sound_startup(&work_sr, &asset_cache_sr, &resource_sr);
|
||||||
struct draw_startup_receipt draw_sr = draw_startup(&renderer_sr, &font_sr);
|
struct draw_startup_receipt draw_sr = draw_startup(&renderer_sr, &font_sr);
|
||||||
struct game_startup_receipt game_sr = game_startup(&mixer_sr, &sprite_sr, &sound_sr);
|
struct phys_startup_receipt phys_sr = phys_startup();
|
||||||
|
struct game_startup_receipt game_sr = game_startup(&mixer_sr, &sprite_sr, &sound_sr, &phys_sr);
|
||||||
struct user_startup_receipt user_sr = user_startup(&work_sr, &renderer_sr, &font_sr, &sprite_sr, &draw_sr, &game_sr, &asset_cache_sr, &mixer_sr, &window);
|
struct user_startup_receipt user_sr = user_startup(&work_sr, &renderer_sr, &font_sr, &sprite_sr, &draw_sr, &game_sr, &asset_cache_sr, &mixer_sr, &window);
|
||||||
struct playback_startup_receipt playback_sr = playback_startup(&mixer_sr);
|
struct playback_startup_receipt playback_sr = playback_startup(&mixer_sr);
|
||||||
|
|
||||||
|
|||||||
@ -852,6 +852,88 @@ struct collider_closest_points_result collider_closest_points(struct collider_sh
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Time of impact
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
/* Takes 2 shapes and their xforms at t=0 and t=1.
|
||||||
|
* Returns time of impact in range [0, 1]. */
|
||||||
|
f32 collider_time_of_impact(struct collider_shape *c0, struct collider_shape *c1,
|
||||||
|
struct xform xf0_t0, struct xform xf1_t0,
|
||||||
|
struct xform xf0_t1, struct xform xf1_t1,
|
||||||
|
f32 tolerance, u32 max_iterations)
|
||||||
|
{
|
||||||
|
f32 t0 = 0;
|
||||||
|
f32 t1 = 1;
|
||||||
|
f32 t0_sep = 0;
|
||||||
|
f32 t1_sep = 0;
|
||||||
|
f32 t = 0;
|
||||||
|
f32 t_sep = F32_INFINITY;
|
||||||
|
|
||||||
|
/* Find direction p0 -> p1 at t=0 */
|
||||||
|
struct v2 dir;
|
||||||
|
struct v2 dir_neg;
|
||||||
|
{
|
||||||
|
struct collider_closest_points_result closest_points_res = collider_closest_points(c0, c1, xf0_t0, xf1_t0);
|
||||||
|
if (closest_points_res.colliding) {
|
||||||
|
/* Shapes are penetrating at t=0 */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
dir = v2_sub(closest_points_res.p1, closest_points_res.p0);
|
||||||
|
t0_sep = v2_len(dir);
|
||||||
|
dir = v2_div(dir, t0_sep); /* Normalize */
|
||||||
|
dir_neg = v2_neg(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
struct v2 p0 = collider_support_point(c0, xf0_t1, dir);
|
||||||
|
struct v2 p1 = collider_support_point(c1, xf1_t1, dir_neg);
|
||||||
|
t1_sep = v2_dot(dir, v2_sub(p1, p0));
|
||||||
|
if (t1_sep > 0) {
|
||||||
|
/* Shapes are not penetrating at t=1 */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 iteration = 0;
|
||||||
|
while (math_fabs(t_sep) > tolerance) {
|
||||||
|
if (iteration >= max_iterations) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use mix of bisection & false position method to find root
|
||||||
|
* (as described in https://box2d.org/files/ErinCatto_ContinuousCollision_GDC2013.pdf) */
|
||||||
|
if (iteration & 1) {
|
||||||
|
/* Bisect */
|
||||||
|
t = (t1 + t0) / 2.0;
|
||||||
|
} else {
|
||||||
|
/* False position (fastest for linear case) */
|
||||||
|
f32 m = (t1_sep - t0_sep) / (t1 - t0);
|
||||||
|
t = (-t1_sep / m) + t1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct xform xf0 = xform_lerp(xf0_t0, xf0_t1, t);
|
||||||
|
struct xform xf1 = xform_lerp(xf1_t0, xf1_t1, t);
|
||||||
|
|
||||||
|
struct v2 p0 = collider_support_point(c0, xf0, dir);
|
||||||
|
struct v2 p1 = collider_support_point(c1, xf1, dir_neg);
|
||||||
|
t_sep = v2_dot(dir, v2_sub(p1, p0));
|
||||||
|
|
||||||
|
/* Update bracket */
|
||||||
|
if (t_sep > 0) {
|
||||||
|
t0 = t;
|
||||||
|
t0_sep = t_sep;
|
||||||
|
} else {
|
||||||
|
t1 = t;
|
||||||
|
t1_sep = t_sep;
|
||||||
|
}
|
||||||
|
|
||||||
|
++iteration;
|
||||||
|
}
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Debug functions
|
* Debug functions
|
||||||
* TODO: Remove these
|
* TODO: Remove these
|
||||||
|
|||||||
@ -5,13 +5,6 @@
|
|||||||
extern u32 collider_debug_steps;
|
extern u32 collider_debug_steps;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct v2 collider_support_point(struct collider_shape *a, struct xform xf, struct v2 dir);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* Returns simple true or false indicating shape collision */
|
|
||||||
b32 collider_collision_boolean(struct collider_shape *shape0, struct collider_shape *shape1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct collider_menkowski_point {
|
struct collider_menkowski_point {
|
||||||
struct v2 p; /* Menkowski difference point */
|
struct v2 p; /* Menkowski difference point */
|
||||||
struct v2 s0; /* Support point of first shape in dir */
|
struct v2 s0; /* Support point of first shape in dir */
|
||||||
@ -47,8 +40,6 @@ struct collider_collision_points_result {
|
|||||||
struct v2 a0, b0, a1, b1; /* Clipping faces */
|
struct v2 a0, b0, a1, b1; /* Clipping faces */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct collider_collision_points_result collider_collision_points(struct collider_shape *shape0, struct collider_shape *shape1, struct xform xf0, struct xform xf1);
|
|
||||||
|
|
||||||
struct collider_closest_points_result {
|
struct collider_closest_points_result {
|
||||||
struct v2 p0, p1;
|
struct v2 p0, p1;
|
||||||
b32 colliding;
|
b32 colliding;
|
||||||
@ -59,8 +50,14 @@ struct collider_closest_points_result {
|
|||||||
struct collider_prototype prototype;
|
struct collider_prototype prototype;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct v2 collider_support_point(struct collider_shape *a, struct xform xf, struct v2 dir);
|
||||||
|
|
||||||
|
struct collider_collision_points_result collider_collision_points(struct collider_shape *shape0, struct collider_shape *shape1, struct xform xf0, struct xform xf1);
|
||||||
|
|
||||||
struct collider_closest_points_result collider_closest_points(struct collider_shape *shape0, struct collider_shape *shape1, struct xform xf0, struct xform xf1);
|
struct collider_closest_points_result collider_closest_points(struct collider_shape *shape0, struct collider_shape *shape1, struct xform xf0, struct xform xf1);
|
||||||
|
|
||||||
|
f32 collider_time_of_impact(struct collider_shape *c0, struct collider_shape *c1, struct xform xf0_t0, struct xform xf1_t0, struct xform xf0_t1, struct xform xf1_t1, f32 tolerance, u32 max_iterations);
|
||||||
|
|
||||||
struct v2_array menkowski(struct arena *arena, struct collider_shape *shape0, struct collider_shape *shape1, struct xform xf0, struct xform xf1, u32 detail);
|
struct v2_array menkowski(struct arena *arena, struct collider_shape *shape0, struct collider_shape *shape1, struct xform xf0, struct xform xf1, u32 detail);
|
||||||
struct v2_array cloud(struct arena *arena, struct collider_shape *shape0, struct collider_shape *shape1, struct xform xf0, struct xform xf1);
|
struct v2_array cloud(struct arena *arena, struct collider_shape *shape0, struct collider_shape *shape1, struct xform xf0, struct xform xf1);
|
||||||
|
|
||||||
|
|||||||
@ -491,6 +491,11 @@ struct renderer_handle {
|
|||||||
u64 v[1];
|
u64 v[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct entity_handle {
|
||||||
|
u64 idx;
|
||||||
|
u64 gen;
|
||||||
|
};
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Tag structs
|
* Tag structs
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|||||||
122
src/entity.c
122
src/entity.c
@ -397,3 +397,125 @@ void entity_unlink_parent(struct entity *ent)
|
|||||||
ent->prev = entity_nil_handle();
|
ent->prev = entity_nil_handle();
|
||||||
ent->next = entity_nil_handle();
|
ent->next = entity_nil_handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Entity lookup
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
struct entity_lookup entity_lookup_alloc(u64 num_buckets)
|
||||||
|
{
|
||||||
|
ASSERT(num_buckets > 0);
|
||||||
|
struct entity_lookup l = ZI;
|
||||||
|
l.arena = arena_alloc(GIGABYTE(64));
|
||||||
|
l.buckets = arena_push_array_zero(&l.arena, struct entity_lookup_bucket, num_buckets);
|
||||||
|
l.num_buckets = num_buckets;
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
void entity_lookup_release(struct entity_lookup *l)
|
||||||
|
{
|
||||||
|
arena_release(&l->arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct entity_lookup_entry *entity_lookup_get(struct entity_lookup *l, struct entity_lookup_key key)
|
||||||
|
{
|
||||||
|
u64 index = key.hash % l->num_buckets;
|
||||||
|
struct entity_lookup_bucket *bucket = &l->buckets[index];
|
||||||
|
struct entity_lookup_entry *res = NULL;
|
||||||
|
for (struct entity_lookup_entry *e = bucket->first; e; e = e->next) {
|
||||||
|
if (e->key.hash == key.hash) {
|
||||||
|
res = e;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void entity_lookup_set(struct entity_lookup *l, struct entity_lookup_key key, struct entity_handle handle)
|
||||||
|
{
|
||||||
|
u64 index = key.hash % l->num_buckets;
|
||||||
|
struct entity_lookup_bucket *bucket = &l->buckets[index];
|
||||||
|
|
||||||
|
struct entity_lookup_entry *prev = NULL;
|
||||||
|
struct entity_lookup_entry **slot = &bucket->first;
|
||||||
|
while (*slot) {
|
||||||
|
if ((*slot)->key.hash == key.hash) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prev = *slot;
|
||||||
|
slot = &(*slot)->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct entity_lookup_entry *entry = *slot;
|
||||||
|
if (entry) {
|
||||||
|
/* Set existing entry */
|
||||||
|
entry->entity = handle;
|
||||||
|
} else {
|
||||||
|
/* Allocate entry */
|
||||||
|
if (l->first_free_entry) {
|
||||||
|
entry = l->first_free_entry;
|
||||||
|
l->first_free_entry->prev = NULL;
|
||||||
|
l->first_free_entry = entry->next;
|
||||||
|
} else {
|
||||||
|
entry = arena_push(&l->arena, struct entity_lookup_entry);
|
||||||
|
}
|
||||||
|
MEMZERO_STRUCT(entry);
|
||||||
|
|
||||||
|
entry->key = key;
|
||||||
|
entry->entity = handle;
|
||||||
|
if (prev) {
|
||||||
|
entry->prev = prev;
|
||||||
|
prev->next = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
bucket->last = entry;
|
||||||
|
*slot = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void entity_lookup_remove(struct entity_lookup *l, struct entity_lookup_entry *entry)
|
||||||
|
{
|
||||||
|
struct entity_lookup_bucket *bucket = &l->buckets[entry->key.hash % l->num_buckets];
|
||||||
|
struct entity_lookup_entry *prev = entry->prev;
|
||||||
|
struct entity_lookup_entry *next = entry->next;
|
||||||
|
|
||||||
|
if (prev) {
|
||||||
|
prev->next = next;
|
||||||
|
} else {
|
||||||
|
bucket->first = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next) {
|
||||||
|
next->prev = prev;
|
||||||
|
} else {
|
||||||
|
bucket->last = prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l->first_free_entry) {
|
||||||
|
l->first_free_entry->prev = entry;
|
||||||
|
}
|
||||||
|
entry->next = l->first_free_entry;
|
||||||
|
entry->prev = NULL;
|
||||||
|
l->first_free_entry = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct entity_lookup_key entity_lookup_key_from_two_handles(struct entity_handle h0, struct entity_handle h1)
|
||||||
|
{
|
||||||
|
struct entity_lookup_key key = ZI;
|
||||||
|
struct buffer b0 = BUFFER_FROM_STRUCT(&h0);
|
||||||
|
struct buffer b1 = BUFFER_FROM_STRUCT(&h1);
|
||||||
|
key.hash = hash_fnv64(HASH_FNV64_BASIS, b0);
|
||||||
|
key.hash = hash_fnv64(key.hash, b1);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Activate
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
void entity_activate(struct entity *ent, u64 current_tick_id)
|
||||||
|
{
|
||||||
|
entity_enable_prop(ent, ENTITY_PROP_ACTIVE);
|
||||||
|
ent->activation_tick = current_tick_id;
|
||||||
|
++ent->continuity_gen;
|
||||||
|
}
|
||||||
|
|||||||
202
src/entity.h
202
src/entity.h
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "sprite.h"
|
#include "sprite.h"
|
||||||
#include "mixer.h"
|
#include "mixer.h"
|
||||||
|
#include "phys.h"
|
||||||
|
|
||||||
enum entity_prop {
|
enum entity_prop {
|
||||||
ENTITY_PROP_NONE,
|
ENTITY_PROP_NONE,
|
||||||
@ -44,11 +45,6 @@ enum entity_prop {
|
|||||||
ENTITY_PROP_COUNT
|
ENTITY_PROP_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
struct entity_handle {
|
|
||||||
u64 idx;
|
|
||||||
u64 gen;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct entity_store {
|
struct entity_store {
|
||||||
struct arena arena;
|
struct arena arena;
|
||||||
u64 allocated;
|
u64 allocated;
|
||||||
@ -58,154 +54,29 @@ struct entity_store {
|
|||||||
struct entity *entities;
|
struct entity *entities;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct entity_lookup_key {
|
||||||
|
u64 hash;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* TODO: Remove this */
|
|
||||||
#include "collider.h"
|
|
||||||
#include "math.h"
|
|
||||||
|
|
||||||
struct contact_point {
|
|
||||||
/* Contact point in local space of each entity */
|
|
||||||
struct v2 point_local_e0;
|
|
||||||
struct v2 point_local_e1;
|
|
||||||
|
|
||||||
u32 id; /* ID generated during clipping */
|
|
||||||
f32 starting_separation; /* How far are original points along normal */
|
|
||||||
f32 normal_impulse; /* Accumulated impulse along normal */
|
|
||||||
f32 tangent_impulse; /* Accumulated impulse along tangent */
|
|
||||||
|
|
||||||
f32 inv_normal_mass;
|
|
||||||
f32 inv_tangent_mass;
|
|
||||||
|
|
||||||
/* Debugging */
|
|
||||||
struct v2 dbg_pt;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct contact_constraint {
|
struct entity_lookup_entry {
|
||||||
u64 last_updated_tick; /* To avoid checking collisions for the same constraint twice in one tick */
|
struct entity_lookup_key key;
|
||||||
b32 skip_solve;
|
struct entity_handle entity;
|
||||||
struct entity_handle e0;
|
struct entity_lookup_entry *next;
|
||||||
struct entity_handle e1;
|
struct entity_lookup_entry *prev;
|
||||||
f32 inv_m0;
|
|
||||||
f32 inv_m1;
|
|
||||||
f32 inv_i0;
|
|
||||||
f32 inv_i1;
|
|
||||||
|
|
||||||
struct v2 normal; /* Normal vector of collision from e0 -> e1 */
|
|
||||||
u64 last_iteration;
|
|
||||||
struct contact_point points[2];
|
|
||||||
u32 num_points;
|
|
||||||
|
|
||||||
f32 friction;
|
|
||||||
|
|
||||||
struct math_spring_result softness;
|
|
||||||
f32 pushout_velocity;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct collision_debug {
|
struct entity_lookup_bucket {
|
||||||
struct entity_handle e0;
|
struct entity_lookup_entry *first;
|
||||||
struct entity_handle e1;
|
struct entity_lookup_entry *last;
|
||||||
struct collider_collision_points_result res;
|
|
||||||
|
|
||||||
struct contact_point points[2];
|
|
||||||
u32 num_points;
|
|
||||||
|
|
||||||
struct v2 closest0;
|
|
||||||
struct v2 closest1;
|
|
||||||
|
|
||||||
struct xform xf0;
|
|
||||||
struct xform xf1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct entity_lookup {
|
||||||
|
struct arena arena;
|
||||||
|
struct entity_lookup_bucket *buckets;
|
||||||
|
u64 num_buckets;
|
||||||
|
struct entity_lookup_entry *first_free_entry;
|
||||||
struct motor_joint_def {
|
|
||||||
struct entity_handle e0;
|
|
||||||
struct entity_handle e1;
|
|
||||||
f32 correction_rate;
|
|
||||||
f32 max_force;
|
|
||||||
f32 max_torque;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct motor_joint {
|
|
||||||
struct entity_handle e0;
|
|
||||||
struct entity_handle e1;
|
|
||||||
f32 correction_rate;
|
|
||||||
f32 max_force;
|
|
||||||
f32 max_torque;
|
|
||||||
|
|
||||||
f32 inv_m0;
|
|
||||||
f32 inv_m1;
|
|
||||||
f32 inv_i0;
|
|
||||||
f32 inv_i1;
|
|
||||||
|
|
||||||
struct v2 linear_impulse;
|
|
||||||
f32 angular_impulse;
|
|
||||||
|
|
||||||
struct v2 point_local_e0;
|
|
||||||
struct v2 point_local_e1;
|
|
||||||
|
|
||||||
struct xform linear_mass_xf;
|
|
||||||
f32 angular_mass;
|
|
||||||
};
|
|
||||||
|
|
||||||
INLINE struct motor_joint motor_joint_from_def(struct motor_joint_def def)
|
|
||||||
{
|
|
||||||
struct motor_joint res = ZI;
|
|
||||||
res.e0 = def.e0;
|
|
||||||
res.e1 = def.e1;
|
|
||||||
res.correction_rate = clamp_f32(def.correction_rate, 0, 1);
|
|
||||||
res.max_force = def.max_force;
|
|
||||||
res.max_torque = def.max_torque;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct mouse_joint {
|
|
||||||
struct entity_handle target;
|
|
||||||
struct v2 point_local_start;
|
|
||||||
struct v2 point_local_end;
|
|
||||||
struct math_spring_result linear_softness;
|
|
||||||
struct math_spring_result angular_softness;
|
|
||||||
f32 max_force;
|
|
||||||
|
|
||||||
f32 inv_m;
|
|
||||||
f32 inv_i;
|
|
||||||
|
|
||||||
struct v2 linear_impulse;
|
|
||||||
f32 angular_impulse;
|
|
||||||
|
|
||||||
struct xform linear_mass_xf;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct hit_event {
|
|
||||||
struct entity_handle e0;
|
|
||||||
struct entity_handle e1;
|
|
||||||
struct v2 point;
|
|
||||||
struct v2 normal;
|
|
||||||
struct v2 vrel; /* Relative velocity */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct entity {
|
struct entity {
|
||||||
/* ====================================================================== */
|
/* ====================================================================== */
|
||||||
/* Metadata */
|
/* Metadata */
|
||||||
@ -229,50 +100,38 @@ struct entity {
|
|||||||
struct entity_handle first;
|
struct entity_handle first;
|
||||||
struct entity_handle last;
|
struct entity_handle last;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* TODO: Remove this (testing) */
|
|
||||||
i32 colliding;
|
|
||||||
struct collision_debug collision_debug_data;
|
|
||||||
|
|
||||||
|
|
||||||
/* ====================================================================== */
|
/* ====================================================================== */
|
||||||
/* Collider */
|
/* Collider */
|
||||||
|
|
||||||
struct collider_shape local_collider;
|
struct collider_shape local_collider;
|
||||||
|
|
||||||
|
#if COLLIDER_DEBUG
|
||||||
|
i32 colliding;
|
||||||
|
struct phys_collision_debug collision_debug_data;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* ====================================================================== */
|
/* ====================================================================== */
|
||||||
/* Contact constraint */
|
/* Contact constraint */
|
||||||
|
|
||||||
/* ENTITY_PROP_CONSTRAINT_CONTACT */
|
/* ENTITY_PROP_CONSTRAINT_CONTACT */
|
||||||
struct contact_constraint contact_constraint_data;
|
struct phys_contact_constraint contact_constraint_data;
|
||||||
|
|
||||||
/* ====================================================================== */
|
/* ====================================================================== */
|
||||||
/* Motor joint */
|
/* Motor joint */
|
||||||
|
|
||||||
/* ENTITY_PROP_MOTOR_JOINT */
|
/* ENTITY_PROP_MOTOR_JOINT */
|
||||||
struct motor_joint motor_joint_data;
|
struct phys_motor_joint motor_joint_data;
|
||||||
|
|
||||||
/* ====================================================================== */
|
/* ====================================================================== */
|
||||||
/* Mouse joint */
|
/* Mouse joint */
|
||||||
|
|
||||||
/* ENTITY_PROP_MOUSE_JOINT */
|
/* ENTITY_PROP_MOUSE_JOINT */
|
||||||
struct mouse_joint mouse_joint_data;
|
struct phys_mouse_joint mouse_joint_data;
|
||||||
|
|
||||||
/* ====================================================================== */
|
/* ====================================================================== */
|
||||||
/* Hit event */
|
/* Hit event */
|
||||||
|
|
||||||
struct hit_event hit_event;
|
struct phys_hit_event hit_event;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ====================================================================== */
|
/* ====================================================================== */
|
||||||
/* Activation */
|
/* Activation */
|
||||||
@ -503,4 +362,15 @@ struct entity *entity_find_first_match_all(struct entity_store *store, struct en
|
|||||||
void entity_link_parent(struct entity *parent, struct entity *child);
|
void entity_link_parent(struct entity *parent, struct entity *child);
|
||||||
void entity_unlink_parent(struct entity *ent);
|
void entity_unlink_parent(struct entity *ent);
|
||||||
|
|
||||||
|
/* Lookup */
|
||||||
|
struct entity_lookup entity_lookup_alloc(u64 num_buckets);
|
||||||
|
void entity_lookup_release(struct entity_lookup *l);
|
||||||
|
struct entity_lookup_entry *entity_lookup_get(struct entity_lookup *l, struct entity_lookup_key key);
|
||||||
|
void entity_lookup_set(struct entity_lookup *l, struct entity_lookup_key key, struct entity_handle handle);
|
||||||
|
void entity_lookup_remove(struct entity_lookup *l, struct entity_lookup_entry *entry);
|
||||||
|
struct entity_lookup_key entity_lookup_key_from_two_handles(struct entity_handle h0, struct entity_handle h1);
|
||||||
|
|
||||||
|
/* Activate */
|
||||||
|
void entity_activate(struct entity *ent, u64 current_tick_id);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
1457
src/game.c
1457
src/game.c
File diff suppressed because it is too large
Load Diff
@ -5,6 +5,7 @@ struct world;
|
|||||||
struct mixer_startup_receipt;
|
struct mixer_startup_receipt;
|
||||||
struct sprite_startup_receipt;
|
struct sprite_startup_receipt;
|
||||||
struct sound_startup_receipt;
|
struct sound_startup_receipt;
|
||||||
|
struct phys_startup_receipt;
|
||||||
|
|
||||||
enum game_cmd_state {
|
enum game_cmd_state {
|
||||||
GAME_CMD_STATE_STOP = -1,
|
GAME_CMD_STATE_STOP = -1,
|
||||||
@ -53,7 +54,8 @@ struct game_cmd_array {
|
|||||||
struct game_startup_receipt { i32 _; };
|
struct game_startup_receipt { i32 _; };
|
||||||
struct game_startup_receipt game_startup(struct mixer_startup_receipt *mixer_sr,
|
struct game_startup_receipt game_startup(struct mixer_startup_receipt *mixer_sr,
|
||||||
struct sprite_startup_receipt *sheet_sr,
|
struct sprite_startup_receipt *sheet_sr,
|
||||||
struct sound_startup_receipt *sound_sr);
|
struct sound_startup_receipt *sound_sr,
|
||||||
|
struct phys_startup_receipt *phys_sr);
|
||||||
|
|
||||||
void game_get_latest_tick(struct world *dest);
|
void game_get_latest_tick(struct world *dest);
|
||||||
u64 game_get_latest_tick_id(void);
|
u64 game_get_latest_tick_id(void);
|
||||||
|
|||||||
1134
src/phys.c
Normal file
1134
src/phys.c
Normal file
File diff suppressed because it is too large
Load Diff
171
src/phys.h
Normal file
171
src/phys.h
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
#ifndef PHYS_H
|
||||||
|
#define PHYS_H
|
||||||
|
|
||||||
|
#include "collider.h"
|
||||||
|
#include "math.h"
|
||||||
|
|
||||||
|
struct entity_store;
|
||||||
|
struct entity_lookup;
|
||||||
|
|
||||||
|
struct phys_hit_event {
|
||||||
|
struct entity_handle e0;
|
||||||
|
struct entity_handle e1;
|
||||||
|
struct v2 point;
|
||||||
|
struct v2 normal;
|
||||||
|
struct v2 vrel; /* Relative velocity */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Startup
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
struct phys_startup_receipt { i32 _; };
|
||||||
|
struct phys_startup_receipt phys_startup(void);
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Contact
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
struct phys_contact_point {
|
||||||
|
/* Contact point in local space of each entity */
|
||||||
|
struct v2 point_local_e0;
|
||||||
|
struct v2 point_local_e1;
|
||||||
|
|
||||||
|
u32 id; /* ID generated during clipping */
|
||||||
|
f32 starting_separation; /* How far are original points along normal */
|
||||||
|
f32 normal_impulse; /* Accumulated impulse along normal */
|
||||||
|
f32 tangent_impulse; /* Accumulated impulse along tangent */
|
||||||
|
|
||||||
|
f32 inv_normal_mass;
|
||||||
|
f32 inv_tangent_mass;
|
||||||
|
|
||||||
|
/* Debugging */
|
||||||
|
struct v2 dbg_pt;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct phys_contact_constraint {
|
||||||
|
u64 last_updated_tick; /* To avoid checking collisions for the same constraint twice in one tick */
|
||||||
|
b32 skip_solve;
|
||||||
|
struct entity_handle e0;
|
||||||
|
struct entity_handle e1;
|
||||||
|
f32 inv_m0;
|
||||||
|
f32 inv_m1;
|
||||||
|
f32 inv_i0;
|
||||||
|
f32 inv_i1;
|
||||||
|
|
||||||
|
struct v2 normal; /* Normal vector of collision from e0 -> e1 */
|
||||||
|
u64 last_iteration;
|
||||||
|
struct phys_contact_point points[2];
|
||||||
|
u32 num_points;
|
||||||
|
|
||||||
|
f32 friction;
|
||||||
|
|
||||||
|
struct math_spring_result softness;
|
||||||
|
f32 pushout_velocity;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct phys_collision_debug {
|
||||||
|
struct entity_handle e0;
|
||||||
|
struct entity_handle e1;
|
||||||
|
struct collider_collision_points_result res;
|
||||||
|
|
||||||
|
struct phys_contact_point points[2];
|
||||||
|
u32 num_points;
|
||||||
|
|
||||||
|
struct v2 closest0;
|
||||||
|
struct v2 closest1;
|
||||||
|
|
||||||
|
struct xform xf0;
|
||||||
|
struct xform xf1;
|
||||||
|
};
|
||||||
|
|
||||||
|
void phys_create_contacts(struct entity_store *store, struct entity_lookup *contact_lookup, struct entity_lookup *debug_lookup, u64 tick_id);
|
||||||
|
void phys_prepare_contacts(struct entity_store *store, struct entity_lookup *contact_lookup, struct entity_lookup *debug_lookup);
|
||||||
|
void phys_warm_start_contacts(struct entity_store *store);
|
||||||
|
void phys_solve_contacts(struct entity_store *store, f32 dt, b32 apply_bias);
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Motor joint
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
struct phys_motor_joint_def {
|
||||||
|
struct entity_handle e0;
|
||||||
|
struct entity_handle e1;
|
||||||
|
f32 correction_rate;
|
||||||
|
f32 max_force;
|
||||||
|
f32 max_torque;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct phys_motor_joint {
|
||||||
|
struct entity_handle e0;
|
||||||
|
struct entity_handle e1;
|
||||||
|
f32 correction_rate;
|
||||||
|
f32 max_force;
|
||||||
|
f32 max_torque;
|
||||||
|
|
||||||
|
f32 inv_m0;
|
||||||
|
f32 inv_m1;
|
||||||
|
f32 inv_i0;
|
||||||
|
f32 inv_i1;
|
||||||
|
|
||||||
|
struct v2 linear_impulse;
|
||||||
|
f32 angular_impulse;
|
||||||
|
|
||||||
|
struct v2 point_local_e0;
|
||||||
|
struct v2 point_local_e1;
|
||||||
|
|
||||||
|
struct xform linear_mass_xf;
|
||||||
|
f32 angular_mass;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct phys_motor_joint motor_joint_from_def(struct phys_motor_joint_def def);
|
||||||
|
void phys_prepare_motor_joints(struct entity_store *store);
|
||||||
|
void phys_warm_start_motor_joints(struct entity_store *store);
|
||||||
|
void phys_solve_motor_joints(struct entity_store *store, f32 dt);
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Mouse joint
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
struct phys_mouse_joint {
|
||||||
|
struct entity_handle target;
|
||||||
|
struct v2 point_local_start;
|
||||||
|
struct v2 point_local_end;
|
||||||
|
struct math_spring_result linear_softness;
|
||||||
|
struct math_spring_result angular_softness;
|
||||||
|
f32 max_force;
|
||||||
|
|
||||||
|
f32 inv_m;
|
||||||
|
f32 inv_i;
|
||||||
|
|
||||||
|
struct v2 linear_impulse;
|
||||||
|
f32 angular_impulse;
|
||||||
|
|
||||||
|
struct xform linear_mass_xf;
|
||||||
|
};
|
||||||
|
|
||||||
|
void phys_create_mouse_joints(struct entity_store *store, struct v2 cursor, b32 start_dragging, b32 stop_dragging);
|
||||||
|
void phys_prepare_mouse_joints(struct entity_store *store);
|
||||||
|
void phys_warm_start_mouse_joints(struct entity_store *store);
|
||||||
|
void phys_solve_mouse_joints(struct entity_store *store, f32 dt);
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Earliest time of impact
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
f32 phys_determine_earliest_toi_for_bullets(struct entity_store *store, f32 step_dt, f32 tolerance, u32 max_iterations);
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Integration
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
void phys_integrate_forces(struct entity_store *store, f32 dt);
|
||||||
|
void phys_integrate_velocities(struct entity_store *store, f32 dt);
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Step
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
void phys_step(struct entity_store *store, f32 step_dt, struct entity_lookup *contact_lookup, struct entity_lookup *collision_debug_lookup, u64 tick_id, struct v2 dbg_cursor_pos, b32 dbg_start_dragging, b32 dbg_stop_dragging);
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1072,11 +1072,11 @@ INTERNAL void user_update(void)
|
|||||||
/* Draw constraint */
|
/* Draw constraint */
|
||||||
#if 1
|
#if 1
|
||||||
if (entity_has_prop(ent, ENTITY_PROP_COLLISION_DEBUG)) {
|
if (entity_has_prop(ent, ENTITY_PROP_COLLISION_DEBUG)) {
|
||||||
struct collision_debug *data = &ent->collision_debug_data;
|
struct phys_collision_debug *data = &ent->collision_debug_data;
|
||||||
struct collider_collision_points_result collider_res = data->res;
|
struct collider_collision_points_result collider_res = data->res;
|
||||||
|
|
||||||
//struct contact_constraint *data = &entity_from_handle(store, data->contact_constraint_ent)->contact_constraint_data;
|
//struct phys_contact_constraint *data = &entity_from_handle(store, data->contact_constraint_ent)->contact_constraint_data;
|
||||||
//struct contact_constraint *data = &data->contact_constraint_data;
|
//struct phys_contact_constraint *data = &data->contact_constraint_data;
|
||||||
struct entity *e0 = entity_from_handle(store, data->e0);
|
struct entity *e0 = entity_from_handle(store, data->e0);
|
||||||
struct entity *e1 = entity_from_handle(store, data->e1);
|
struct entity *e1 = entity_from_handle(store, data->e1);
|
||||||
struct collider_shape e0_collider = e0->local_collider;
|
struct collider_shape e0_collider = e0->local_collider;
|
||||||
@ -1216,7 +1216,7 @@ INTERNAL void user_update(void)
|
|||||||
{
|
{
|
||||||
f32 radius = 5;
|
f32 radius = 5;
|
||||||
for (u32 i = 0; i < data->num_points; ++i) {
|
for (u32 i = 0; i < data->num_points; ++i) {
|
||||||
struct contact_point point = data->points[i];
|
struct phys_contact_point point = data->points[i];
|
||||||
#if 0
|
#if 0
|
||||||
struct v2 p0 = xform_mul_v2(e0_xf, contact.point_local_e0);
|
struct v2 p0 = xform_mul_v2(e0_xf, contact.point_local_e0);
|
||||||
struct v2 p1 = xform_mul_v2(e1_xf, contact.point_local_e1);
|
struct v2 p1 = xform_mul_v2(e1_xf, contact.point_local_e1);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user