cleanup collision debug leak & merge structure with contact lookup into entity lookup
This commit is contained in:
parent
6268e012f6
commit
02290601c3
@ -35,6 +35,7 @@
|
|||||||
#define GAME_PHYSICS_SUBSTEPS 4
|
#define GAME_PHYSICS_SUBSTEPS 4
|
||||||
#define GAME_PHYSICS_ENABLE_WARM_STARTING 1
|
#define GAME_PHYSICS_ENABLE_WARM_STARTING 1
|
||||||
#define GAME_PHYSICS_ENABLE_RELAXATION 1
|
#define GAME_PHYSICS_ENABLE_RELAXATION 1
|
||||||
|
#define GAME_PHYSICS_ENABLE_TOI 1
|
||||||
|
|
||||||
#define USER_DRAW_MENKOWSKI 0
|
#define USER_DRAW_MENKOWSKI 0
|
||||||
#define GAME_PHYSICS_ENABLE_COLLISION 1
|
#define GAME_PHYSICS_ENABLE_COLLISION 1
|
||||||
|
|||||||
224
src/game.c
224
src/game.c
@ -12,32 +12,29 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "collider.h"
|
#include "collider.h"
|
||||||
|
|
||||||
struct contact_lookup_entry {
|
struct entity_lookup_key {
|
||||||
u64 hash;
|
u64 hash;
|
||||||
struct entity_handle contact_ent_handle;
|
|
||||||
struct contact_lookup_entry *next;
|
|
||||||
struct contact_lookup_entry *prev;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct contact_lookup_bucket {
|
struct entity_lookup_entry {
|
||||||
struct contact_lookup_entry *first;
|
struct entity_lookup_key key;
|
||||||
struct contact_lookup_entry *last;
|
struct entity_handle entity;
|
||||||
|
struct entity_lookup_entry *next;
|
||||||
|
struct entity_lookup_entry *prev;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct contact_lookup {
|
struct entity_lookup_bucket {
|
||||||
|
struct entity_lookup_entry *first;
|
||||||
|
struct entity_lookup_entry *last;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct entity_lookup {
|
||||||
struct arena arena;
|
struct arena arena;
|
||||||
struct contact_lookup_bucket buckets[4096];
|
struct entity_lookup_bucket *buckets;
|
||||||
struct contact_lookup_entry *first_free_entry;
|
u64 num_buckets;
|
||||||
|
struct entity_lookup_entry *first_free_entry;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if COLLIDER_DEBUG
|
|
||||||
/* TODO: Remove this (debugging) */
|
|
||||||
struct collision_debug_lookup {
|
|
||||||
struct arena arena;
|
|
||||||
struct fixed_dict dict;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GLOBAL struct {
|
GLOBAL struct {
|
||||||
struct atomic_i32 game_thread_shutdown;
|
struct atomic_i32 game_thread_shutdown;
|
||||||
struct sys_thread game_thread;
|
struct sys_thread game_thread;
|
||||||
@ -64,9 +61,9 @@ GLOBAL struct {
|
|||||||
f32 mouse_joint_max_force;
|
f32 mouse_joint_max_force;
|
||||||
|
|
||||||
/* Bookkeeping structures */
|
/* Bookkeeping structures */
|
||||||
struct contact_lookup contact_lookup;
|
struct entity_lookup contact_lookup;
|
||||||
#if COLLIDER_DEBUG
|
#if COLLIDER_DEBUG
|
||||||
struct collision_debug_lookup collision_debug_lookup;
|
struct entity_lookup collision_debug_lookup;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Ticks */
|
/* Ticks */
|
||||||
@ -176,36 +173,31 @@ INTERNAL void activate_now(struct entity *ent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Contact lookup
|
* Entity lookup
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
INTERNAL void contact_lookup_alloc(struct contact_lookup *l)
|
INTERNAL struct entity_lookup entity_lookup_alloc(u64 num_buckets)
|
||||||
{
|
{
|
||||||
MEMZERO_STRUCT(l);
|
ASSERT(num_buckets > 0);
|
||||||
l->arena = arena_alloc(GIGABYTE(64));
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void contact_lookup_release(struct contact_lookup *l)
|
INTERNAL void entity_lookup_release(struct entity_lookup *l)
|
||||||
{
|
{
|
||||||
arena_release(&l->arena);
|
arena_release(&l->arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL u64 contact_lookup_hash_from_entities(struct entity_handle h0, struct entity_handle h1)
|
INTERNAL struct entity_lookup_entry *entity_lookup_get(struct entity_lookup *l, struct entity_lookup_key key)
|
||||||
{
|
{
|
||||||
struct buffer b0 = BUFFER_FROM_STRUCT(&h0);
|
u64 index = key.hash % l->num_buckets;
|
||||||
struct buffer b1 = BUFFER_FROM_STRUCT(&h1);
|
struct entity_lookup_bucket *bucket = &l->buckets[index];
|
||||||
u64 hash = hash_fnv64(HASH_FNV64_BASIS, b0);
|
struct entity_lookup_entry *res = NULL;
|
||||||
hash = hash_fnv64(hash, b1);
|
for (struct entity_lookup_entry *e = bucket->first; e; e = e->next) {
|
||||||
return hash;
|
if (e->key.hash == key.hash) {
|
||||||
}
|
|
||||||
|
|
||||||
INTERNAL struct contact_lookup_entry *contact_lookup_get(struct contact_lookup *l, u64 hash)
|
|
||||||
{
|
|
||||||
u64 index = hash % ARRAY_COUNT(l->buckets);
|
|
||||||
struct contact_lookup_bucket *bucket = &l->buckets[index];
|
|
||||||
struct contact_lookup_entry *res = NULL;
|
|
||||||
for (struct contact_lookup_entry *e = bucket->first; e; e = e->next) {
|
|
||||||
if (e->hash == hash) {
|
|
||||||
res = e;
|
res = e;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -213,25 +205,25 @@ INTERNAL struct contact_lookup_entry *contact_lookup_get(struct contact_lookup *
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void contact_lookup_set(struct contact_lookup *l, u64 hash, struct entity_handle handle)
|
INTERNAL void entity_lookup_set(struct entity_lookup *l, struct entity_lookup_key key, struct entity_handle handle)
|
||||||
{
|
{
|
||||||
u64 index = hash % ARRAY_COUNT(l->buckets);
|
u64 index = key.hash % l->num_buckets;
|
||||||
struct contact_lookup_bucket *bucket = &l->buckets[index];
|
struct entity_lookup_bucket *bucket = &l->buckets[index];
|
||||||
|
|
||||||
struct contact_lookup_entry *prev = NULL;
|
struct entity_lookup_entry *prev = NULL;
|
||||||
struct contact_lookup_entry **slot = &bucket->first;
|
struct entity_lookup_entry **slot = &bucket->first;
|
||||||
while (*slot) {
|
while (*slot) {
|
||||||
if ((*slot)->hash == hash) {
|
if ((*slot)->key.hash == key.hash) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
prev = *slot;
|
prev = *slot;
|
||||||
slot = &(*slot)->next;
|
slot = &(*slot)->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct contact_lookup_entry *entry = *slot;
|
struct entity_lookup_entry *entry = *slot;
|
||||||
if (entry) {
|
if (entry) {
|
||||||
/* Set existing entry */
|
/* Set existing entry */
|
||||||
entry->contact_ent_handle = handle;
|
entry->entity = handle;
|
||||||
} else {
|
} else {
|
||||||
/* Allocate entry */
|
/* Allocate entry */
|
||||||
if (l->first_free_entry) {
|
if (l->first_free_entry) {
|
||||||
@ -239,12 +231,12 @@ INTERNAL void contact_lookup_set(struct contact_lookup *l, u64 hash, struct enti
|
|||||||
l->first_free_entry->prev = NULL;
|
l->first_free_entry->prev = NULL;
|
||||||
l->first_free_entry = entry->next;
|
l->first_free_entry = entry->next;
|
||||||
} else {
|
} else {
|
||||||
entry = arena_push(&l->arena, struct contact_lookup_entry);
|
entry = arena_push(&l->arena, struct entity_lookup_entry);
|
||||||
}
|
}
|
||||||
MEMZERO_STRUCT(entry);
|
MEMZERO_STRUCT(entry);
|
||||||
|
|
||||||
entry->hash = hash;
|
entry->key = key;
|
||||||
entry->contact_ent_handle = handle;
|
entry->entity = handle;
|
||||||
if (prev) {
|
if (prev) {
|
||||||
entry->prev = prev;
|
entry->prev = prev;
|
||||||
prev->next = entry;
|
prev->next = entry;
|
||||||
@ -255,11 +247,11 @@ INTERNAL void contact_lookup_set(struct contact_lookup *l, u64 hash, struct enti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void contact_lookup_remove(struct contact_lookup *l, struct contact_lookup_entry *entry)
|
INTERNAL void entity_lookup_remove(struct entity_lookup *l, struct entity_lookup_entry *entry)
|
||||||
{
|
{
|
||||||
struct contact_lookup_bucket *bucket = &l->buckets[entry->hash % ARRAY_COUNT(l->buckets)];
|
struct entity_lookup_bucket *bucket = &l->buckets[entry->key.hash % l->num_buckets];
|
||||||
struct contact_lookup_entry *prev = entry->prev;
|
struct entity_lookup_entry *prev = entry->prev;
|
||||||
struct contact_lookup_entry *next = entry->next;
|
struct entity_lookup_entry *next = entry->next;
|
||||||
|
|
||||||
if (prev) {
|
if (prev) {
|
||||||
prev->next = next;
|
prev->next = next;
|
||||||
@ -281,6 +273,16 @@ INTERNAL void contact_lookup_remove(struct contact_lookup *l, struct contact_loo
|
|||||||
l->first_free_entry = entry;
|
l->first_free_entry = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INTERNAL 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;
|
||||||
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Reset
|
* Reset
|
||||||
* ========================== */
|
* ========================== */
|
||||||
@ -291,17 +293,14 @@ INTERNAL void reset_world(void)
|
|||||||
/* Release world */
|
/* Release world */
|
||||||
world_release(&G.tick);
|
world_release(&G.tick);
|
||||||
/* Release bookkeeping */
|
/* Release bookkeeping */
|
||||||
#if COLLIDER_DEBUG
|
entity_lookup_release(&G.collision_debug_lookup);
|
||||||
arena_release(&G.collision_debug_lookup.arena);
|
entity_lookup_release(&G.contact_lookup);
|
||||||
#endif
|
|
||||||
contact_lookup_release(&G.contact_lookup);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create bookkeeping */
|
/* Create bookkeeping */
|
||||||
contact_lookup_alloc(&G.contact_lookup);
|
G.contact_lookup = entity_lookup_alloc(4096);
|
||||||
#if COLLIDER_DEBUG
|
#if COLLIDER_DEBUG
|
||||||
G.collision_debug_lookup.arena = arena_alloc(GIGABYTE(64));
|
G.collision_debug_lookup = entity_lookup_alloc(4096);
|
||||||
G.collision_debug_lookup.dict = fixed_dict_init(&G.collision_debug_lookup.arena, 4096);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Re-create world */
|
/* Re-create world */
|
||||||
@ -507,12 +506,12 @@ INTERNAL void create_contacts(void)
|
|||||||
e1_collider = check0_collider;
|
e1_collider = check0_collider;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 lookup_hash = contact_lookup_hash_from_entities(e0->handle, e1->handle);
|
struct entity_lookup_key key = entity_lookup_key_from_two_handles(e0->handle, e1->handle);
|
||||||
struct contact_lookup_entry *entry = contact_lookup_get(&G.contact_lookup, lookup_hash);
|
struct entity_lookup_entry *entry = entity_lookup_get(&G.contact_lookup, key);
|
||||||
|
|
||||||
struct entity *constraint_ent = entity_nil();
|
struct entity *constraint_ent = entity_nil();
|
||||||
if (entry) {
|
if (entry) {
|
||||||
constraint_ent = entity_from_handle(store, entry->contact_ent_handle);
|
constraint_ent = entity_from_handle(store, entry->entity);
|
||||||
if (entity_is_valid_and_active(constraint_ent)) {
|
if (entity_is_valid_and_active(constraint_ent)) {
|
||||||
if (constraint_ent->contact_constraint_data.last_iteration >= G.tick.tick_id) {
|
if (constraint_ent->contact_constraint_data.last_iteration >= G.tick.tick_id) {
|
||||||
/* Already processed constraint this iteration */
|
/* Already processed constraint this iteration */
|
||||||
@ -522,7 +521,7 @@ INTERNAL void create_contacts(void)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Constraint ent no longer valid, delete entry */
|
/* Constraint ent no longer valid, delete entry */
|
||||||
contact_lookup_remove(&G.contact_lookup, entry);
|
entity_lookup_remove(&G.contact_lookup, entry);
|
||||||
entry = NULL;
|
entry = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -583,7 +582,7 @@ INTERNAL void create_contacts(void)
|
|||||||
entity_enable_prop(constraint_ent, ENTITY_PROP_CONTACT_CONSTRAINT);
|
entity_enable_prop(constraint_ent, ENTITY_PROP_CONTACT_CONSTRAINT);
|
||||||
activate_now(constraint_ent);
|
activate_now(constraint_ent);
|
||||||
ASSERT(!entry); /* Existing entry should never be present here */
|
ASSERT(!entry); /* Existing entry should never be present here */
|
||||||
contact_lookup_set(&G.contact_lookup, lookup_hash, constraint_ent->handle);
|
entity_lookup_set(&G.contact_lookup, key, constraint_ent->handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
constraint = &constraint_ent->contact_constraint_data;
|
constraint = &constraint_ent->contact_constraint_data;
|
||||||
@ -648,21 +647,17 @@ INTERNAL void create_contacts(void)
|
|||||||
/* TODO: Remove this (debugging) */
|
/* TODO: Remove this (debugging) */
|
||||||
#if COLLIDER_DEBUG
|
#if COLLIDER_DEBUG
|
||||||
{
|
{
|
||||||
struct string fdkey = STRING_FROM_BUFFER(BUFFER_FROM_STRUCT(&lookup_hash));
|
struct entity *dbg_ent = entity_nil();
|
||||||
struct entity_handle *dbg_ent_handle = fixed_dict_get(&G.collision_debug_lookup.dict, fdkey);
|
struct entity_lookup_entry *dbg_entry = entity_lookup_get(&G.collision_debug_lookup, key);
|
||||||
if (!dbg_ent_handle) {
|
if (dbg_entry) {
|
||||||
/* FIXME: Handle never released */
|
dbg_ent = entity_from_handle(store, dbg_entry->entity);
|
||||||
dbg_ent_handle = arena_push_zero(&G.collision_debug_lookup.arena, struct entity_handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct entity *dbg_ent = entity_from_handle(store, *dbg_ent_handle);
|
|
||||||
|
|
||||||
if (!dbg_ent->valid) {
|
if (!dbg_ent->valid) {
|
||||||
/* FIXME: Entity never released */
|
/* FIXME: Entity never released */
|
||||||
dbg_ent = entity_alloc(root);
|
dbg_ent = entity_alloc(root);
|
||||||
entity_enable_prop(dbg_ent, ENTITY_PROP_COLLISION_DEBUG);
|
entity_enable_prop(dbg_ent, ENTITY_PROP_COLLISION_DEBUG);
|
||||||
*dbg_ent_handle = dbg_ent->handle;
|
entity_lookup_set(&G.collision_debug_lookup, key, dbg_ent->handle);
|
||||||
fixed_dict_set(&G.collision_debug_lookup.arena, &G.collision_debug_lookup.dict, fdkey, dbg_ent_handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct collision_debug *dbg = &dbg_ent->collision_debug_data;
|
struct collision_debug *dbg = &dbg_ent->collision_debug_data;
|
||||||
@ -785,15 +780,53 @@ INTERNAL void prepare_contacts(void)
|
|||||||
entity_disable_prop(constraint_ent, ENTITY_PROP_ACTIVE);
|
entity_disable_prop(constraint_ent, ENTITY_PROP_ACTIVE);
|
||||||
entity_enable_prop(constraint_ent, ENTITY_PROP_RELEASE_AT_END_OF_FRAME);
|
entity_enable_prop(constraint_ent, ENTITY_PROP_RELEASE_AT_END_OF_FRAME);
|
||||||
/* Remove from lookup */
|
/* Remove from lookup */
|
||||||
u64 hash = contact_lookup_hash_from_entities(constraint->e0, constraint->e1);
|
struct entity_lookup_key key = entity_lookup_key_from_two_handles(constraint->e0, constraint->e1);
|
||||||
struct contact_lookup_entry *entry = contact_lookup_get(&G.contact_lookup, hash);
|
struct entity_lookup_entry *entry = entity_lookup_get(&G.contact_lookup, key);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
contact_lookup_remove(&G.contact_lookup, entry);
|
entity_lookup_remove(&G.contact_lookup, entry);
|
||||||
} else {
|
} else {
|
||||||
ASSERT(false); /* This should always exist */
|
ASSERT(false); /* This should always exist */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if COLLIDER_DEBUG
|
||||||
|
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
|
||||||
|
struct entity *dbg_ent = &store->entities[entity_index];
|
||||||
|
if (!entity_is_valid_and_active(dbg_ent)) continue;
|
||||||
|
if (!entity_has_prop(dbg_ent, ENTITY_PROP_COLLISION_DEBUG)) continue;
|
||||||
|
|
||||||
|
struct collision_debug *dbg = &dbg_ent->collision_debug_data;
|
||||||
|
struct entity *e0 = entity_from_handle(store, dbg->e0);
|
||||||
|
struct entity *e1 = entity_from_handle(store, dbg->e1);
|
||||||
|
|
||||||
|
|
||||||
|
if (!entity_is_valid_and_active(e0) || !entity_is_valid_and_active(e1)
|
||||||
|
|| !(entity_has_prop(e0, ENTITY_PROP_PHYSICAL_DYNAMIC) || entity_has_prop(e0, ENTITY_PROP_PHYSICAL_KINEMATIC))
|
||||||
|
|| !(entity_has_prop(e1, ENTITY_PROP_PHYSICAL_DYNAMIC) || entity_has_prop(e1, ENTITY_PROP_PHYSICAL_KINEMATIC))) {
|
||||||
|
/* Mark dbg ent for removal */
|
||||||
|
entity_disable_prop(dbg_ent, ENTITY_PROP_ACTIVE);
|
||||||
|
entity_enable_prop(dbg_ent, ENTITY_PROP_RELEASE_AT_END_OF_FRAME);
|
||||||
|
|
||||||
|
/* Remove from lookup */
|
||||||
|
struct entity_lookup_key key = entity_lookup_key_from_two_handles(dbg->e0, dbg->e1);
|
||||||
|
struct entity_lookup_entry *entry = entity_lookup_get(&G.collision_debug_lookup, key);
|
||||||
|
|
||||||
|
if (e0->valid) {
|
||||||
|
--e0->colliding;
|
||||||
|
}
|
||||||
|
if (e1->valid) {
|
||||||
|
--e0->colliding;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry) {
|
||||||
|
entity_lookup_remove(&G.collision_debug_lookup, entry);
|
||||||
|
} else {
|
||||||
|
ASSERT(false); /* This should always exist */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void warm_start_contacts(void)
|
INTERNAL void warm_start_contacts(void)
|
||||||
@ -1563,7 +1596,6 @@ INTERNAL f32 determine_earliest_toi(f32 dt, f32 tolerance, u32 max_iterations)
|
|||||||
struct entity_store *store = G.tick.entity_store;
|
struct entity_store *store = G.tick.entity_store;
|
||||||
//struct entity *root = G.root;
|
//struct entity *root = G.root;
|
||||||
|
|
||||||
|
|
||||||
for (u64 e0_index = 0; e0_index < store->reserved; ++e0_index) {
|
for (u64 e0_index = 0; e0_index < store->reserved; ++e0_index) {
|
||||||
struct entity *e0 = &store->entities[e0_index];
|
struct entity *e0 = &store->entities[e0_index];
|
||||||
if (!entity_is_valid_and_active(e0)) continue;
|
if (!entity_is_valid_and_active(e0)) continue;
|
||||||
@ -1583,7 +1615,6 @@ INTERNAL f32 determine_earliest_toi(f32 dt, f32 tolerance, u32 max_iterations)
|
|||||||
e0_xf_t1 = xform_basis_rotated_world(e0_xf_t1, tick_angular_velocity);
|
e0_xf_t1 = xform_basis_rotated_world(e0_xf_t1, tick_angular_velocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Start e1 index at e0 index + 1 to prevent redundant checks */
|
/* Start e1 index at e0 index + 1 to prevent redundant checks */
|
||||||
for (u64 e1_index = e0_index + 1; e1_index < store->reserved; ++e1_index) {
|
for (u64 e1_index = e0_index + 1; e1_index < store->reserved; ++e1_index) {
|
||||||
struct entity *e1 = &store->entities[e1_index];
|
struct entity *e1 = &store->entities[e1_index];
|
||||||
@ -1609,7 +1640,6 @@ INTERNAL f32 determine_earliest_toi(f32 dt, f32 tolerance, u32 max_iterations)
|
|||||||
if (t != 0 && t < smallest_t) {
|
if (t != 0 && t < smallest_t) {
|
||||||
smallest_t = t;
|
smallest_t = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1617,24 +1647,6 @@ INTERNAL f32 determine_earliest_toi(f32 dt, f32 tolerance, u32 max_iterations)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Update
|
* Update
|
||||||
@ -2254,11 +2266,21 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
|
|||||||
f32 remaining_dt = dt;
|
f32 remaining_dt = dt;
|
||||||
integrate_velocities_from_forces(dt);
|
integrate_velocities_from_forces(dt);
|
||||||
while (remaining_dt > 0) {
|
while (remaining_dt > 0) {
|
||||||
|
f32 earliest_toi = 1;
|
||||||
|
{
|
||||||
|
#if GAME_PHYSICS_ENABLE_TOI
|
||||||
const f32 min_toi = 0.000001f;
|
const f32 min_toi = 0.000001f;
|
||||||
const f32 tolerance = 0.00001f;
|
const f32 tolerance = 0.00001f;
|
||||||
const u32 max_iterations = 128;
|
const u32 max_iterations = 128;
|
||||||
f32 earliest_toi = max_f32(determine_earliest_toi(remaining_dt, tolerance, max_iterations), min_toi);
|
earliest_toi = max_f32(determine_earliest_toi(remaining_dt, tolerance, max_iterations), min_toi);
|
||||||
|
#else
|
||||||
|
(UNUSED)toi;
|
||||||
|
(UNUSED)determine_earliest_toi;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
f32 step_dt = remaining_dt * earliest_toi;
|
f32 step_dt = remaining_dt * earliest_toi;
|
||||||
|
|
||||||
create_contacts();
|
create_contacts();
|
||||||
create_mouse_joints(game_cmds);
|
create_mouse_joints(game_cmds);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user