remove entity tree

This commit is contained in:
jacob 2025-12-16 16:37:35 -06:00
parent ed5e95d6d4
commit af3687f3e5
3 changed files with 68 additions and 272 deletions

View File

@ -1,9 +1,7 @@
S_SharedState S_shared_state = ZI;
Readonly S_Ent S_nil_ent = {
.local_xf = CompXformIdentity,
.world_xf = CompXformIdentity,
.tint = { 0.5, 0.5, 0.5, 1 },
.xf = CompXformIdentity
};
////////////////////////////////////////////////////////////
@ -168,86 +166,29 @@ S_Ent *S_EntFromKey(S_Lookup *lookup, S_Key key)
////////////////////////////////////////////////////////////
//~ Iteration helpers
S_Ent *S_FirstEntEx(Arena *arena, S_Iter *iter, S_Lookup *lookup, S_Key key, S_IterKind kind)
S_Ent *S_FirstEnt(S_Iter *iter, S_World *world)
{
iter->kind = kind;
iter->lookup = lookup;
for (S_IterDfsNode *n = iter->first_dfs; n; n = n->next)
{
n->next = iter->first_free_dfs;
iter->first_free_dfs = n;
}
iter->first_dfs = 0;
{
S_IterDfsNode *n = iter->first_free_dfs;
if (n)
{
SllStackPop(iter->first_free_dfs);
ZeroStruct(n);
}
else
{
n = PushStruct(arena, S_IterDfsNode);
}
n->ent_key = key;
SllStackPush(iter->first_dfs, n);
}
return S_NextEnt(arena, iter);
ZeroStruct(iter);
iter->world = world;
return S_NextEnt(iter);
}
S_Ent *S_NextEnt(Arena *arena, S_Iter *iter)
S_Ent *S_NextEnt(S_Iter *iter)
{
S_World *world = iter->world;
S_Ent *result = &S_nil_ent;
S_Lookup *lookup = iter->lookup;
b32 is_post_order = iter->kind == S_IterKind_Post;
b32 stop = 0;
while (!stop)
i64 ent_idx = iter->cur_idx;
for (; ent_idx < world->ents_count; ++ent_idx)
{
if (iter->first_dfs)
S_Ent *ent = &world->ents[ent_idx];
if (ent->active)
{
S_IterDfsNode *n = iter->first_dfs;
S_Ent *ent = S_EntFromKey(iter->lookup, n->ent_key);
if (!n->visited)
{
/* Push children to dfs stack */
for (S_Ent *child = S_EntFromKey(lookup, ent->last); !S_IsEntNil(child); child = S_EntFromKey(lookup, child->prev))
{
S_IterDfsNode *child_n = iter->first_free_dfs;
if (child_n)
{
SllStackPop(iter->first_free_dfs);
ZeroStruct(child_n);
}
else
{
child_n = PushStruct(arena, S_IterDfsNode);
}
child_n->ent_key = child->key;
SllStackPush(iter->first_dfs, child_n);
}
n->visited = 1;
if (!is_post_order)
{
result = ent;
stop = 1;
}
}
else
{
SllStackPop(iter->first_dfs);
if (is_post_order)
{
result = ent;
stop = 1;
}
}
}
else
{
stop = 1;
result = ent;
break;
}
}
iter->cur_idx = ent_idx + 1;
return result;
}
@ -323,17 +264,6 @@ void S_TickForever(WaveLaneCtx *lane)
f64 sim_dt = SecondsFromNs(sim_dt_ns);
world->tick += 1;
//////////////////////////////
//- Create root ent
if (world->tick == 1)
{
S_Ent *root_ent = PushStruct(ents_arena, S_Ent);
*root_ent = S_nil_ent;
root_ent->key = S_RootKey;
root_ent->active = 1;
++world->ents_count;
}
lookup = S_LookupFromWorld(frame_arena, world);
//////////////////////////////
@ -362,12 +292,8 @@ void S_TickForever(WaveLaneCtx *lane)
for (S_EntListNode *src_n = cmd.ents.first; src_n; src_n = src_n->next)
{
S_Ent *src = &src_n->ent;
if (S_IsKeyNil(src->parent))
{
src->parent = S_RootKey;
}
S_Key key = src->key;
if (!S_MatchKey(key, S_RootKey) && !S_IsKeyNil(key))
if (!S_IsKeyNil(key))
{
S_Ent *dst = S_EntFromKey(&lookup, key);
if (S_IsEntNil(dst))
@ -396,84 +322,6 @@ void S_TickForever(WaveLaneCtx *lane)
}
lookup = S_LookupFromWorld(frame_arena, world);
//////////////////////////////
//- Build entity tree
{
/* Reset tree links */
for (i64 ent_idx = 0; ent_idx < world->ents_count; ++ent_idx)
{
S_Ent *ent = &world->ents[ent_idx];
if (ent->active)
{
ent->first = S_NilKey;
ent->last = S_NilKey;
ent->next = S_NilKey;
ent->prev = S_NilKey;
ent->count = 0;
}
}
{
/* Sort ents by key before tree-build (for deterministic child order in parents) */
S_Ent **sorted_ents = 0;
{
sorted_ents = PushStructsNoZero(frame_arena, S_Ent *, world->ents_count);
for (i64 ent_idx = 0; ent_idx < world->ents_count; ++ent_idx)
{
sorted_ents[ent_idx] = &world->ents[ent_idx];
}
Mergesort(sorted_ents, world->ents_count, sizeof(*sorted_ents), S_SortEntsByKeyCmp, 0);
}
/* Build tree */
for (i64 ent_idx = 0; ent_idx < world->ents_count; ++ent_idx)
{
S_Ent *ent = sorted_ents[ent_idx];
if (ent->active)
{
S_Key key = ent->key;
S_Ent *parent = S_EntFromKey(&lookup, ent->parent);
if (parent->active)
{
S_Ent *prev = S_EntFromKey(&lookup, parent->last);
if (S_IsEntNil(prev))
{
parent->first = key;
}
else
{
prev->next = key;
}
ent->prev = prev->key;
parent->last = key;
++parent->count;
}
}
}
}
/* Prune dangling ents */
/* NOTE: If only the top level of a multi-level ent tree is
* dangling, the children may be marked inactive one level per tick
* since iteration is linear over the array. */
for (i64 ent_idx = 0; ent_idx < world->ents_count; ++ent_idx)
{
S_Ent *ent = &world->ents[ent_idx];
if (ent->active && !S_MatchKey(ent->key, S_RootKey))
{
S_Ent *parent = S_EntFromKey(&lookup, ent->parent);
if (!parent->active)
{
ent->active = 0;
ent->next_free_ent_num = first_free_ent_num;
first_free_ent_num = ent_idx + 1;
}
}
}
}
lookup = S_LookupFromWorld(frame_arena, world);
//////////////////////////////
//- Update ent controls
@ -494,30 +342,26 @@ void S_TickForever(WaveLaneCtx *lane)
//////////////////////////////
//- Apply control forces
for (S_Ent *ent = S_FirstEnt(frame_arena, &iter, &lookup); ent->active; ent = S_NextEnt(frame_arena, &iter))
for (S_Ent *ent = S_FirstEnt(&iter, world); ent->active; ent = S_NextEnt(&iter))
{
Xform xf = ent->local_xf;
if (!IsVec2Zero(ent->move))
{
DEBUGBREAKABLE;
}
Xform xf = ent->xf;
if (!IsVec2Zero(ent->look))
{
xf = XformWithWorldRotation(xf, AngleFromVec2(ent->look));
}
xf.og = AddVec2(xf.og, MulVec2(ent->move, ent->move_speed));
ent->local_xf = xf;
}
//////////////////////////////
//- Compute pre-solve world transforms
for (S_Ent *ent = S_FirstEnt(frame_arena, &iter, &lookup); ent->active; ent = S_NextEnt(frame_arena, &iter))
{
ent->old_world_xf = ent->world_xf;
ent->world_xf = MulXform(S_EntFromKey(&lookup, ent->parent)->world_xf, ent->local_xf);
ent->xf = xf;
}
//////////////////////////////
//- Solve followers
for (S_Ent *ent = S_FirstEnt(frame_arena, &iter, &lookup); ent->active; ent = S_NextEnt(frame_arena, &iter))
for (S_Ent *ent = S_FirstEnt(&iter, world); ent->active; ent = S_NextEnt(&iter))
{
S_Ent *follow = S_EntFromKey(&lookup, ent->follow);
if (follow->active)
@ -527,24 +371,15 @@ void S_TickForever(WaveLaneCtx *lane)
look_ratio.y = 0.25;
look_ratio.x = look_ratio.y / (16.0 / 9.0);
Vec2 target = MulXformV2(follow->world_xf, follow->local_shape.centroid);
Vec2 target = MulXformV2(follow->xf, follow->local_shape.centroid);
target = AddVec2(target, MulVec2Vec2(follow->look, look_ratio));
Xform xf = ent->local_xf;
// xf.og = AddVec2(xf.og, SubVec2(follow->world_xf.og, follow->old_world_xf.og));
Xform xf = ent->xf;
xf.og = LerpVec2(xf.og, target, follow_speed);
ent->local_xf = xf;
ent->xf = xf;
}
}
//////////////////////////////
//- Compute post-solve world transforms
for (S_Ent *ent = S_FirstEnt(frame_arena, &iter, &lookup); ent->active; ent = S_NextEnt(frame_arena, &iter))
{
ent->world_xf = MulXform(S_EntFromKey(&lookup, ent->parent)->world_xf, ent->local_xf);
}
//////////////////////////////
//- Publish sim state

View File

@ -2,7 +2,6 @@
//~ Key types
#define S_NilKey ((S_Key) { 0 })
#define S_RootKey ((S_Key) { .v.hi = 0xaaaaaaaaaaaaaaaa, .v.lo = 0xaaaaaaaaaaaaaaaa })
Struct(S_Key)
{
@ -38,16 +37,6 @@ Struct(S_Shape)
Struct(S_Ent)
{
//////////////////////////////
//- Tree links
S_Key parent;
S_Key first;
S_Key last;
S_Key next;
S_Key prev;
u64 count;
//////////////////////////////
//- Persistent data
@ -57,29 +46,18 @@ Struct(S_Ent)
//////////////////////////////
//- Build data
Xform local_xf;
Vec4 tint;
Xform xf;
S_Shape local_shape;
S_Key follow;
S_Key camera;
S_Shape local_shape;
f32 move_speed;
Vec2 move;
Vec2 look;
//////////////////////////////
//- Pre-solve data
Xform old_world_xf;
//////////////////////////////
//- Post-solve data
Xform world_xf;
b32 has_weapon;
//////////////////////////////
//- Internal sim data
@ -151,25 +129,10 @@ Struct(S_SnapshotNode)
////////////////////////////////////////////////////////////
//~ Iterator types
Enum(S_IterKind)
{
S_IterKind_Pre,
S_IterKind_Post,
};
Struct(S_IterDfsNode)
{
S_IterDfsNode *next;
b32 visited;
S_Key ent_key;
};
Struct(S_Iter)
{
S_IterKind kind;
S_Lookup *lookup;
S_IterDfsNode *first_dfs;
S_IterDfsNode *first_free_dfs;
S_World *world;
i64 cur_idx;
};
////////////////////////////////////////////////////////////
@ -278,9 +241,8 @@ S_Ent *S_EntFromKey(S_Lookup *lookup, S_Key key);
////////////////////////////////////////////////////////////
//~ Iteration helpers
#define S_FirstEnt(arena, iter, lookup) S_FirstEntEx((arena), (iter), (lookup), S_RootKey, S_IterKind_Pre)
S_Ent *S_FirstEntEx(Arena *arena, S_Iter *iter, S_Lookup *lookup, S_Key key, S_IterKind kind);
S_Ent *S_NextEnt(Arena *arena, S_Iter *iter);
S_Ent *S_FirstEnt(S_Iter *iter, S_World *world);
S_Ent *S_NextEnt(S_Iter *iter);
////////////////////////////////////////////////////////////
//~ Snapshot helpers

View File

@ -152,7 +152,7 @@ void V_TickForever(WaveLaneCtx *lane)
S_Key child_key = S_RandKey();
S_Key camera_key = S_RandKey();
i32 count = 3;
i32 count = 2;
for (u64 i = 0; i < count; ++i)
{
S_EntListNode *n = PushStruct(frame->arena, S_EntListNode);
@ -165,7 +165,6 @@ void V_TickForever(WaveLaneCtx *lane)
/* Test player */
case 0:
{
ent->tint = Color_Red;
ent->key = V.player_key;
ent->camera = camera_key;
ent->move_speed = 0.1;
@ -177,32 +176,12 @@ void V_TickForever(WaveLaneCtx *lane)
);
}
// ent->local_xf = XformFromPos(VEC2(200, 200));
ent->local_xf = XformFromPos(VEC2(0, 0));
} break;
/* Test child */
case 1:
{
f32 width = 0.1;
f32 height = 1;
ent->tint = Color_Cyan;
ent->key = child_key;
ent->parent = V.player_key;
{
ent->local_shape = S_ShapeFromDesc(
.count = 4,
.points = {
VEC2(-width / 2, -height), VEC2(width / 2, -height),
VEC2(width / 2, 0), VEC2(-width / 2, 0),
}
);
}
ent->local_xf = XformFromTrs(TRS(.t = { 0, 0 }, .r = Tau / 4));
ent->xf = XformFromPos(VEC2(0, 0));
ent->has_weapon = 1;
} break;
/* Test camera */
case 2:
case 1:
{
ent->key = camera_key;
ent->follow = V.player_key;
@ -286,7 +265,7 @@ void V_TickForever(WaveLaneCtx *lane)
{
S_Ent *player = S_EntFromKey(&V.lookup, V.player_key);
S_Ent *camera = S_EntFromKey(&V.lookup, player->camera);
camera_pos = MulXformV2(camera->world_xf, camera->local_shape.centroid);
camera_pos = MulXformV2(camera->xf, camera->local_shape.centroid);
}
//////////////////////////////
@ -531,7 +510,7 @@ void V_TickForever(WaveLaneCtx *lane)
Vec2 look = ZI;
{
S_Ent *player = S_EntFromKey(&V.lookup, V.player_key);
Vec2 center = MulXformV2(player->world_xf, player->local_shape.centroid);
Vec2 center = MulXformV2(player->xf, player->local_shape.centroid);
look = SubVec2(world_cursor, center);
}
cmd->target = V.player_key;
@ -572,19 +551,39 @@ void V_TickForever(WaveLaneCtx *lane)
//- Build render data
/* Build shape buffers */
for (S_Ent *ent = S_FirstEnt(frame->arena, &iter, &V.lookup); ent->active; ent = S_NextEnt(frame->arena, &iter))
for (S_Ent *ent = S_FirstEnt(&iter, V.world); ent->active; ent = S_NextEnt(&iter))
{
Xform ent_to_world_xf = ent->world_xf;
Xform ent_to_world_xf = ent->xf;
Xform ent_to_draw_xf = MulXform(world_to_draw_xf, ent_to_world_xf);
/* Draw shape */
b32 is_visible = ent->tint.w != 0;
b32 is_visible = 1;
if (is_visible)
{
Vec4 color = ent->tint;
i32 detail = 32;
S_Shape shape = S_MulXformShape(ent_to_draw_xf, ent->local_shape);
V_DrawShape(frame->dverts_arena, frame->dvert_idxs_arena, shape, LinearFromSrgb(color), detail, V_DrawFlag_Line);
/* Draw shape */
{
Vec4 color = Color_Purple;
i32 detail = 32;
S_Shape shape = S_MulXformShape(ent_to_draw_xf, ent->local_shape);
V_DrawShape(frame->dverts_arena, frame->dvert_idxs_arena, shape, LinearFromSrgb(color), detail, V_DrawFlag_Line);
}
/* Draw weapon */
if (ent->has_weapon)
{
Vec4 color = Color_Cyan;
f32 width = 0.1;
f32 height = 1;
S_Shape local_shape = S_ShapeFromDesc(
.count = 4,
.points = {
VEC2(-width / 2, -height), VEC2(width / 2, -height),
VEC2(width / 2, 0), VEC2(-width / 2, 0),
}
);
Xform local_xf = XformFromTrs(TRS(.t = { 0, 0 }, .r = Tau / 4));
Xform xf = MulXform(ent_to_draw_xf, local_xf);
S_Shape shape = S_MulXformShape(xf, local_shape);
V_DrawShape(frame->dverts_arena, frame->dvert_idxs_arena, shape, LinearFromSrgb(color), 10, V_DrawFlag_Line);
}
}
}