pp refactor progress

This commit is contained in:
jacob 2025-08-05 16:50:47 -05:00
parent eabefaa16d
commit c649867ef4
7 changed files with 1240 additions and 637 deletions

View File

@ -7,11 +7,14 @@ Entity *AcquireRaw(Snapshot *ss, Entity *parent, EntityId id)
Assert(ss->valid); Assert(ss->valid);
Assert(ss == parent->ss); Assert(ss == parent->ss);
Entity *ent; Entity *ent;
if (ss->first_free_ent > 0 && ss->first_free_ent < ss->num_ents_reserved) { if (ss->first_free_ent > 0 && ss->first_free_ent < ss->num_ents_reserved)
{
/* Reuse from free list */ /* Reuse from free list */
ent = &ss->ents[ss->first_free_ent]; ent = &ss->ents[ss->first_free_ent];
ss->first_free_ent = ent->next_free; ss->first_free_ent = ent->next_free;
} else { }
else
{
/* Make new */ /* Make new */
ent = PushStructNoZero(ss->ents_arena, Entity); ent = PushStructNoZero(ss->ents_arena, Entity);
++ss->num_ents_reserved; ++ss->num_ents_reserved;
@ -83,7 +86,8 @@ void ReleaseRaw(Entity *ent)
Snapshot *ss = ent->ss; Snapshot *ss = ent->ss;
/* Release children */ /* Release children */
Entity *child = EntityFromId(ss, ent->first); Entity *child = EntityFromId(ss, ent->first);
while (child->valid) { while (child->valid)
{
Entity *next = EntityFromId(ss, child->next); Entity *next = EntityFromId(ss, child->next);
ReleaseRaw(child); ReleaseRaw(child);
child = next; child = next;
@ -103,7 +107,8 @@ void Release(Entity *ent)
{ {
Snapshot *ss = ent->ss; Snapshot *ss = ent->ss;
Entity *parent = EntityFromId(ss, ent->parent); Entity *parent = EntityFromId(ss, ent->parent);
if (parent->valid) { if (parent->valid)
{
Unlink(ent); Unlink(ent);
} }
ReleaseRaw(ent); ReleaseRaw(ent);
@ -115,9 +120,11 @@ void ReleaseAllWithProp(Snapshot *ss, Prop prop)
Entity **ents_to_release = PushDry(scratch.arena, Entity *); Entity **ents_to_release = PushDry(scratch.arena, Entity *);
u64 ents_to_release_count = 0; u64 ents_to_release_count = 0;
for (u64 ent_index = 0; ent_index < ss->num_ents_reserved; ++ent_index) { for (u64 ent_index = 0; ent_index < ss->num_ents_reserved; ++ent_index)
{
Entity *ent = &ss->ents[ent_index]; Entity *ent = &ss->ents[ent_index];
if (ent->valid && HasProp(ent, prop)) { if (ent->valid && HasProp(ent, prop))
{
*PushStructNoZero(scratch.arena, Entity *) = ent; *PushStructNoZero(scratch.arena, Entity *) = ent;
++ents_to_release_count; ++ents_to_release_count;
} }
@ -126,9 +133,11 @@ void ReleaseAllWithProp(Snapshot *ss, Prop prop)
/* Release from snapshot */ /* Release from snapshot */
/* TODO: Breadth first iteration to only release parent entities (since /* TODO: Breadth first iteration to only release parent entities (since
* child entities will be released along with parent anyway) */ * child entities will be released along with parent anyway) */
for (u64 i = 0; i < ents_to_release_count; ++i) { for (u64 i = 0; i < ents_to_release_count; ++i)
{
Entity *ent = ents_to_release[i]; Entity *ent = ents_to_release[i];
if (ent->valid && !ent->is_root && !HasProp(ent, Prop_Cmd) && !HasProp(ent, Prop_Player)) { if (ent->valid && !ent->is_root && !HasProp(ent, Prop_Cmd) && !HasProp(ent, Prop_Player))
{
Release(ent); Release(ent);
} }
} }
@ -156,9 +165,12 @@ u32 IndexFromEntity(Snapshot *ss, Entity *ent)
Entity *EntityFromIndex(Snapshot *ss, u32 index) Entity *EntityFromIndex(Snapshot *ss, u32 index)
{ {
if (index > 0 && index < ss->num_ents_reserved) { if (index > 0 && index < ss->num_ents_reserved)
{
return &ss->ents[index]; return &ss->ents[index];
} else { }
else
{
return NilEntity(); return NilEntity();
} }
} }
@ -173,9 +185,11 @@ void SetEntityId(Entity *ent, EntityId id)
{ {
Snapshot *ss = ent->ss; Snapshot *ss = ent->ss;
EntityId old_id = ent->id; EntityId old_id = ent->id;
if (!EqId(old_id, id)) { if (!EqId(old_id, id))
{
/* Release old from lookup */ /* Release old from lookup */
if (!IsNilId(old_id)) { if (!IsNilId(old_id))
{
EntBin *bin = BinFromId(ss, old_id); EntBin *bin = BinFromId(ss, old_id);
u32 prev_index = 0; u32 prev_index = 0;
u32 next_index = 0; u32 next_index = 0;
@ -183,10 +197,12 @@ void SetEntityId(Entity *ent, EntityId id)
Entity *prev = NilEntity(); Entity *prev = NilEntity();
Entity *next = NilEntity(); Entity *next = NilEntity();
Entity *search = EntityFromIndex(ss, search_index); Entity *search = EntityFromIndex(ss, search_index);
while (search->valid) { while (search->valid)
{
next_index = search->next_in_id_bin; next_index = search->next_in_id_bin;
next = EntityFromIndex(ss, next_index); next = EntityFromIndex(ss, next_index);
if (EqId(search->id, old_id)) { if (EqId(search->id, old_id))
{
break; break;
} }
prev_index = search_index; prev_index = search_index;
@ -198,21 +214,28 @@ void SetEntityId(Entity *ent, EntityId id)
/* Old id not in bin, this should be impossible. */ /* Old id not in bin, this should be impossible. */
Assert(search->valid); Assert(search->valid);
if (prev->valid) { if (prev->valid)
{
prev->next_in_id_bin = next_index; prev->next_in_id_bin = next_index;
} else { }
else
{
bin->first = next_index; bin->first = next_index;
} }
if (next->valid) { if (next->valid)
{
next->prev_in_id_bin = prev_index; next->prev_in_id_bin = prev_index;
} else { }
else
{
bin->last = prev_index; bin->last = prev_index;
} }
} }
/* Insert new id into lookup */ /* Insert new id into lookup */
if (!IsNilId(id)) { if (!IsNilId(id))
{
#if RtcIsEnabled #if RtcIsEnabled
{ {
Entity *existing = EntityFromId(ss, id); Entity *existing = EntityFromId(ss, id);
@ -224,10 +247,13 @@ void SetEntityId(Entity *ent, EntityId id)
EntBin *bin = BinFromId(ss, id); EntBin *bin = BinFromId(ss, id);
u32 ent_index = IndexFromEntity(ss, ent); u32 ent_index = IndexFromEntity(ss, ent);
Entity *last = EntityFromIndex(ss, bin->last); Entity *last = EntityFromIndex(ss, bin->last);
if (last->valid) { if (last->valid)
{
last->next_in_id_bin = ent_index; last->next_in_id_bin = ent_index;
ent->prev_in_id_bin = bin->last; ent->prev_in_id_bin = bin->last;
} else { }
else
{
bin->first = ent_index; bin->first = ent_index;
ent->prev_in_id_bin = 0; ent->prev_in_id_bin = 0;
} }
@ -242,10 +268,13 @@ void SetEntityId(Entity *ent, EntityId id)
Entity *EntityFromId(Snapshot *ss, EntityId id) Entity *EntityFromId(Snapshot *ss, EntityId id)
{ {
Entity *result = NilEntity(); Entity *result = NilEntity();
if (!IsNilId(id) && ss->valid) { if (!IsNilId(id) && ss->valid)
{
EntBin *bin = BinFromId(ss, id); EntBin *bin = BinFromId(ss, id);
for (Entity *e = EntityFromIndex(ss, bin->first); e->valid; e = EntityFromIndex(ss, e->next_in_id_bin)) { for (Entity *e = EntityFromIndex(ss, bin->first); e->valid; e = EntityFromIndex(ss, e->next_in_id_bin))
if (EqId(e->id, id)) { {
if (EqId(e->id, id))
{
result = e; result = e;
break; break;
} }
@ -299,9 +328,11 @@ Entity *FirstWithProp(Snapshot *ss, Prop prop)
{ {
u64 count = ss->num_ents_reserved; u64 count = ss->num_ents_reserved;
Entity *entities = ss->ents; Entity *entities = ss->ents;
for (u64 ent_index = 0; ent_index < count; ++ent_index) { for (u64 ent_index = 0; ent_index < count; ++ent_index)
{
Entity *ent = &entities[ent_index]; Entity *ent = &entities[ent_index];
if (ent->valid && HasProp(ent, prop)) { if (ent->valid && HasProp(ent, prop))
{
return ent; return ent;
} }
} }
@ -312,17 +343,22 @@ Entity *FirstWithAllProps(Snapshot *ss, PropArray props)
{ {
u64 count = ss->num_ents_reserved; u64 count = ss->num_ents_reserved;
Entity *entities = ss->ents; Entity *entities = ss->ents;
for (u64 ent_index = 0; ent_index < count; ++ent_index) { for (u64 ent_index = 0; ent_index < count; ++ent_index)
{
Entity *ent = &entities[ent_index]; Entity *ent = &entities[ent_index];
if (ent->valid) { if (ent->valid)
{
b32 all = 1; b32 all = 1;
for (u64 i = 0; i < props.count; ++i) { for (u64 i = 0; i < props.count; ++i)
if (!HasProp(ent, props.props[i])) { {
if (!HasProp(ent, props.props[i]))
{
all = 0; all = 0;
break; break;
} }
} }
if (all) { if (all)
{
return ent; return ent;
} }
} }
@ -338,7 +374,8 @@ void Link(Entity *ent, Entity *parent)
Snapshot *ss = ent->ss; Snapshot *ss = ent->ss;
Entity *old_parent = EntityFromId(ss, ent->parent); Entity *old_parent = EntityFromId(ss, ent->parent);
if (old_parent->valid) { if (old_parent->valid)
{
/* Unlink from current parent */ /* Unlink from current parent */
Unlink(ent); Unlink(ent);
} }
@ -346,18 +383,24 @@ void Link(Entity *ent, Entity *parent)
EntityId ent_id = ent->id; EntityId ent_id = ent->id;
EntityId last_child_id = parent->last; EntityId last_child_id = parent->last;
Entity *last_child = EntityFromId(ss, last_child_id); Entity *last_child = EntityFromId(ss, last_child_id);
if (last_child->valid) { if (last_child->valid)
{
ent->prev = last_child_id; ent->prev = last_child_id;
last_child->next = ent_id; last_child->next = ent_id;
} else { }
else
{
parent->first = ent_id; parent->first = ent_id;
} }
parent->last = ent_id; parent->last = ent_id;
if (parent->is_root) { if (parent->is_root)
{
ent->is_top = 1; ent->is_top = 1;
ent->top = ent_id; ent->top = ent_id;
} else { }
else
{
ent->top = parent->top; ent->top = parent->top;
} }
@ -375,14 +418,20 @@ void Unlink(Entity *ent)
Entity *next = EntityFromId(ss, ent->next); Entity *next = EntityFromId(ss, ent->next);
/* Unlink from parent & siblings */ /* Unlink from parent & siblings */
if (prev->valid) { if (prev->valid)
{
prev->next = next->id; prev->next = next->id;
} else { }
else
{
parent->first = next->id; parent->first = next->id;
} }
if (next->valid) { if (next->valid)
{
next->prev = prev->id; next->prev = prev->id;
} else { }
else
{
parent->last = prev->id; parent->last = prev->id;
} }
ent->prev = NilEntityId; ent->prev = NilEntityId;
@ -394,10 +443,14 @@ void Unlink(Entity *ent)
void MarkChildXformsDirty(Snapshot *ss, Entity *ent) void MarkChildXformsDirty(Snapshot *ss, Entity *ent)
{ {
for (Entity *child = EntityFromId(ss, ent->first); child->valid; child = EntityFromId(ss, child->next)) { for (Entity *child = EntityFromId(ss, ent->first); child->valid; child = EntityFromId(ss, child->next))
if (child->_is_xform_dirty) { {
if (child->_is_xform_dirty)
{
break; break;
} else { }
else
{
child->_is_xform_dirty = 1; child->_is_xform_dirty = 1;
MarkChildXformsDirty(ss, child); MarkChildXformsDirty(ss, child);
} }
@ -407,10 +460,14 @@ void MarkChildXformsDirty(Snapshot *ss, Entity *ent)
Xform XformFromEntity_(Snapshot *ss, Entity *ent) Xform XformFromEntity_(Snapshot *ss, Entity *ent)
{ {
Xform xf; Xform xf;
if (ent->_is_xform_dirty) { if (ent->_is_xform_dirty)
if (ent->is_top) { {
if (ent->is_top)
{
xf = ent->_local_xform; xf = ent->_local_xform;
} else { }
else
{
Entity *parent = EntityFromId(ss, ent->parent); Entity *parent = EntityFromId(ss, ent->parent);
xf = XformFromEntity_(ss, parent); xf = XformFromEntity_(ss, parent);
xf = MulXform(xf, ent->_local_xform); xf = MulXform(xf, ent->_local_xform);
@ -419,7 +476,9 @@ Xform XformFromEntity_(Snapshot *ss, Entity *ent)
} }
ent->_xform = xf; ent->_xform = xf;
ent->_is_xform_dirty = 0; ent->_is_xform_dirty = 0;
} else { }
else
{
xf = ent->_xform; xf = ent->_xform;
} }
return xf; return xf;
@ -428,10 +487,14 @@ Xform XformFromEntity_(Snapshot *ss, Entity *ent)
Xform XformFromEntity(Entity *ent) Xform XformFromEntity(Entity *ent)
{ {
Xform xf; Xform xf;
if (ent->_is_xform_dirty) { if (ent->_is_xform_dirty)
if (ent->is_top) { {
if (ent->is_top)
{
xf = ent->_local_xform; xf = ent->_local_xform;
} else { }
else
{
Snapshot *ss = ent->ss; Snapshot *ss = ent->ss;
Entity *parent = EntityFromId(ss, ent->parent); Entity *parent = EntityFromId(ss, ent->parent);
xf = XformFromEntity_(ss, parent); xf = XformFromEntity_(ss, parent);
@ -441,7 +504,9 @@ Xform XformFromEntity(Entity *ent)
} }
ent->_xform = xf; ent->_xform = xf;
ent->_is_xform_dirty = 0; ent->_is_xform_dirty = 0;
} else { }
else
{
xf = ent->_xform; xf = ent->_xform;
} }
return xf; return xf;
@ -454,12 +519,16 @@ Xform LocalXformFromEntity(Entity *ent)
void SetXform(Entity *ent, Xform xf) void SetXform(Entity *ent, Xform xf)
{ {
if (!EqXform(xf, ent->_xform)) { if (!EqXform(xf, ent->_xform))
{
Snapshot *ss = ent->ss; Snapshot *ss = ent->ss;
/* Update local xform */ /* Update local xform */
if (ent->is_top) { if (ent->is_top)
{
ent->_local_xform = xf; ent->_local_xform = xf;
} else { }
else
{
Entity *parent = EntityFromId(ss, ent->parent); Entity *parent = EntityFromId(ss, ent->parent);
Xform parent_global = XformFromEntity_(ss, parent); Xform parent_global = XformFromEntity_(ss, parent);
ent->_local_xform = MulXform(InvertXform(parent_global), xf); ent->_local_xform = MulXform(InvertXform(parent_global), xf);
@ -472,7 +541,8 @@ void SetXform(Entity *ent, Xform xf)
void SetLocalXform(Entity *ent, Xform xf) void SetLocalXform(Entity *ent, Xform xf)
{ {
if (!EqXform(xf, ent->_local_xform)) { if (!EqXform(xf, ent->_local_xform))
{
ent->_local_xform = xf; ent->_local_xform = xf;
ent->_is_xform_dirty = 1; ent->_is_xform_dirty = 1;
MarkChildXformsDirty(ent->ss, ent); MarkChildXformsDirty(ent->ss, ent);
@ -484,21 +554,24 @@ void SetLocalXform(Entity *ent, Xform xf)
void SetLinearVelocity(Entity *ent, Vec2 velocity) void SetLinearVelocity(Entity *ent, Vec2 velocity)
{ {
if (HasProp(ent, Prop_Kinematic) || HasProp(ent, Prop_Dynamic)) { if (HasProp(ent, Prop_Kinematic) || HasProp(ent, Prop_Dynamic))
{
ent->linear_velocity = ClampVec2Len(velocity, SIM_MAX_LINEAR_VELOCITY); ent->linear_velocity = ClampVec2Len(velocity, SIM_MAX_LINEAR_VELOCITY);
} }
} }
void SetAngularVelocity(Entity *ent, f32 velocity) void SetAngularVelocity(Entity *ent, f32 velocity)
{ {
if (HasProp(ent, Prop_Kinematic) || HasProp(ent, Prop_Dynamic)) { if (HasProp(ent, Prop_Kinematic) || HasProp(ent, Prop_Dynamic))
{
ent->angular_velocity = ClampF32(velocity, -SIM_MAX_ANGULAR_VELOCITY, SIM_MAX_ANGULAR_VELOCITY); ent->angular_velocity = ClampF32(velocity, -SIM_MAX_ANGULAR_VELOCITY, SIM_MAX_ANGULAR_VELOCITY);
} }
} }
void ApplyLinearImpulse(Entity *ent, Vec2 impulse, Vec2 point) void ApplyLinearImpulse(Entity *ent, Vec2 impulse, Vec2 point)
{ {
if (HasProp(ent, Prop_Dynamic)) { if (HasProp(ent, Prop_Dynamic))
{
Xform xf = XformFromEntity(ent); Xform xf = XformFromEntity(ent);
Vec2 center = xf.og; Vec2 center = xf.og;
f32 scale = AbsF32(DeterminantFromXform(xf)); f32 scale = AbsF32(DeterminantFromXform(xf));
@ -513,7 +586,8 @@ void ApplyLinearImpulse(Entity *ent, Vec2 impulse, Vec2 point)
void ApplyLinearImpulseToCenter(Entity *ent, Vec2 impulse) void ApplyLinearImpulseToCenter(Entity *ent, Vec2 impulse)
{ {
if (HasProp(ent, Prop_Dynamic)) { if (HasProp(ent, Prop_Dynamic))
{
Xform xf = XformFromEntity(ent); Xform xf = XformFromEntity(ent);
f32 scale = AbsF32(DeterminantFromXform(xf)); f32 scale = AbsF32(DeterminantFromXform(xf));
f32 inv_mass = 1.f / (ent->mass_unscaled * scale); f32 inv_mass = 1.f / (ent->mass_unscaled * scale);
@ -524,14 +598,16 @@ void ApplyLinearImpulseToCenter(Entity *ent, Vec2 impulse)
void ApplyForceToCenter(Entity *ent, Vec2 force) void ApplyForceToCenter(Entity *ent, Vec2 force)
{ {
if (HasProp(ent, Prop_Dynamic)) { if (HasProp(ent, Prop_Dynamic))
{
ent->force = AddVec2(ent->force, force); ent->force = AddVec2(ent->force, force);
} }
} }
void ApplyAngularImpulse(Entity *ent, f32 impulse) void ApplyAngularImpulse(Entity *ent, f32 impulse)
{ {
if (HasProp(ent, Prop_Dynamic)) { if (HasProp(ent, Prop_Dynamic))
{
Xform xf = XformFromEntity(ent); Xform xf = XformFromEntity(ent);
f32 scale = AbsF32(DeterminantFromXform(xf)); f32 scale = AbsF32(DeterminantFromXform(xf));
f32 inv_inertia = 1.f / (ent->inertia_unscaled * scale); f32 inv_inertia = 1.f / (ent->inertia_unscaled * scale);
@ -541,7 +617,8 @@ void ApplyAngularImpulse(Entity *ent, f32 impulse)
void ApplyTorque(Entity *ent, f32 torque) void ApplyTorque(Entity *ent, f32 torque)
{ {
if (HasProp(ent, Prop_Dynamic)) { if (HasProp(ent, Prop_Dynamic))
{
ent->torque += torque; ent->torque += torque;
} }
} }
@ -576,10 +653,12 @@ void LerpEntity(Entity *e, Entity *e0, Entity *e1, f64 blend)
{ {
if (IsValidAndActive(e0) && IsValidAndActive(e1) if (IsValidAndActive(e0) && IsValidAndActive(e1)
&& EqId(e0->id, e1->id) && EqId(e0->id, e1->id)
&& e0->continuity_gen == e1->continuity_gen) { && e0->continuity_gen == e1->continuity_gen)
{
e->_local_xform = LerpXform(e0->_local_xform, e1->_local_xform, blend); e->_local_xform = LerpXform(e0->_local_xform, e1->_local_xform, blend);
if (e->is_top) { if (e->is_top)
{
/* TODO: Cache parent & child xforms in sim */ /* TODO: Cache parent & child xforms in sim */
Xform e0_xf = XformFromEntity(e0); Xform e0_xf = XformFromEntity(e0);
Xform e1_xf = XformFromEntity(e1); Xform e1_xf = XformFromEntity(e1);
@ -615,16 +694,19 @@ void LerpEntity(Entity *e, Entity *e0, Entity *e1, f64 blend)
void CreateMissingEntitiesFromSnapshots(Entity *local_parent, Entity *remote, EntityId remote_player) void CreateMissingEntitiesFromSnapshots(Entity *local_parent, Entity *remote, EntityId remote_player)
{ {
__prof; __prof;
if (HasProp(remote, Prop_SyncSrc)) { if (HasProp(remote, Prop_SyncSrc))
{
Snapshot *local_ss = local_parent->ss; Snapshot *local_ss = local_parent->ss;
Snapshot *remote_ss = remote->ss; Snapshot *remote_ss = remote->ss;
EntityId id = remote->id; EntityId id = remote->id;
Entity *local_ent = EntityFromId(local_ss, id); Entity *local_ent = EntityFromId(local_ss, id);
if (!local_ent->valid) { if (!local_ent->valid)
{
local_ent = AcquireSyncDst(local_parent, id, remote_player); local_ent = AcquireSyncDst(local_parent, id, remote_player);
} }
for (Entity *remote_child = EntityFromId(remote_ss, remote->first); remote_child->valid; remote_child = EntityFromId(remote_ss, remote_child->next)) { for (Entity *remote_child = EntityFromId(remote_ss, remote->first); remote_child->valid; remote_child = EntityFromId(remote_ss, remote_child->next))
{
CreateMissingEntitiesFromSnapshots(local_ent, remote_child, remote_player); CreateMissingEntitiesFromSnapshots(local_ent, remote_child, remote_player);
} }
} }
@ -665,7 +747,8 @@ void SyncEntity(Entity *local, Entity *remote)
#if 1 #if 1
//- Encode ////////////////////////////////
//~ Encode
void EncodeEntity(BB_Writer *bw, Entity *e0, Entity *e1) void EncodeEntity(BB_Writer *bw, Entity *e0, Entity *e1)
{ {
@ -676,11 +759,13 @@ void EncodeEntity(BB_Writer *bw, Entity *e0, Entity *e1)
u64 pos = 0; u64 pos = 0;
e1->ss = e0->ss; e1->ss = e0->ss;
while (pos < sizeof(*e1)) { while (pos < sizeof(*e1))
{
u64 chunk_size = MinU64(pos + 8, sizeof(*e1)) - pos; u64 chunk_size = MinU64(pos + 8, sizeof(*e1)) - pos;
u8 *chunk0 = (u8 *)e0 + pos; u8 *chunk0 = (u8 *)e0 + pos;
u8 *chunk1 = (u8 *)e1 + pos; u8 *chunk1 = (u8 *)e1 + pos;
if (BB_WriteBit(bw, !EqBytes(chunk0, chunk1, chunk_size))) { if (BB_WriteBit(bw, !EqBytes(chunk0, chunk1, chunk_size)))
{
u64 bits = 0; u64 bits = 0;
CopyBytes(&bits, chunk1, chunk_size); CopyBytes(&bits, chunk1, chunk_size);
BB_WriteUBits(bw, bits, 64); BB_WriteUBits(bw, bits, 64);
@ -690,16 +775,19 @@ void EncodeEntity(BB_Writer *bw, Entity *e0, Entity *e1)
e1->ss = ss; e1->ss = ss;
} }
//- Decode ////////////////////////////////
//~ Decode
void DecodeEntity(BB_Reader *br, Entity *e) void DecodeEntity(BB_Reader *br, Entity *e)
{ {
Snapshot *old_ss = e->ss; Snapshot *old_ss = e->ss;
{ {
u64 pos = 0; u64 pos = 0;
while (pos < sizeof(*e)) { while (pos < sizeof(*e))
{
u8 *chunk = (u8 *)e + pos; u8 *chunk = (u8 *)e + pos;
if (BB_ReadBit(br)) { if (BB_ReadBit(br))
{
u64 chunk_size = MinU64(pos + 8, sizeof(*e)) - pos; u64 chunk_size = MinU64(pos + 8, sizeof(*e)) - pos;
u64 bits = BB_ReadUBits(br, 64); u64 bits = BB_ReadUBits(br, 64);
CopyBytes(chunk, &bits, chunk_size); CopyBytes(chunk, &bits, chunk_size);
@ -713,7 +801,8 @@ void DecodeEntity(BB_Reader *br, Entity *e)
#else #else
//- Encode ////////////////////////////////
//~ Encode
void EncodeEntity(BB_Writer *bw, Entity *e0, Entity *e1) void EncodeEntity(BB_Writer *bw, Entity *e0, Entity *e1)
{ {
@ -727,13 +816,17 @@ void EncodeEntity(BB_Writer *bw, Entity *e0, Entity *e1)
u64 pos = 0; u64 pos = 0;
e1->ss = e0->ss; e1->ss = e0->ss;
while (pos < sizeof(*e1)) { while (pos < sizeof(*e1))
{
u64 chunk_size = MinU64(pos + 8, sizeof(*e1)) - pos; u64 chunk_size = MinU64(pos + 8, sizeof(*e1)) - pos;
u8 *chunk0 = (u8 *)e0 + pos; u8 *chunk0 = (u8 *)e0 + pos;
u8 *chunk1 = (u8 *)e1 + pos; u8 *chunk1 = (u8 *)e1 + pos;
if (EqBytes(chunk0, chunk1, chunk_size)) { if (EqBytes(chunk0, chunk1, chunk_size))
{
BB_WriteBit(bw, 0); BB_WriteBit(bw, 0);
} else { }
else
{
BB_WriteBit(bw, 1); BB_WriteBit(bw, 1);
u64 bits = 0; u64 bits = 0;
CopyBytes(&bits, chunk1, chunk_size); CopyBytes(&bits, chunk1, chunk_size);
@ -744,16 +837,19 @@ void EncodeEntity(BB_Writer *bw, Entity *e0, Entity *e1)
e1->ss = ss; e1->ss = ss;
} }
//- Decode ////////////////////////////////
//~ Decode
void DecodeEntity(BB_Reader *br, Entity *e) void DecodeEntity(BB_Reader *br, Entity *e)
{ {
Entity decoded = *e; Entity decoded = *e;
{ {
u64 pos = 0; u64 pos = 0;
while (pos < sizeof(decoded)) { while (pos < sizeof(decoded))
{
u8 *chunk = (u8 *)&decoded + pos; u8 *chunk = (u8 *)&decoded + pos;
if (BB_ReadBit(br)) { if (BB_ReadBit(br))
{
u64 chunk_size = MinU64(pos + 8, sizeof(decoded)) - pos; u64 chunk_size = MinU64(pos + 8, sizeof(decoded)) - pos;
u64 bits = BB_ReadUBits(br, 64); u64 bits = BB_ReadUBits(br, 64);
CopyBytes(chunk, &bits, chunk_size); CopyBytes(chunk, &bits, chunk_size);
@ -767,7 +863,8 @@ void DecodeEntity(BB_Reader *br, Entity *e)
EntityId new_id = decoded.id; EntityId new_id = decoded.id;
CopyStruct(e, &decoded); CopyStruct(e, &decoded);
e->id = old_id; e->id = old_id;
if (!EqId(old_id, new_id)) { if (!EqId(old_id, new_id))
{
SetEntityId(e, new_id); SetEntityId(e, new_id);
} }
} }

View File

@ -558,7 +558,11 @@ void CreateMissingEntitiesFromSnapshots(Entity *local_parent, Entity *remote, En
void SyncEntity(Entity *local, Entity *remote); void SyncEntity(Entity *local, Entity *remote);
//////////////////////////////// ////////////////////////////////
//~ Encode / decode operations //~ Encode
void EncodeEntity(BB_Writer *bw, Entity *e0, Entity *e1); void EncodeEntity(BB_Writer *bw, Entity *e0, Entity *e1);
////////////////////////////////
//~ Decode
void DecodeEntity(BB_Reader *br, Entity *e); void DecodeEntity(BB_Reader *br, Entity *e);

View File

@ -22,7 +22,8 @@ void CreateAndUpdateContacts(PhysStepCtx *ctx, f32 elapsed_dt, u64 phys_iteratio
Entity *root = EntityFromId(ss, RootEntityId); Entity *root = EntityFromId(ss, RootEntityId);
u64 tick = ss->tick; u64 tick = ss->tick;
for (u64 check0_index = 0; check0_index < ss->num_ents_reserved; ++check0_index) { for (u64 check0_index = 0; check0_index < ss->num_ents_reserved; ++check0_index)
{
Entity *check0 = &ss->ents[check0_index]; Entity *check0 = &ss->ents[check0_index];
if (!IsValidAndActive(check0)) continue; if (!IsValidAndActive(check0)) continue;
if (!(HasProp(check0, Prop_Solid) || HasProp(check0, Prop_Sensor))) continue; if (!(HasProp(check0, Prop_Solid) || HasProp(check0, Prop_Sensor))) continue;
@ -34,7 +35,8 @@ void CreateAndUpdateContacts(PhysStepCtx *ctx, f32 elapsed_dt, u64 phys_iteratio
SpaceIter iter = space_iter_begin_aabb(space, aabb); SpaceIter iter = space_iter_begin_aabb(space, aabb);
SpaceEntry *space_entry; SpaceEntry *space_entry;
while ((space_entry = space_iter_next(&iter)) != 0) { while ((space_entry = space_iter_next(&iter)) != 0)
{
Entity *check1 = EntityFromId(ss, space_entry->ent); Entity *check1 = EntityFromId(ss, space_entry->ent);
if (!IsValidAndActive(check1)) continue; if (!IsValidAndActive(check1)) continue;
if (!(HasProp(check1, Prop_Solid) || HasProp(check1, Prop_Sensor))) continue; if (!(HasProp(check1, Prop_Solid) || HasProp(check1, Prop_Sensor))) continue;
@ -48,14 +50,17 @@ void CreateAndUpdateContacts(PhysStepCtx *ctx, f32 elapsed_dt, u64 phys_iteratio
Xform e1_xf; Xform e1_xf;
CLD_Shape e0_collider; CLD_Shape e0_collider;
CLD_Shape e1_collider; CLD_Shape e1_collider;
if (check0->id.uid.hi < check1->id.uid.hi) { if (check0->id.uid.hi < check1->id.uid.hi)
{
e0 = check0; e0 = check0;
e1 = check1; e1 = check1;
e0_xf = check0_xf; e0_xf = check0_xf;
e1_xf = XformFromEntity(check1); e1_xf = XformFromEntity(check1);
e0_collider = check0_collider; e0_collider = check0_collider;
e1_collider = check1->local_collider; e1_collider = check1->local_collider;
} else { }
else
{
e0 = check1; e0 = check1;
e1 = check0; e1 = check0;
e0_xf = XformFromEntity(check1); e0_xf = XformFromEntity(check1);
@ -67,11 +72,15 @@ void CreateAndUpdateContacts(PhysStepCtx *ctx, f32 elapsed_dt, u64 phys_iteratio
EntityId constraint_id = ContactConstraintIdFromContactingIds(local_player, e0->id, e1->id); EntityId constraint_id = ContactConstraintIdFromContactingIds(local_player, e0->id, e1->id);
Entity *constraint_ent = EntityFromId(ss, constraint_id); Entity *constraint_ent = EntityFromId(ss, constraint_id);
if (constraint_ent->valid) { if (constraint_ent->valid)
if (constraint_ent->contact_constraint_data.last_phys_iteration >= phys_iteration) { {
if (constraint_ent->contact_constraint_data.last_phys_iteration >= phys_iteration)
{
/* Already processed constraint this iteration */ /* Already processed constraint this iteration */
continue; continue;
} else { }
else
{
constraint_ent->contact_constraint_data.last_phys_iteration = phys_iteration; constraint_ent->contact_constraint_data.last_phys_iteration = phys_iteration;
} }
} }
@ -84,9 +93,11 @@ void CreateAndUpdateContacts(PhysStepCtx *ctx, f32 elapsed_dt, u64 phys_iteratio
StaticAssert(countof(collision_result.points) == 2); StaticAssert(countof(collision_result.points) == 2);
ContactConstraint *constraint = 0; ContactConstraint *constraint = 0;
if (collision_result.num_points > 0) { if (collision_result.num_points > 0)
{
b32 is_start = 0; b32 is_start = 0;
if (!constraint_ent->valid) { if (!constraint_ent->valid)
{
is_start = 1; is_start = 1;
/* Create constraint */ /* Create constraint */
constraint_ent = AcquireLocalWithId(root, constraint_id); constraint_ent = AcquireLocalWithId(root, constraint_id);
@ -106,17 +117,21 @@ void CreateAndUpdateContacts(PhysStepCtx *ctx, f32 elapsed_dt, u64 phys_iteratio
constraint->friction = SqrtF32(e0->friction * e1->friction); constraint->friction = SqrtF32(e0->friction * e1->friction);
/* Delete old contacts that are no longer present */ /* Delete old contacts that are no longer present */
for (u32 i = 0; i < constraint->num_points; ++i) { for (u32 i = 0; i < constraint->num_points; ++i)
{
ContactPoint *old = &constraint->points[i]; ContactPoint *old = &constraint->points[i];
u32 id = old->id; u32 id = old->id;
b32 found = 0; b32 found = 0;
for (u32 j = 0; j < collision_result.num_points; ++j) { for (u32 j = 0; j < collision_result.num_points; ++j)
if (collision_result.points[j].id == id) { {
if (collision_result.points[j].id == id)
{
found = 1; found = 1;
break; break;
} }
} }
if (!found) { if (!found)
{
/* Delete contact by replacing with last in array */ /* Delete contact by replacing with last in array */
*old = constraint->points[--constraint->num_points]; *old = constraint->points[--constraint->num_points];
--i; --i;
@ -124,21 +139,25 @@ void CreateAndUpdateContacts(PhysStepCtx *ctx, f32 elapsed_dt, u64 phys_iteratio
} }
/* Update / insert returned contacts */ /* Update / insert returned contacts */
for (u32 i = 0; i < collision_result.num_points; ++i) { for (u32 i = 0; i < collision_result.num_points; ++i)
{
CLD_CollisionPoint *res_point = &collision_result.points[i]; CLD_CollisionPoint *res_point = &collision_result.points[i];
Vec2 point = res_point->point; Vec2 point = res_point->point;
f32 sep = res_point->separation; f32 sep = res_point->separation;
u32 id = res_point->id; u32 id = res_point->id;
ContactPoint *contact = 0; ContactPoint *contact = 0;
/* Match */ /* Match */
for (u32 j = 0; j < constraint->num_points; ++j) { for (u32 j = 0; j < constraint->num_points; ++j)
{
ContactPoint *t = &constraint->points[j]; ContactPoint *t = &constraint->points[j];
if (t->id == id) { if (t->id == id)
{
contact = t; contact = t;
break; break;
} }
} }
if (!contact) { if (!contact)
{
/* Insert */ /* Insert */
contact = &constraint->points[constraint->num_points++]; contact = &constraint->points[constraint->num_points++];
ZeroStruct(contact); ZeroStruct(contact);
@ -163,17 +182,20 @@ void CreateAndUpdateContacts(PhysStepCtx *ctx, f32 elapsed_dt, u64 phys_iteratio
Vec2 dir1 = e1->collision_dir; Vec2 dir1 = e1->collision_dir;
f32 threshold = 0.5; f32 threshold = 0.5;
b32 is_wrong_dir = 0; b32 is_wrong_dir = 0;
if (!IsVec2Zero(dir0)) { if (!IsVec2Zero(dir0))
{
is_wrong_dir = DotVec2(dir0, normal) <= threshold; is_wrong_dir = DotVec2(dir0, normal) <= threshold;
} }
if (!IsVec2Zero(dir1) && !is_wrong_dir) { if (!IsVec2Zero(dir1) && !is_wrong_dir)
{
is_wrong_dir = DotVec2(dir1, NegVec2(normal)) <= threshold; is_wrong_dir = DotVec2(dir1, NegVec2(normal)) <= threshold;
} }
constraint->wrong_dir = is_wrong_dir; constraint->wrong_dir = is_wrong_dir;
} }
/* Run collision callback */ /* Run collision callback */
if (collision_callback) { if (collision_callback)
{
CollisionData data = ZI; CollisionData data = ZI;
data.e0 = e0->id; data.e0 = e0->id;
data.e1 = e1->id; data.e1 = e1->id;
@ -183,7 +205,8 @@ void CreateAndUpdateContacts(PhysStepCtx *ctx, f32 elapsed_dt, u64 phys_iteratio
/* Calculate point */ /* Calculate point */
Vec2 midpoint = collision_result.points[0].point; Vec2 midpoint = collision_result.points[0].point;
if (collision_result.num_points > 1) { if (collision_result.num_points > 1)
{
midpoint = AddVec2(midpoint, MulVec2(SubVec2(collision_result.points[1].point, midpoint), 0.5f)); midpoint = AddVec2(midpoint, MulVec2(SubVec2(collision_result.points[1].point, midpoint), 0.5f));
} }
data.point = midpoint; data.point = midpoint;
@ -213,11 +236,14 @@ void CreateAndUpdateContacts(PhysStepCtx *ctx, f32 elapsed_dt, u64 phys_iteratio
/* Run callback twice for both e0 & e1 */ /* Run callback twice for both e0 & e1 */
b32 skip_solve0 = collision_callback(&data, sim_step_ctx); b32 skip_solve0 = collision_callback(&data, sim_step_ctx);
b32 skip_solve1 = collision_callback(&data_inverted, sim_step_ctx); b32 skip_solve1 = collision_callback(&data_inverted, sim_step_ctx);
if (skip_solve0 || skip_solve1) { if (skip_solve0 || skip_solve1)
{
constraint->skip_solve = 1; constraint->skip_solve = 1;
} }
} }
} else if (constraint_ent->valid) { }
else if (constraint_ent->valid)
{
constraint_ent->contact_constraint_data.num_points = 0; constraint_ent->contact_constraint_data.num_points = 0;
} }
@ -226,7 +252,8 @@ void CreateAndUpdateContacts(PhysStepCtx *ctx, f32 elapsed_dt, u64 phys_iteratio
{ {
EntityId dbg_ent_id = CollisionDebugIdFromIds(local_player, e0->id, e1->id); EntityId dbg_ent_id = CollisionDebugIdFromIds(local_player, e0->id, e1->id);
Entity *dbg_ent = EntityFromId(ss, dbg_ent_id); Entity *dbg_ent = EntityFromId(ss, dbg_ent_id);
if (!dbg_ent->valid) { if (!dbg_ent->valid)
{
/* FIXME: Entity never released */ /* FIXME: Entity never released */
dbg_ent = AcquireLocalWithId(root, dbg_ent_id); dbg_ent = AcquireLocalWithId(root, dbg_ent_id);
EnableProp(dbg_ent, Prop_CollisionDebug); EnableProp(dbg_ent, Prop_CollisionDebug);
@ -238,10 +265,13 @@ void CreateAndUpdateContacts(PhysStepCtx *ctx, f32 elapsed_dt, u64 phys_iteratio
dbg->e1 = e1->id; dbg->e1 = e1->id;
dbg->collision_result = collision_result; dbg->collision_result = collision_result;
if (constraint) { if (constraint)
{
CopyBytes(dbg->points, constraint->points, sizeof(dbg->points)); CopyBytes(dbg->points, constraint->points, sizeof(dbg->points));
dbg->num_points = constraint->num_points; dbg->num_points = constraint->num_points;
} else { }
else
{
dbg->num_points = 0; dbg->num_points = 0;
} }
@ -266,7 +296,8 @@ void PrepareContacts(PhysStepCtx *ctx, u64 phys_iteration)
__prof; __prof;
Snapshot *ss = ctx->sim_step_ctx->world; Snapshot *ss = ctx->sim_step_ctx->world;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) { for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index)
{
Entity *constraint_ent = &ss->ents[sim_ent_index]; Entity *constraint_ent = &ss->ents[sim_ent_index];
if (!ShouldSimulate(constraint_ent)) continue; if (!ShouldSimulate(constraint_ent)) continue;
if (!HasProp(constraint_ent, Prop_ContactConstraint)) continue; if (!HasProp(constraint_ent, Prop_ContactConstraint)) continue;
@ -276,7 +307,8 @@ void PrepareContacts(PhysStepCtx *ctx, u64 phys_iteration)
u32 num_points = constraint->num_points; u32 num_points = constraint->num_points;
Entity *e0 = EntityFromId(ss, constraint->e0); Entity *e0 = EntityFromId(ss, constraint->e0);
Entity *e1 = EntityFromId(ss, constraint->e1); Entity *e1 = EntityFromId(ss, constraint->e1);
if (constraint->last_phys_iteration >= phys_iteration && num_points > 0 && IsValidAndActive(e0) && IsValidAndActive(e1)) { if (constraint->last_phys_iteration >= phys_iteration && num_points > 0 && IsValidAndActive(e0) && IsValidAndActive(e1))
{
Vec2 normal = constraint->normal; Vec2 normal = constraint->normal;
Vec2 tangent = PerpVec2(normal); Vec2 tangent = PerpVec2(normal);
@ -291,14 +323,16 @@ void PrepareContacts(PhysStepCtx *ctx, u64 phys_iteration)
f32 inv_i1 = 0; f32 inv_i1 = 0;
{ {
/* If not simulated locally or ent is not dynamic, pretend contact mass is infinite */ /* If not simulated locally or ent is not dynamic, pretend contact mass is infinite */
if (ShouldSimulate(e0) && HasProp(e0, Prop_Dynamic)) { if (ShouldSimulate(e0) && HasProp(e0, Prop_Dynamic))
{
f32 scale = AbsF32(DeterminantFromXform(e0_xf)); f32 scale = AbsF32(DeterminantFromXform(e0_xf));
f32 scaled_mass = e0->mass_unscaled * scale; f32 scaled_mass = e0->mass_unscaled * scale;
f32 scaled_inertia = e0->inertia_unscaled * scale; f32 scaled_inertia = e0->inertia_unscaled * scale;
inv_m0 = 1.f / scaled_mass; inv_m0 = 1.f / scaled_mass;
inv_i0 = 1.f / scaled_inertia; inv_i0 = 1.f / scaled_inertia;
} }
if (ShouldSimulate(e1) && HasProp(e1, Prop_Dynamic)) { if (ShouldSimulate(e1) && HasProp(e1, Prop_Dynamic))
{
f32 scale = AbsF32(DeterminantFromXform(e1_xf)); f32 scale = AbsF32(DeterminantFromXform(e1_xf));
f32 scaled_mass = e1->mass_unscaled * scale; f32 scaled_mass = e1->mass_unscaled * scale;
f32 scaled_inertia = e1->inertia_unscaled * scale; f32 scaled_inertia = e1->inertia_unscaled * scale;
@ -313,7 +347,8 @@ void PrepareContacts(PhysStepCtx *ctx, u64 phys_iteration)
constraint->inv_i1 = inv_i1; constraint->inv_i1 = inv_i1;
/* Update / insert returned contacts */ /* Update / insert returned contacts */
for (u32 i = 0; i < num_points; ++i) { for (u32 i = 0; i < num_points; ++i)
{
ContactPoint *contact = &constraint->points[i]; ContactPoint *contact = &constraint->points[i];
Vec2 vcp0 = contact->vcp0; Vec2 vcp0 = contact->vcp0;
Vec2 vcp1 = contact->vcp1; Vec2 vcp1 = contact->vcp1;
@ -339,7 +374,9 @@ void PrepareContacts(PhysStepCtx *ctx, u64 phys_iteration)
contact->tangent_impulse = 0; contact->tangent_impulse = 0;
#endif #endif
} }
} else { }
else
{
/* Mark constraint for removal */ /* Mark constraint for removal */
constraint_ent->contact_constraint_data.num_points = 0; constraint_ent->contact_constraint_data.num_points = 0;
DisableProp(constraint_ent, Prop_Active); DisableProp(constraint_ent, Prop_Active);
@ -350,7 +387,8 @@ void PrepareContacts(PhysStepCtx *ctx, u64 phys_iteration)
#if 0 #if 0
#if COLLIDER_DEBUG #if COLLIDER_DEBUG
/* Remove collision debug ents */ /* Remove collision debug ents */
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) { for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index)
{
Entity *dbg_ent = &ss->ents[sim_ent_index]; Entity *dbg_ent = &ss->ents[sim_ent_index];
if (!ShouldSimulate(dbg_ent)) continue; if (!ShouldSimulate(dbg_ent)) continue;
if (!HasProp(dbg_ent, Prop_CollisionDebug)) continue; if (!HasProp(dbg_ent, Prop_CollisionDebug)) continue;
@ -361,7 +399,8 @@ void PrepareContacts(PhysStepCtx *ctx, u64 phys_iteration)
if (!(ShouldSimulate(e0) && ShouldSimulate(e1)) || if (!(ShouldSimulate(e0) && ShouldSimulate(e1)) ||
!(HasProp(e0, Prop_Solid) || HasProp(e0, Prop_Sensor)) || !(HasProp(e0, Prop_Solid) || HasProp(e0, Prop_Sensor)) ||
!(HasProp(e1, Prop_Solid) || HasProp(e1, Prop_Sensor))) { !(HasProp(e1, Prop_Solid) || HasProp(e1, Prop_Sensor)))
{
/* Mark dbg ent for removal */ /* Mark dbg ent for removal */
DisableProp(dbg_ent, Prop_Active); DisableProp(dbg_ent, Prop_Active);
EnableProp(dbg_ent, Prop_Release); EnableProp(dbg_ent, Prop_Release);
@ -375,7 +414,8 @@ void WarmStartContacts(PhysStepCtx *ctx)
{ {
__prof; __prof;
Snapshot *ss = ctx->sim_step_ctx->world; Snapshot *ss = ctx->sim_step_ctx->world;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) { for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index)
{
Entity *constraint_ent = &ss->ents[sim_ent_index]; Entity *constraint_ent = &ss->ents[sim_ent_index];
if (!ShouldSimulate(constraint_ent)) continue; if (!ShouldSimulate(constraint_ent)) continue;
if (!HasProp(constraint_ent, Prop_ContactConstraint)) continue; if (!HasProp(constraint_ent, Prop_ContactConstraint)) continue;
@ -386,7 +426,8 @@ void WarmStartContacts(PhysStepCtx *ctx)
Entity *e0 = EntityFromId(ss, constraint->e0); Entity *e0 = EntityFromId(ss, constraint->e0);
Entity *e1 = EntityFromId(ss, constraint->e1); Entity *e1 = EntityFromId(ss, constraint->e1);
if (num_points > 0 && IsValidAndActive(e0) && IsValidAndActive(e1) && !constraint->skip_solve && !constraint->wrong_dir) { if (num_points > 0 && IsValidAndActive(e0) && IsValidAndActive(e1) && !constraint->skip_solve && !constraint->wrong_dir)
{
f32 inv_m0 = constraint->inv_m0; f32 inv_m0 = constraint->inv_m0;
f32 inv_m1 = constraint->inv_m1; f32 inv_m1 = constraint->inv_m1;
f32 inv_i0 = constraint->inv_i0; f32 inv_i0 = constraint->inv_i0;
@ -401,7 +442,8 @@ void WarmStartContacts(PhysStepCtx *ctx)
Vec2 normal = constraint->normal; Vec2 normal = constraint->normal;
Vec2 tangent = PerpVec2(normal); Vec2 tangent = PerpVec2(normal);
f32 inv_num_points = 1.f / num_points; f32 inv_num_points = 1.f / num_points;
for (u32 i = 0; i < num_points; ++i) { for (u32 i = 0; i < num_points; ++i)
{
ContactPoint *point = &constraint->points[i]; ContactPoint *point = &constraint->points[i];
Vec2 vcp0 = point->vcp0; Vec2 vcp0 = point->vcp0;
Vec2 vcp1 = point->vcp1; Vec2 vcp1 = point->vcp1;
@ -427,7 +469,8 @@ void SolveContacts(PhysStepCtx *ctx, f32 dt, b32 apply_bias)
{ {
__prof; __prof;
Snapshot *ss = ctx->sim_step_ctx->world; Snapshot *ss = ctx->sim_step_ctx->world;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) { for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index)
{
Entity *constraint_ent = &ss->ents[sim_ent_index]; Entity *constraint_ent = &ss->ents[sim_ent_index];
if (!ShouldSimulate(constraint_ent)) continue; if (!ShouldSimulate(constraint_ent)) continue;
if (!HasProp(constraint_ent, Prop_ContactConstraint)) continue; if (!HasProp(constraint_ent, Prop_ContactConstraint)) continue;
@ -443,7 +486,8 @@ void SolveContacts(PhysStepCtx *ctx, f32 dt, b32 apply_bias)
f32 w1 = e1->angular_velocity; f32 w1 = e1->angular_velocity;
u32 num_points = constraint->num_points; u32 num_points = constraint->num_points;
if (num_points > 0 && IsValidAndActive(e0) && IsValidAndActive(e1) && !constraint->skip_solve && !constraint->wrong_dir) { if (num_points > 0 && IsValidAndActive(e0) && IsValidAndActive(e1) && !constraint->skip_solve && !constraint->wrong_dir)
{
Xform e0_xf = XformFromEntity(e0); Xform e0_xf = XformFromEntity(e0);
Xform e1_xf = XformFromEntity(e1); Xform e1_xf = XformFromEntity(e1);
@ -454,7 +498,8 @@ void SolveContacts(PhysStepCtx *ctx, f32 dt, b32 apply_bias)
/* Normal impulse */ /* Normal impulse */
Vec2 normal = constraint->normal; Vec2 normal = constraint->normal;
for (u32 point_index = 0; point_index < num_points; ++point_index) { for (u32 point_index = 0; point_index < num_points; ++point_index)
{
ContactPoint *point = &constraint->points[point_index]; ContactPoint *point = &constraint->points[point_index];
Vec2 vcp0 = point->vcp0; Vec2 vcp0 = point->vcp0;
Vec2 vcp1 = point->vcp1; Vec2 vcp1 = point->vcp1;
@ -468,10 +513,13 @@ void SolveContacts(PhysStepCtx *ctx, f32 dt, b32 apply_bias)
f32 mass_scale = 1.0f; f32 mass_scale = 1.0f;
f32 impulse_scale = 0.0f; f32 impulse_scale = 0.0f;
if (separation > 0.0f) { if (separation > 0.0f)
{
/* Speculative */ /* Speculative */
velocity_bias = separation / dt; velocity_bias = separation / dt;
} else if (apply_bias) { }
else if (apply_bias)
{
/* Soft constraint */ /* Soft constraint */
SoftSpring softness = MakeSpring(ContactSpringHz, ContactSpringDamp, dt); SoftSpring softness = MakeSpring(ContactSpringHz, ContactSpringDamp, dt);
f32 pushout_velocity = constraint->pushout_velocity; f32 pushout_velocity = constraint->pushout_velocity;
@ -504,7 +552,8 @@ void SolveContacts(PhysStepCtx *ctx, f32 dt, b32 apply_bias)
/* Tangent impulse */ /* Tangent impulse */
Vec2 tangent = PerpVec2(normal); Vec2 tangent = PerpVec2(normal);
for (u32 point_index = 0; point_index < num_points; ++point_index) { for (u32 point_index = 0; point_index < num_points; ++point_index)
{
ContactPoint *point = &constraint->points[point_index]; ContactPoint *point = &constraint->points[point_index];
Vec2 vcp0 = point->vcp0; Vec2 vcp0 = point->vcp0;
Vec2 vcp1 = point->vcp1; Vec2 vcp1 = point->vcp1;
@ -564,7 +613,8 @@ void PrepareMotorJoints(PhysStepCtx *ctx)
{ {
__prof; __prof;
Snapshot *ss = ctx->sim_step_ctx->world; Snapshot *ss = ctx->sim_step_ctx->world;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) { for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index)
{
Entity *joint_ent = &ss->ents[sim_ent_index]; Entity *joint_ent = &ss->ents[sim_ent_index];
if (!ShouldSimulate(joint_ent)) continue; if (!ShouldSimulate(joint_ent)) continue;
if (!HasProp(joint_ent, Prop_MotorJoint)) continue; if (!HasProp(joint_ent, Prop_MotorJoint)) continue;
@ -574,7 +624,8 @@ void PrepareMotorJoints(PhysStepCtx *ctx)
Entity *e0 = EntityFromId(ss, joint->e0); Entity *e0 = EntityFromId(ss, joint->e0);
Entity *e1 = EntityFromId(ss, joint->e1); Entity *e1 = EntityFromId(ss, joint->e1);
if (ShouldSimulate(e0) && ShouldSimulate(e1)) { if (ShouldSimulate(e0) && ShouldSimulate(e1))
{
Xform e0_xf = XformFromEntity(e0); Xform e0_xf = XformFromEntity(e0);
Xform e1_xf = XformFromEntity(e1); Xform e1_xf = XformFromEntity(e1);
@ -616,7 +667,9 @@ void PrepareMotorJoints(PhysStepCtx *ctx)
joint->linear_impulse = VEC2(0, 0); joint->linear_impulse = VEC2(0, 0);
joint->angular_impulse = 0; joint->angular_impulse = 0;
#endif #endif
} else { }
else
{
/* Mark joint for removal */ /* Mark joint for removal */
DisableProp(joint_ent, Prop_Active); DisableProp(joint_ent, Prop_Active);
EnableProp(joint_ent, Prop_Release); EnableProp(joint_ent, Prop_Release);
@ -628,7 +681,8 @@ void WarmStartMotorJoints(PhysStepCtx *ctx)
{ {
__prof; __prof;
Snapshot *ss = ctx->sim_step_ctx->world; Snapshot *ss = ctx->sim_step_ctx->world;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) { for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index)
{
Entity *joint_ent = &ss->ents[sim_ent_index]; Entity *joint_ent = &ss->ents[sim_ent_index];
if (!ShouldSimulate(joint_ent)) continue; if (!ShouldSimulate(joint_ent)) continue;
if (!HasProp(joint_ent, Prop_MotorJoint)) continue; if (!HasProp(joint_ent, Prop_MotorJoint)) continue;
@ -660,7 +714,8 @@ void SolveMotorJoints(PhysStepCtx *ctx, f32 dt)
{ {
__prof; __prof;
Snapshot *ss = ctx->sim_step_ctx->world; Snapshot *ss = ctx->sim_step_ctx->world;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) { for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index)
{
Entity *joint_ent = &ss->ents[sim_ent_index]; Entity *joint_ent = &ss->ents[sim_ent_index];
if (!ShouldSimulate(joint_ent)) continue; if (!ShouldSimulate(joint_ent)) continue;
if (!HasProp(joint_ent, Prop_MotorJoint)) continue; if (!HasProp(joint_ent, Prop_MotorJoint)) continue;
@ -765,14 +820,16 @@ void PrepareMouseJoints(PhysStepCtx *ctx)
{ {
__prof; __prof;
Snapshot *ss = ctx->sim_step_ctx->world; Snapshot *ss = ctx->sim_step_ctx->world;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) { for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index)
{
Entity *joint_ent = &ss->ents[sim_ent_index]; Entity *joint_ent = &ss->ents[sim_ent_index];
if (!ShouldSimulate(joint_ent)) continue; if (!ShouldSimulate(joint_ent)) continue;
if (!HasProp(joint_ent, Prop_MouseJoint)) continue; if (!HasProp(joint_ent, Prop_MouseJoint)) continue;
MouseJoint *joint = &joint_ent->mouse_joint_data; MouseJoint *joint = &joint_ent->mouse_joint_data;
Entity *ent = EntityFromId(ss, joint->target); Entity *ent = EntityFromId(ss, joint->target);
if (ShouldSimulate(ent)) { if (ShouldSimulate(ent))
{
Xform xf = XformFromEntity(ent); Xform xf = XformFromEntity(ent);
/* TODO: Cache this */ /* TODO: Cache this */
@ -800,7 +857,9 @@ void PrepareMouseJoints(PhysStepCtx *ctx)
joint->linear_impulse = VEC2(0, 0); joint->linear_impulse = VEC2(0, 0);
joint->angular_impulse = 0; joint->angular_impulse = 0;
#endif #endif
} else { }
else
{
/* Mark joint for removal */ /* Mark joint for removal */
DisableProp(joint_ent, Prop_Active); DisableProp(joint_ent, Prop_Active);
EnableProp(joint_ent, Prop_Release); EnableProp(joint_ent, Prop_Release);
@ -812,14 +871,16 @@ void WarmStartMouseJoints(PhysStepCtx *ctx)
{ {
__prof; __prof;
Snapshot *ss = ctx->sim_step_ctx->world; Snapshot *ss = ctx->sim_step_ctx->world;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) { for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index)
{
Entity *joint_ent = &ss->ents[sim_ent_index]; Entity *joint_ent = &ss->ents[sim_ent_index];
if (!ShouldSimulate(joint_ent)) continue; if (!ShouldSimulate(joint_ent)) continue;
if (!HasProp(joint_ent, Prop_MouseJoint)) continue; if (!HasProp(joint_ent, Prop_MouseJoint)) continue;
MouseJoint *joint = &joint_ent->mouse_joint_data; MouseJoint *joint = &joint_ent->mouse_joint_data;
Entity *ent = EntityFromId(ss, joint->target); Entity *ent = EntityFromId(ss, joint->target);
if (ShouldSimulate(ent)) { if (ShouldSimulate(ent))
{
f32 inv_m = joint->inv_m; f32 inv_m = joint->inv_m;
f32 inv_i = joint->inv_i; f32 inv_i = joint->inv_i;
Xform xf = XformFromEntity(ent); Xform xf = XformFromEntity(ent);
@ -834,14 +895,16 @@ void SolveMouseJoints(PhysStepCtx *ctx, f32 dt)
{ {
__prof; __prof;
Snapshot *ss = ctx->sim_step_ctx->world; Snapshot *ss = ctx->sim_step_ctx->world;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) { for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index)
{
Entity *joint_ent = &ss->ents[sim_ent_index]; Entity *joint_ent = &ss->ents[sim_ent_index];
if (!ShouldSimulate(joint_ent)) continue; if (!ShouldSimulate(joint_ent)) continue;
if (!HasProp(joint_ent, Prop_MouseJoint)) continue; if (!HasProp(joint_ent, Prop_MouseJoint)) continue;
MouseJoint *joint = &joint_ent->mouse_joint_data; MouseJoint *joint = &joint_ent->mouse_joint_data;
Entity *ent = EntityFromId(ss, joint->target); Entity *ent = EntityFromId(ss, joint->target);
if (ShouldSimulate(ent)) { if (ShouldSimulate(ent))
{
Vec2 v = ent->linear_velocity; Vec2 v = ent->linear_velocity;
f32 w = ent->angular_velocity; f32 w = ent->angular_velocity;
@ -929,7 +992,8 @@ void PrepareWeldJoints(PhysStepCtx *ctx)
{ {
__prof; __prof;
Snapshot *ss = ctx->sim_step_ctx->world; Snapshot *ss = ctx->sim_step_ctx->world;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) { for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index)
{
Entity *joint_ent = &ss->ents[sim_ent_index]; Entity *joint_ent = &ss->ents[sim_ent_index];
if (!ShouldSimulate(joint_ent)) continue; if (!ShouldSimulate(joint_ent)) continue;
if (!HasProp(joint_ent, Prop_WeldJoint)) continue; if (!HasProp(joint_ent, Prop_WeldJoint)) continue;
@ -939,7 +1003,8 @@ void PrepareWeldJoints(PhysStepCtx *ctx)
WeldJoint *joint = &joint_ent->weld_joint_data; WeldJoint *joint = &joint_ent->weld_joint_data;
Entity *e0 = EntityFromId(ss, joint->e0); Entity *e0 = EntityFromId(ss, joint->e0);
Entity *e1 = EntityFromId(ss, joint->e1); Entity *e1 = EntityFromId(ss, joint->e1);
if (ShouldSimulate(e0) && ShouldSimulate(e1)) { if (ShouldSimulate(e0) && ShouldSimulate(e1))
{
Xform e0_xf = XformFromEntity(e0); Xform e0_xf = XformFromEntity(e0);
Xform e1_xf = XformFromEntity(e1); Xform e1_xf = XformFromEntity(e1);
@ -966,7 +1031,9 @@ void PrepareWeldJoints(PhysStepCtx *ctx)
joint->angular_impulse0 = 0; joint->angular_impulse0 = 0;
joint->angular_impulse1 = 0; joint->angular_impulse1 = 0;
#endif #endif
} else { }
else
{
/* Mark joint for removal */ /* Mark joint for removal */
DisableProp(joint_ent, Prop_Active); DisableProp(joint_ent, Prop_Active);
EnableProp(joint_ent, Prop_Release); EnableProp(joint_ent, Prop_Release);
@ -978,7 +1045,8 @@ void WarmStartWeldJoints(PhysStepCtx *ctx)
{ {
__prof; __prof;
Snapshot *ss = ctx->sim_step_ctx->world; Snapshot *ss = ctx->sim_step_ctx->world;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) { for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index)
{
Entity *joint_ent = &ss->ents[sim_ent_index]; Entity *joint_ent = &ss->ents[sim_ent_index];
if (!ShouldSimulate(joint_ent)) continue; if (!ShouldSimulate(joint_ent)) continue;
if (!HasProp(joint_ent, Prop_WeldJoint)) continue; if (!HasProp(joint_ent, Prop_WeldJoint)) continue;
@ -987,7 +1055,8 @@ void WarmStartWeldJoints(PhysStepCtx *ctx)
#if 0 #if 0
Entity *e0 = EntityFromId(ss, joint->e0); Entity *e0 = EntityFromId(ss, joint->e0);
if (ShouldSimulate(e0)) { if (ShouldSimulate(e0))
{
f32 inv_m = joint->inv_m0; f32 inv_m = joint->inv_m0;
f32 inv_i = joint->inv_i0; f32 inv_i = joint->inv_i0;
Xform xf = XformFromEntity(e1); Xform xf = XformFromEntity(e1);
@ -999,7 +1068,8 @@ void WarmStartWeldJoints(PhysStepCtx *ctx)
#if 1 #if 1
Entity *e1 = EntityFromId(ss, joint->e1); Entity *e1 = EntityFromId(ss, joint->e1);
if (ShouldSimulate(e1)) { if (ShouldSimulate(e1))
{
f32 inv_m = joint->inv_m1; f32 inv_m = joint->inv_m1;
f32 inv_i = joint->inv_i1; f32 inv_i = joint->inv_i1;
SetLinearVelocity(e1, AddVec2(e1->linear_velocity, MulVec2(joint->linear_impulse1, inv_m))); SetLinearVelocity(e1, AddVec2(e1->linear_velocity, MulVec2(joint->linear_impulse1, inv_m)));
@ -1015,7 +1085,8 @@ void SolveWeldJoints(PhysStepCtx *ctx, f32 dt)
{ {
__prof; __prof;
Snapshot *ss = ctx->sim_step_ctx->world; Snapshot *ss = ctx->sim_step_ctx->world;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) { for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index)
{
Entity *joint_ent = &ss->ents[sim_ent_index]; Entity *joint_ent = &ss->ents[sim_ent_index];
if (!ShouldSimulate(joint_ent)) continue; if (!ShouldSimulate(joint_ent)) continue;
if (!HasProp(joint_ent, Prop_WeldJoint)) continue; if (!HasProp(joint_ent, Prop_WeldJoint)) continue;
@ -1023,7 +1094,8 @@ void SolveWeldJoints(PhysStepCtx *ctx, f32 dt)
WeldJoint *joint = &joint_ent->weld_joint_data; WeldJoint *joint = &joint_ent->weld_joint_data;
Entity *e0 = EntityFromId(ss, joint->e0); Entity *e0 = EntityFromId(ss, joint->e0);
Entity *e1 = EntityFromId(ss, joint->e1); Entity *e1 = EntityFromId(ss, joint->e1);
if (ShouldSimulate(e0) && ShouldSimulate(e1)) { if (ShouldSimulate(e0) && ShouldSimulate(e1))
{
Xform xf0 = XformFromEntity(e0); Xform xf0 = XformFromEntity(e0);
Xform xf1 = XformFromEntity(e1); Xform xf1 = XformFromEntity(e1);
@ -1094,20 +1166,23 @@ void IntegrateForces(PhysStepCtx *ctx, f32 dt)
{ {
__prof; __prof;
Snapshot *ss = ctx->sim_step_ctx->world; Snapshot *ss = ctx->sim_step_ctx->world;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) { for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index)
{
Entity *ent = &ss->ents[sim_ent_index]; Entity *ent = &ss->ents[sim_ent_index];
if (!ShouldSimulate(ent)) continue; if (!ShouldSimulate(ent)) continue;
b32 is_dynamic = HasProp(ent, Prop_Dynamic); b32 is_dynamic = HasProp(ent, Prop_Dynamic);
b32 is_kinematic = HasProp(ent, Prop_Kinematic); b32 is_kinematic = HasProp(ent, Prop_Kinematic);
if (is_dynamic || is_kinematic) { if (is_dynamic || is_kinematic)
{
Vec2 linear_velocity = ent->linear_velocity; Vec2 linear_velocity = ent->linear_velocity;
f32 angular_velocity = ent->angular_velocity; f32 angular_velocity = ent->angular_velocity;
f32 linear_damping_factor = MaxF32(1.0f - (ent->linear_damping * dt), 0); f32 linear_damping_factor = MaxF32(1.0f - (ent->linear_damping * dt), 0);
f32 angular_damping_factor = MaxF32(1.0f - (ent->angular_damping * dt), 0); f32 angular_damping_factor = MaxF32(1.0f - (ent->angular_damping * dt), 0);
/* Integrate forces */ /* Integrate forces */
if (is_dynamic) { if (is_dynamic)
{
Xform xf = XformFromEntity(ent); Xform xf = XformFromEntity(ent);
f32 det_abs = AbsF32(DeterminantFromXform(xf)); f32 det_abs = AbsF32(DeterminantFromXform(xf));
f32 mass = ent->mass_unscaled * det_abs; f32 mass = ent->mass_unscaled * det_abs;
@ -1136,7 +1211,8 @@ void IntegrateVelocities(PhysStepCtx *ctx, f32 dt)
{ {
__prof; __prof;
Snapshot *ss = ctx->sim_step_ctx->world; Snapshot *ss = ctx->sim_step_ctx->world;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) { for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index)
{
Entity *ent = &ss->ents[sim_ent_index]; Entity *ent = &ss->ents[sim_ent_index];
if (!ShouldSimulate(ent)) continue; if (!ShouldSimulate(ent)) continue;
if (!HasProp(ent, Prop_Dynamic) && !HasProp(ent, Prop_Kinematic)) continue; if (!HasProp(ent, Prop_Dynamic) && !HasProp(ent, Prop_Kinematic)) continue;
@ -1156,7 +1232,8 @@ f32 DetermineEarliestToi(PhysStepCtx *ctx, f32 step_dt, f32 tolerance, u32 max_i
Space *space = ctx->sim_step_ctx->accel->space; Space *space = ctx->sim_step_ctx->accel->space;
f32 smallest_t = 1; f32 smallest_t = 1;
for (u64 e0_index = 0; e0_index < ss->num_ents_reserved; ++e0_index) { for (u64 e0_index = 0; e0_index < ss->num_ents_reserved; ++e0_index)
{
Entity *e0 = &ss->ents[e0_index]; Entity *e0 = &ss->ents[e0_index];
if (!ShouldSimulate(e0)) continue; if (!ShouldSimulate(e0)) continue;
if (!(HasProp(e0, Prop_Solid) || HasProp(e0, Prop_Sensor))) continue; if (!(HasProp(e0, Prop_Solid) || HasProp(e0, Prop_Sensor))) continue;
@ -1174,7 +1251,8 @@ f32 DetermineEarliestToi(PhysStepCtx *ctx, f32 step_dt, f32 tolerance, u32 max_i
SpaceIter iter = space_iter_begin_aabb(space, combined_aabb); SpaceIter iter = space_iter_begin_aabb(space, combined_aabb);
SpaceEntry *entry; SpaceEntry *entry;
while ((entry = space_iter_next(&iter)) != 0) { while ((entry = space_iter_next(&iter)) != 0)
{
Entity *e1 = EntityFromId(ss, entry->ent); Entity *e1 = EntityFromId(ss, entry->ent);
if (!ShouldSimulate(e1)) continue; if (!ShouldSimulate(e1)) continue;
if (!(HasProp(e1, Prop_Solid) || HasProp(e1, Prop_Sensor))) continue; if (!(HasProp(e1, Prop_Solid) || HasProp(e1, Prop_Sensor))) continue;
@ -1186,7 +1264,8 @@ f32 DetermineEarliestToi(PhysStepCtx *ctx, f32 step_dt, f32 tolerance, u32 max_i
Xform e1_xf_t1 = GetDerivedEntityXform(e1, step_dt); Xform e1_xf_t1 = GetDerivedEntityXform(e1, step_dt);
f32 t = CLD_TimeOfImpact(&e0_collider, &e1_collider, e0_xf_t0, e1_xf_t0, e0_xf_t1, e1_xf_t1, tolerance, max_iterations); f32 t = CLD_TimeOfImpact(&e0_collider, &e1_collider, e0_xf_t0, e1_xf_t0, e0_xf_t1, e1_xf_t1, tolerance, max_iterations);
if (t != 0 && t < smallest_t) { if (t != 0 && t < smallest_t)
{
smallest_t = t; smallest_t = t;
} }
} }
@ -1204,13 +1283,16 @@ void UpdateAabbs(PhysStepCtx *ctx)
__prof; __prof;
Snapshot *ss = ctx->sim_step_ctx->world; Snapshot *ss = ctx->sim_step_ctx->world;
Space *space = ctx->sim_step_ctx->accel->space; Space *space = ctx->sim_step_ctx->accel->space;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) { for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index)
{
Entity *ent = &ss->ents[sim_ent_index]; Entity *ent = &ss->ents[sim_ent_index];
if (!IsValidAndActive(ent)) continue; if (!IsValidAndActive(ent)) continue;
if (ent->local_collider.count > 0) { if (ent->local_collider.count > 0)
{
Xform xf = XformFromEntity(ent); Xform xf = XformFromEntity(ent);
SpaceEntry *space_entry = space_entry_from_handle(space, ent->space_handle); SpaceEntry *space_entry = space_entry_from_handle(space, ent->space_handle);
if (!space_entry->valid) { if (!space_entry->valid)
{
space_entry = space_entry_acquire(space, ent->id); space_entry = space_entry_acquire(space, ent->id);
ent->space_handle = space_entry->handle; ent->space_handle = space_entry->handle;
} }
@ -1234,7 +1316,8 @@ void StepPhys(PhysStepCtx *ctx, f32 timestep)
UpdateAabbs(ctx); UpdateAabbs(ctx);
f32 remaining_dt = timestep; f32 remaining_dt = timestep;
while (remaining_dt > 0) { while (remaining_dt > 0)
{
__profn("Step part"); __profn("Step part");
++phys_iteration; ++phys_iteration;
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
@ -1262,7 +1345,8 @@ void StepPhys(PhysStepCtx *ctx, f32 timestep)
PrepareWeldJoints(ctx); PrepareWeldJoints(ctx);
f32 substep_dt = step_dt / SIM_PHYSICS_SUBSTEPS; f32 substep_dt = step_dt / SIM_PHYSICS_SUBSTEPS;
for (u32 i = 0; i < SIM_PHYSICS_SUBSTEPS; ++i) { for (u32 i = 0; i < SIM_PHYSICS_SUBSTEPS; ++i)
{
__profn("Substep"); __profn("Substep");
/* Warm start */ /* Warm start */

File diff suppressed because it is too large Load Diff

View File

@ -1,41 +1,31 @@
#define SIM_CLIENT_NIL_HANDLE ((ClientHandle) { .gen = 0, .idx = 0 }) ////////////////////////////////
//~ Id types
/* Absolute layers */ Struct(EntityId)
#define SIM_LAYER_FLOOR_DECALS (-300) {
#define SIM_LAYER_BULLETS (-200)
#define SIM_LAYER_TRACERS (-100)
#define SIM_LAYER_SHOULDERS (0)
#define SIM_LAYER_WALLS (100)
/* Relative layers */
#define SIM_LAYER_RELATIVE_DEFAULT (0)
#define SIM_LAYER_RELATIVE_WEAPON (1)
Struct(EntityId) {
Uid uid; Uid uid;
}; };
Struct(ClientHandle) { Struct(ClientHandle)
{
u32 idx; u32 idx;
u32 gen; u32 gen;
}; };
/* ========================== * #define SIM_CLIENT_NIL_HANDLE ((ClientHandle) { .gen = 0, .idx = 0 })
* Startup
* ========================== */
void StartupSim(void);
/* ========================== * ////////////////////////////////
* Client store //~ Client store types
* ========================== */
Struct(ClientLookupBin) { Struct(ClientLookupBin)
{
struct ClientHandle first; struct ClientHandle first;
struct ClientHandle last; struct ClientHandle last;
}; };
Struct(ClientStore) { Struct(ClientStore)
{
b32 valid; b32 valid;
Arena *arena; Arena *arena;
@ -57,19 +47,17 @@ Inline ClientStore *sim_client_store_nil(void)
return *_g_sim_client_store_nil; return *_g_sim_client_store_nil;
} }
ClientStore *sim_client_store_acquire(void); ////////////////////////////////
void sim_client_store_release(ClientStore *store); //~ Client types
/* ========================== * Struct(SnapshotLookupBin)
* Client {
* ========================== */
Struct(SnapshotLookupBin) {
struct Snapshot *first; struct Snapshot *first;
struct Snapshot *last; struct Snapshot *last;
}; };
Struct(Client) { Struct(Client)
{
b32 valid; b32 valid;
ClientHandle handle; ClientHandle handle;
ClientStore *store; ClientStore *store;
@ -122,22 +110,25 @@ Inline b32 sim_client_handle_eq(ClientHandle a, ClientHandle b)
return a.gen == b.gen && a.idx == b.idx; return a.gen == b.gen && a.idx == b.idx;
} }
Client *sim_client_acquire(ClientStore *store); ////////////////////////////////
void sim_client_release(Client *client); //~ Layer types
Client *sim_client_from_channel_id(ClientStore *store, N_ChannelId channel_id); /* Absolute layers */
void sim_client_set_channel_id(Client *client, N_ChannelId channel_id); #define SIM_LAYER_FLOOR_DECALS (-300)
Client *sim_client_from_handle(ClientStore *store, ClientHandle handle); #define SIM_LAYER_BULLETS (-200)
#define SIM_LAYER_TRACERS (-100)
#define SIM_LAYER_SHOULDERS (0)
#define SIM_LAYER_WALLS (100)
/* ========================== * /* Relative layers */
* Snapshot #define SIM_LAYER_RELATIVE_DEFAULT (0)
* ========================== */ #define SIM_LAYER_RELATIVE_WEAPON (1)
typedef i32 SyncFlag; enum { ////////////////////////////////
SIM_SYNC_FLAG_NOSYNC_PREDICTABLES = 1 << 0 //~ Control types
};
typedef i32 ControlFlag; enum { typedef i32 ControlFlag; enum
{
SIM_CONTROL_FLAG_FIRE = 1 << 0, SIM_CONTROL_FLAG_FIRE = 1 << 0,
SIM_CONTROL_FLAG_FIRE_ALT = 1 << 1, SIM_CONTROL_FLAG_FIRE_ALT = 1 << 1,
@ -155,22 +146,27 @@ typedef i32 ControlFlag; enum {
SIM_CONTROL_FLAG_TELEPORT_TEST = 1 << 12, SIM_CONTROL_FLAG_TELEPORT_TEST = 1 << 12,
}; };
Struct(ControlData) { Struct(ControlData)
{
Vec2 move; /* Movement direction vector (speed of 0 -> 1) */ Vec2 move; /* Movement direction vector (speed of 0 -> 1) */
Vec2 focus; /* Focus direction vector (where does the controller want to look) */ Vec2 focus; /* Focus direction vector (where does the controller want to look) */
Vec2 dbg_cursor; /* Where is the user's cursor in the world (used for things like editing the world) */ Vec2 dbg_cursor; /* Where is the user's cursor in the world (used for things like editing the world) */
ControlFlag flags; ControlFlag flags;
}; };
typedef i32 CmdKind; enum { typedef i32 CmdKind; enum
{
SIM_CMD_KIND_INVALID, SIM_CMD_KIND_INVALID,
SIM_CMD_KIND_CONTROL, SIM_CMD_KIND_CONTROL,
SIM_CMD_KIND_CHAT SIM_CMD_KIND_CHAT
}; };
////////////////////////////////
//~ Tile types
typedef i32 TileKind; enum { typedef i32 TileKind; enum
{
SIM_TILE_KIND_NONE, SIM_TILE_KIND_NONE,
SIM_TILE_KIND_WALL, SIM_TILE_KIND_WALL,
@ -178,7 +174,16 @@ typedef i32 TileKind; enum {
}; };
StaticAssert(NUM_SIM_TILE_KINDS < 256); /* Tile kind must fit in 8 bits */ StaticAssert(NUM_SIM_TILE_KINDS < 256); /* Tile kind must fit in 8 bits */
Struct(Snapshot) { ////////////////////////////////
//~ Snapshot types
typedef i32 SyncFlag; enum
{
SIM_SYNC_FLAG_NOSYNC_PREDICTABLES = 1 << 0
};
Struct(Snapshot)
{
b32 valid; b32 valid;
u64 tick; u64 tick;
Client *client; Client *client;
@ -221,17 +226,77 @@ Inline Snapshot *sim_snapshot_nil(void)
return *_g_sim_snapshot_nil; return *_g_sim_snapshot_nil;
} }
/* Acquire */ ////////////////////////////////
//~ Shared state
#define CLIENT_LOOKUP_BINS 127
#define TICK_LOOKUP_BINS 127
#define ID_LOOKUP_BINS 4096
Struct(SharedSimCtx)
{
Arena *nil_arena;
ClientStore *nil_client_store;
Client *nil_client;
Snapshot *nil_snapshot;
struct Entity *nil_ent;
};
extern SharedSimCtx shared_sim_ctx;
/* Accessed via `sim_client_store_nil()` */
extern Readonly ClientStore **_g_sim_client_store_nil;
/* Accessed via `sim_client_nil()` */
extern Readonly Client **_g_sim_client_nil;
/* Accessed via `sim_snapshot_nil()` */
extern Readonly Snapshot **_g_sim_snapshot_nil;
extern Readonly struct Entity **_g_sim_ent_nil;
////////////////////////////////
//~ Startup
void StartupSim(void);
////////////////////////////////
//~ Client store acquire operations
ClientStore *sim_client_store_acquire(void);
void sim_client_store_release(ClientStore *store);
////////////////////////////////
//~ Client acquire operations
Client *sim_client_acquire(ClientStore *store);
void sim_client_release(Client *client);
////////////////////////////////
//~ Client lookup operations
u64 client_channel_hash_hash_from_channel_id(N_ChannelId channel_id);
void sim_client_set_channel_id(Client *client, N_ChannelId channel_id);
Client *sim_client_from_channel_id(ClientStore *store, N_ChannelId channel_id);
Client *sim_client_from_handle(ClientStore *store, ClientHandle handle);
////////////////////////////////
//~ Snapshot acquire operations
Snapshot *sim_snapshot_acquire(Client *client, Snapshot *src, u64 tick); Snapshot *sim_snapshot_acquire(Client *client, Snapshot *src, u64 tick);
void sim_snapshot_release(Snapshot *sim_snapshot); void sim_snapshot_release(Snapshot *ss);
void sim_snapshot_release_ticks_in_range(Client *client, u64 start, u64 end); void sim_snapshot_release_ticks_in_range(Client *client, u64 start, u64 end);
/* Lookup */ ////////////////////////////////
//~ Snapshot lookup operations
Snapshot *sim_snapshot_from_tick(Client *client, u64 tick); Snapshot *sim_snapshot_from_tick(Client *client, u64 tick);
Snapshot *sim_snapshot_from_closest_tick_lte(Client *client, u64 tick); Snapshot *sim_snapshot_from_closest_tick_lte(Client *client, u64 tick);
Snapshot *sim_snapshot_from_closest_tick_gte(Client *client, u64 tick); Snapshot *sim_snapshot_from_closest_tick_gte(Client *client, u64 tick);
/* Tile */ ////////////////////////////////
//~ Tile operations
Vec2I32 sim_world_tile_index_from_pos(Vec2 pos); Vec2I32 sim_world_tile_index_from_pos(Vec2 pos);
Vec2 sim_pos_from_world_tile_index(Vec2I32 world_tile_index); Vec2 sim_pos_from_world_tile_index(Vec2I32 world_tile_index);
Vec2I32 sim_local_tile_index_from_world_tile_index(Vec2I32 world_tile_index); Vec2I32 sim_local_tile_index_from_world_tile_index(Vec2I32 world_tile_index);
@ -239,12 +304,22 @@ Vec2I32 sim_world_tile_index_from_local_tile_index(Vec2I32 tile_chunk_index, Vec
Vec2I32 sim_tile_chunk_index_from_world_tile_index(Vec2I32 world_tile_index); Vec2I32 sim_tile_chunk_index_from_world_tile_index(Vec2I32 world_tile_index);
void sim_snapshot_set_tile(Snapshot *ss, Vec2I32 world_tile_index, TileKind tile_kind); void sim_snapshot_set_tile(Snapshot *ss, Vec2I32 world_tile_index, TileKind tile_kind);
/* Lerp */ ////////////////////////////////
//~ Snapshot lerp operations
Snapshot *sim_snapshot_acquire_from_lerp(Client *client, Snapshot *ss0, Snapshot *ss1, f64 blend); Snapshot *sim_snapshot_acquire_from_lerp(Client *client, Snapshot *ss0, Snapshot *ss1, f64 blend);
/* Sync */ ////////////////////////////////
//~ Snapshot sync operations
void sim_snapshot_sync_ents(Snapshot *local_ss, Snapshot *remote_ss, EntityId remote_player, u32 sync_flags); void sim_snapshot_sync_ents(Snapshot *local_ss, Snapshot *remote_ss, EntityId remote_player, u32 sync_flags);
/* Encode / decode */ ////////////////////////////////
//~ Snapshot encode operations
void sim_snapshot_encode(BB_Writer *bw, Client *receiver, Snapshot *ss0, Snapshot *ss1); void sim_snapshot_encode(BB_Writer *bw, Client *receiver, Snapshot *ss0, Snapshot *ss1);
////////////////////////////////
//~ Snapshot decode operations
void sim_snapshot_decode(BB_Reader *br, Snapshot *ss); void sim_snapshot_decode(BB_Reader *br, Snapshot *ss);

File diff suppressed because it is too large Load Diff

View File

@ -4,8 +4,8 @@
/* Structure used to accelerate up entity lookup (rebuilt every step) */ /* Structure used to accelerate up entity lookup (rebuilt every step) */
/* TODO: Remove this and do something better. Just a hack to de-couple old sim ctx from step. */ /* TODO: Remove this and do something better. Just a hack to de-couple old sim ctx from step. */
typedef struct SimAccel SimAccel; Struct(SimAccel)
struct SimAccel { {
Space *space; Space *space;
}; };
@ -13,7 +13,8 @@ struct SimAccel {
//~ Step ctx //~ Step ctx
typedef struct SimStepCtx SimStepCtx; typedef struct SimStepCtx SimStepCtx;
struct SimStepCtx { struct SimStepCtx
{
b32 is_master; b32 is_master;
SimAccel *accel; SimAccel *accel;
RandState rand; /* TODO: Replace with per-sim rand for deterministic rng */ RandState rand; /* TODO: Replace with per-sim rand for deterministic rng */