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; S_SharedState S_shared_state = ZI;
Readonly S_Ent S_nil_ent = { Readonly S_Ent S_nil_ent = {
.local_xf = CompXformIdentity, .xf = CompXformIdentity
.world_xf = CompXformIdentity,
.tint = { 0.5, 0.5, 0.5, 1 },
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -168,86 +166,29 @@ S_Ent *S_EntFromKey(S_Lookup *lookup, S_Key key)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Iteration helpers //~ 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; ZeroStruct(iter);
iter->lookup = lookup; iter->world = world;
for (S_IterDfsNode *n = iter->first_dfs; n; n = n->next) return S_NextEnt(iter);
{
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);
} }
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_Ent *result = &S_nil_ent;
S_Lookup *lookup = iter->lookup;
b32 is_post_order = iter->kind == S_IterKind_Post;
b32 stop = 0; i64 ent_idx = iter->cur_idx;
while (!stop) 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; result = ent;
stop = 1; break;
}
}
else
{
SllStackPop(iter->first_dfs);
if (is_post_order)
{
result = ent;
stop = 1;
}
}
}
else
{
stop = 1;
} }
} }
iter->cur_idx = ent_idx + 1;
return result; return result;
} }
@ -323,17 +264,6 @@ void S_TickForever(WaveLaneCtx *lane)
f64 sim_dt = SecondsFromNs(sim_dt_ns); f64 sim_dt = SecondsFromNs(sim_dt_ns);
world->tick += 1; 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); 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) for (S_EntListNode *src_n = cmd.ents.first; src_n; src_n = src_n->next)
{ {
S_Ent *src = &src_n->ent; S_Ent *src = &src_n->ent;
if (S_IsKeyNil(src->parent))
{
src->parent = S_RootKey;
}
S_Key key = src->key; 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); S_Ent *dst = S_EntFromKey(&lookup, key);
if (S_IsEntNil(dst)) if (S_IsEntNil(dst))
@ -396,84 +322,6 @@ void S_TickForever(WaveLaneCtx *lane)
} }
lookup = S_LookupFromWorld(frame_arena, world); 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 //- Update ent controls
@ -494,30 +342,26 @@ void S_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Apply control forces //- 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)) if (!IsVec2Zero(ent->look))
{ {
xf = XformWithWorldRotation(xf, AngleFromVec2(ent->look)); xf = XformWithWorldRotation(xf, AngleFromVec2(ent->look));
} }
xf.og = AddVec2(xf.og, MulVec2(ent->move, ent->move_speed)); xf.og = AddVec2(xf.og, MulVec2(ent->move, ent->move_speed));
ent->local_xf = xf; ent->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);
} }
////////////////////////////// //////////////////////////////
//- Solve followers //- 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); S_Ent *follow = S_EntFromKey(&lookup, ent->follow);
if (follow->active) if (follow->active)
@ -527,24 +371,15 @@ void S_TickForever(WaveLaneCtx *lane)
look_ratio.y = 0.25; look_ratio.y = 0.25;
look_ratio.x = look_ratio.y / (16.0 / 9.0); 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)); target = AddVec2(target, MulVec2Vec2(follow->look, look_ratio));
Xform xf = ent->local_xf; Xform xf = ent->xf;
// xf.og = AddVec2(xf.og, SubVec2(follow->world_xf.og, follow->old_world_xf.og));
xf.og = LerpVec2(xf.og, target, follow_speed); 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 //- Publish sim state

View File

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

View File

@ -152,7 +152,7 @@ void V_TickForever(WaveLaneCtx *lane)
S_Key child_key = S_RandKey(); S_Key child_key = S_RandKey();
S_Key camera_key = S_RandKey(); S_Key camera_key = S_RandKey();
i32 count = 3; i32 count = 2;
for (u64 i = 0; i < count; ++i) for (u64 i = 0; i < count; ++i)
{ {
S_EntListNode *n = PushStruct(frame->arena, S_EntListNode); S_EntListNode *n = PushStruct(frame->arena, S_EntListNode);
@ -165,7 +165,6 @@ void V_TickForever(WaveLaneCtx *lane)
/* Test player */ /* Test player */
case 0: case 0:
{ {
ent->tint = Color_Red;
ent->key = V.player_key; ent->key = V.player_key;
ent->camera = camera_key; ent->camera = camera_key;
ent->move_speed = 0.1; 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(200, 200));
ent->local_xf = XformFromPos(VEC2(0, 0)); ent->xf = XformFromPos(VEC2(0, 0));
} break; ent->has_weapon = 1;
/* 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));
} break; } break;
/* Test camera */ /* Test camera */
case 2: case 1:
{ {
ent->key = camera_key; ent->key = camera_key;
ent->follow = V.player_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 *player = S_EntFromKey(&V.lookup, V.player_key);
S_Ent *camera = S_EntFromKey(&V.lookup, player->camera); 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; Vec2 look = ZI;
{ {
S_Ent *player = S_EntFromKey(&V.lookup, V.player_key); 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); look = SubVec2(world_cursor, center);
} }
cmd->target = V.player_key; cmd->target = V.player_key;
@ -572,20 +551,40 @@ void V_TickForever(WaveLaneCtx *lane)
//- Build render data //- Build render data
/* Build shape buffers */ /* 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); Xform ent_to_draw_xf = MulXform(world_to_draw_xf, ent_to_world_xf);
/* Draw shape */ b32 is_visible = 1;
b32 is_visible = ent->tint.w != 0;
if (is_visible) if (is_visible)
{ {
Vec4 color = ent->tint; /* Draw shape */
{
Vec4 color = Color_Purple;
i32 detail = 32; i32 detail = 32;
S_Shape shape = S_MulXformShape(ent_to_draw_xf, ent->local_shape); 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); 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);
}
}
} }
////////////////////////////// //////////////////////////////