build ent tree every frame

This commit is contained in:
jacob 2025-11-13 18:27:49 -06:00
parent 05a84ddd5a
commit df2f7f0f1b
4 changed files with 349 additions and 124 deletions

View File

@ -57,6 +57,17 @@ b32 S_MatchKey(S_Key a, S_Key b)
return a.v.hi == b.v.hi && a.v.lo == b.v.lo; return a.v.hi == b.v.hi && a.v.lo == b.v.lo;
} }
////////////////////////////////////////////////////////////
//~ Key helpers
S_Key S_RandKey(void)
{
/* TODO: Don't use true randomness for entity keys. It's overkill & non-deterministic. */
S_Key result = ZI;
TrueRand(StringFromStruct(&result));
return result;
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Shape helpers //~ Shape helpers
@ -93,31 +104,57 @@ Vec2 S_SupportPointFromShape(S_Shape shape, Vec2 dir)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Lookup helpers //~ Lookup helpers
S_Ent *S_EntFromKey(S_World *world, S_Key key) S_Lookup S_LookupFromWorld(Arena *arena, S_World *world)
{ {
S_Ent *ent = &S_nil_ent; S_Lookup lookup = ZI;
lookup.bins_count = 4096;
lookup.bins = PushStructs(arena, S_LookupEntNode *, lookup.bins_count);
for (i64 ent_idx = 0; ent_idx < world->ents_count; ++ent_idx)
{
S_Ent *ent = &world->ents[ent_idx];
if (ent->active)
{
S_Key key = ent->key;
S_LookupEntNode *n = PushStruct(arena, S_LookupEntNode);
n->ent = ent;
S_LookupEntNode **bin = &lookup.bins[ent->key.v.lo % lookup.bins_count];
SllStackPush(*bin, n);
}
}
return lookup;
}
S_Ent *S_EntFromKey(S_Lookup *lookup, S_Key key)
{
S_Ent *result = &S_nil_ent;
if (!S_IsKeyNil(key)) if (!S_IsKeyNil(key))
{ {
S_EntLookupNode *n = world->ent_bins[key.v.lo % world->ent_bins_count]; i64 bins_count = lookup->bins_count;
if (bins_count > 0)
{
S_LookupEntNode *n = lookup->bins[key.v.lo % bins_count];
for (; n; n = n->next) for (; n; n = n->next)
{ {
if (S_MatchKey(n->ent->key, key)) if (S_MatchKey(n->ent->key, key))
{ {
ent = n->ent; result = n->ent;
break; break;
} }
} }
} }
return ent; }
return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Iteration helpers //~ Iteration helpers
void S_ResetIter(Arena *arena, S_Iter *iter, S_World *world, S_Key key, S_IterKind kind) void S_ResetIter(Arena *arena, S_Iter *iter, S_Lookup *lookup, S_Key key, S_IterKind kind)
{ {
iter->kind = kind; iter->kind = kind;
iter->world = world; iter->lookup = lookup;
for (S_IterDfsNode *n = iter->first_dfs; n; n = n->next) for (S_IterDfsNode *n = iter->first_dfs; n; n = n->next)
{ {
n->next = iter->first_free_dfs; n->next = iter->first_free_dfs;
@ -143,7 +180,7 @@ void S_ResetIter(Arena *arena, S_Iter *iter, S_World *world, S_Key key, S_IterKi
S_Ent *S_NextEnt(Arena *arena, S_Iter *iter) S_Ent *S_NextEnt(Arena *arena, S_Iter *iter)
{ {
S_Ent *result = &S_nil_ent; S_Ent *result = &S_nil_ent;
S_World *world = iter->world; S_Lookup *lookup = iter->lookup;
b32 is_post_order = iter->kind == S_IterKind_Post; b32 is_post_order = iter->kind == S_IterKind_Post;
b32 stop = 0; b32 stop = 0;
@ -152,11 +189,11 @@ S_Ent *S_NextEnt(Arena *arena, S_Iter *iter)
if (iter->first_dfs) if (iter->first_dfs)
{ {
S_IterDfsNode *n = iter->first_dfs; S_IterDfsNode *n = iter->first_dfs;
S_Ent *ent = S_EntFromKey(iter->world, n->ent_key); S_Ent *ent = S_EntFromKey(iter->lookup, n->ent_key);
if (!n->visited) if (!n->visited)
{ {
/* Push children to dfs stack */ /* Push children to dfs stack */
for (S_Ent *child = S_EntFromKey(world, ent->last); !S_IsEntNil(child); child = S_EntFromKey(world, ent->prev)) 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; S_IterDfsNode *child_n = iter->first_free_dfs;
if (child_n) if (child_n)
@ -202,32 +239,38 @@ S_Ent *S_NextEnt(Arena *arena, S_Iter *iter)
S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot) S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot)
{ {
TempArena scratch = BeginScratch(arena);
S_World *world = PushStruct(arena, S_World); S_World *world = PushStruct(arena, S_World);
/* Copy ents */ /* Copy ents */
world->ents = PushStructsNoZero(arena, S_Ent, snapshot->ents_count); world->ents = PushStructsNoZero(arena, S_Ent, snapshot->ents_count);
CopyStructs(world->ents, snapshot->ents, snapshot->ents_count); CopyStructs(world->ents, snapshot->ents, snapshot->ents_count);
world->allocated_ents_count = snapshot->ents_count; world->ents_count = snapshot->ents_count;
world->tick = snapshot->tick; world->tick = snapshot->tick;
/* Init lookup */
world->ent_bins_count = 4096;
world->ent_bins = PushStructs(arena, S_EntLookupNode *, world->ent_bins_count);
for (i64 ent_idx = 0; ent_idx < world->allocated_ents_count; ++ent_idx)
{
S_Ent *ent = &world->ents[ent_idx];
S_Key key = ent->key;
S_EntLookupNode *n = PushStruct(arena, S_EntLookupNode);
n->ent = ent;
S_EntLookupNode **bin = &world->ent_bins[ent->key.v.lo % world->ent_bins_count];
SllStackPush(*bin, n);
}
EndScratch(scratch);
return world; return world;
} }
////////////////////////////////////////////////////////////
//~ Sorting
MergesortCompareFuncDef(S_SortEntsByKeyCmp, arg_a, arg_b, _)
{
S_Ent *a = *(S_Ent **)arg_a;
S_Ent *b = *(S_Ent **)arg_b;
S_Key a_key = a->key;
S_Key b_key = b->key;
i32 result = 0;
if (result == 0)
{
result = ((a_key.v.lo < b_key.v.lo) - (a_key.v.lo > b_key.v.lo));
}
if (result == 0)
{
result = ((a_key.v.hi < b_key.v.hi) - (a_key.v.hi > b_key.v.hi));
}
return result;
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Sim worker //~ Sim worker
@ -238,50 +281,10 @@ JobDef(S_SimWorker, _, __)
Arena *perm = PermArena(); Arena *perm = PermArena();
//- World data //- World data
Arena *world_arena = AcquireArena(Gibi(64)); Arena *ents_arena = AcquireArena(Gibi(64));
S_World *world = 0; S_World *world = PushStruct(perm, S_World);
world->ents = ArenaFirst(ents_arena, S_Ent);
{ i64 first_free_ent_num = 0;
S_Snapshot *empty_ss = PushStruct(frame_arena, S_Snapshot);
{
empty_ss->ents = PushStructs(frame_arena, S_Ent, 1024);
/* Create root ent */
S_Ent *root_ent = &empty_ss->ents[empty_ss->ents_count++];
{
*root_ent = S_nil_ent;
root_ent->key = S_RootKey;
}
/* Create test ent */
S_Ent *test_ent = &empty_ss->ents[empty_ss->ents_count++];
{
*test_ent = S_nil_ent;
// test_ent->shape.points_count = 1;
// test_ent->shape.radius = 0.25;
test_ent->key = ((S_Key) { .v.hi = 0x66444f20b7e41f3d, .v.lo = 0x5a2df684b9430943 });
{
S_Shape *shape = &test_ent->local_shape;
shape->points_count = 4;
shape->points[0] = VEC2(100, 100);
shape->points[1] = VEC2(200, 100);
shape->points[2] = VEC2(150, 200);
shape->points[3] = VEC2(125, 200);
// shape->radius = 1;
}
test_ent->parent = root_ent->key;
root_ent->first = test_ent->key;
root_ent->last = test_ent->key;
++root_ent->count;
}
}
world = S_WorldFromSnapshot(world_arena, empty_ss);
}
////////////////////////////// //////////////////////////////
//- Sim loop //- Sim loop
@ -290,13 +293,27 @@ JobDef(S_SimWorker, _, __)
while (!shutdown) while (!shutdown)
{ {
ResetArena(frame_arena); ResetArena(frame_arena);
S_Iter ent_iter = ZI; S_Iter iter = ZI;
S_Lookup lookup = ZI;
////////////////////////////// //////////////////////////////
//- Begin sim frame //- Begin sim frame
i64 frame_begin_ns = TimeNs(); i64 frame_begin_ns = TimeNs();
//////////////////////////////
//- Create root ent
if (world->tick == 0)
{
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);
////////////////////////////// //////////////////////////////
//- Pop sim commands //- Pop sim commands
@ -313,25 +330,132 @@ JobDef(S_SimWorker, _, __)
UnlockTicketMutex(&shared->input_back_tm); UnlockTicketMutex(&shared->input_back_tm);
////////////////////////////// //////////////////////////////
//- Process sim commands //- Spawn entities
for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next) for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
{ {
S_Cmd cmd = cmd_node->cmd; S_Cmd cmd = cmd_node->cmd;
switch (cmd.kind) if (cmd.kind == S_CmdKind_Spawn)
{ {
case S_CmdKind_Ent: for (S_EntListNode *src_n = cmd.ents.first; src_n; src_n = src_n->next)
{ {
LogInfoF("Ent cmd"); S_Ent *src = &src_n->ent;
} break; if (S_IsKeyNil(src->parent))
{
src->parent = S_RootKey;
}
S_Key key = src->key;
if (!S_MatchKey(key, S_RootKey) && !S_IsKeyNil(key))
{
S_Ent *dst = S_EntFromKey(&lookup, key);
if (S_IsEntNil(dst))
{
if (first_free_ent_num > 0)
{
dst = &world->ents[first_free_ent_num - 1];
first_free_ent_num = dst->next_free_ent_num;
}
else
{
dst = PushStructNoZero(ents_arena, S_Ent);
}
*dst = S_nil_ent;
dst->key = key;
++world->ents_count;
}
*dst = *src;
dst->active = 1;
}
LogInfoF("RAAAH %F", FmtSint(world->ents_count));
} }
} }
}
lookup = S_LookupFromWorld(frame_arena, world);
//////////////////////////////
//- Rebuild 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 entities from user control //- Update entities from user control
S_ResetIter(frame_arena, &ent_iter, world, S_RootKey, S_IterKind_Post); S_ResetIter(frame_arena, &iter, &lookup, S_RootKey, S_IterKind_Pre);
for (S_Ent *ent = S_NextEnt(frame_arena, &ent_iter); !S_IsEntNil(ent); ent = S_NextEnt(frame_arena, &ent_iter)) for (S_Ent *ent = S_NextEnt(frame_arena, &iter); !S_IsEntNil(ent); ent = S_NextEnt(frame_arena, &iter))
{ {
} }
@ -345,7 +469,7 @@ JobDef(S_SimWorker, _, __)
S_Snapshot *snapshot = &snapshot_node->snapshot; S_Snapshot *snapshot = &snapshot_node->snapshot;
SllQueuePush(output->first_snapshot_node, output->last_snapshot_node, snapshot_node); SllQueuePush(output->first_snapshot_node, output->last_snapshot_node, snapshot_node);
++output->snapshots_count; ++output->snapshots_count;
snapshot->ents_count = world->allocated_ents_count; snapshot->ents_count = world->ents_count;
snapshot->tick = world->tick; snapshot->tick = world->tick;
snapshot->ents = PushStructsNoZero(output->arena, S_Ent, snapshot->ents_count); snapshot->ents = PushStructsNoZero(output->arena, S_Ent, snapshot->ents_count);
for (i64 ent_idx = 0; ent_idx < snapshot->ents_count; ++ent_idx) for (i64 ent_idx = 0; ent_idx < snapshot->ents_count; ++ent_idx)

View File

@ -22,40 +22,55 @@ Struct(S_Shape)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Ent types //~ Ent types
////////////////////////////// /* TODO: Move boolean fields into bitwise property flags */
//- Ent roperties
Enum(S_EntProp)
{
S_EntProp_None,
};
//////////////////////////////
//- Ent
Struct(S_Ent) Struct(S_Ent)
{ {
//- Tree data //////////////////////////////
//- Tree links
S_Key parent; S_Key parent;
S_Key first; S_Key first;
S_Key last; S_Key last;
S_Key next; S_Key next;
S_Key prev; S_Key prev;
i64 count; u64 count;
//////////////////////////////
//- Persistent data //- Persistent data
b32 active;
S_Key key; S_Key key;
//- Build data //////////////////////////////
//- Pre-solve data
S_Key follow;
S_Key camera;
S_Shape local_shape; S_Shape local_shape;
Xform local_to_parent_xf; Xform local_to_parent_xf;
//- Final data //////////////////////////////
//- Post-solve data
Xform final_local_to_world_xf; Xform final_local_to_world_xf;
//////////////////////////////
//- Internal sim data
i64 next_free_ent_num;
} extern Readonly S_nil_ent; } extern Readonly S_nil_ent;
////////////////////////////// ////////////////////////////////////////////////////////////
//- Ent containers //~ Ent container types
Struct(S_EntArray)
{
u64 count;
S_Ent *ents;
};
Struct(S_EntListNode) Struct(S_EntListNode)
{ {
@ -70,24 +85,29 @@ Struct(S_EntList)
u64 count; u64 count;
}; };
Struct(S_EntLookupNode) ////////////////////////////////////////////////////////////
//~ Lookup types
Struct(S_LookupEntNode)
{ {
S_EntLookupNode *next; S_LookupEntNode *next;
S_Ent *ent; S_Ent *ent;
}; };
Struct(S_Lookup)
{
S_LookupEntNode **bins;
i64 bins_count;
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ World types //~ World types
Struct(S_World) Struct(S_World)
{ {
i64 tick; i64 tick;
S_Ent *ents; S_Ent *ents;
i64 allocated_ents_count; i64 ents_count;
S_EntLookupNode **ent_bins;
i64 ent_bins_count;
}; };
Struct(S_Snapshot) Struct(S_Snapshot)
@ -122,7 +142,7 @@ Struct(S_IterDfsNode)
Struct(S_Iter) Struct(S_Iter)
{ {
S_IterKind kind; S_IterKind kind;
S_World *world; S_Lookup *lookup;
S_IterDfsNode *first_dfs; S_IterDfsNode *first_dfs;
S_IterDfsNode *first_free_dfs; S_IterDfsNode *first_free_dfs;
}; };
@ -133,13 +153,13 @@ Struct(S_Iter)
Enum(S_CmdKind) Enum(S_CmdKind)
{ {
S_CmdKind_Nop, S_CmdKind_Nop,
S_CmdKind_Ent, S_CmdKind_Spawn,
}; };
Struct(S_Cmd) Struct(S_Cmd)
{ {
S_CmdKind kind; S_CmdKind kind;
S_Ent ent; S_EntList ents;
}; };
Struct(S_CmdNode) Struct(S_CmdNode)
@ -201,6 +221,11 @@ b32 S_IsKeyNil(S_Key key);
b32 S_IsEntNil(S_Ent *ent); b32 S_IsEntNil(S_Ent *ent);
b32 S_MatchKey(S_Key a, S_Key b); b32 S_MatchKey(S_Key a, S_Key b);
////////////////////////////////////////////////////////////
//~ Key helpers
S_Key S_RandKey(void);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Shape helpers //~ Shape helpers
@ -210,12 +235,13 @@ Vec2 S_SupportPointFromShape(S_Shape shape, Vec2 dir);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Lookup helpers //~ Lookup helpers
S_Ent *S_EntFromKey(S_World *world, S_Key key); S_Lookup S_LookupFromWorld(Arena *arena, S_World *world);
S_Ent *S_EntFromKey(S_Lookup *lookup, S_Key key);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Iteration helpers //~ Iteration helpers
void S_ResetIter(Arena *arena, S_Iter *iter, S_World *world, S_Key key, S_IterKind kind); void S_ResetIter(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_NextEnt(Arena *arena, S_Iter *iter);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -223,6 +249,11 @@ S_Ent *S_NextEnt(Arena *arena, S_Iter *iter);
S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot); S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot);
////////////////////////////////////////////////////////////
//~ Sorting
MergesortCompareFuncDef(S_SortEntsByKeyCmp, arg_a, arg_b, _);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Sim worker //~ Sim worker

View File

@ -22,6 +22,55 @@ void V_Shutdown(void)
YieldOnFence(&shared->worker_completion_fence, shared->workers_count); YieldOnFence(&shared->worker_completion_fence, shared->workers_count);
} }
////////////////////////////////////////////////////////////
//~ Test ents
void V_PushTestEnts(Arena *arena, S_EntList *list)
{
S_Key player_key = S_RandKey();
S_Key camera_key = S_RandKey();
i32 count = 2;
for (u64 i = 0; i < count; ++i)
{
S_EntListNode *n = PushStruct(arena, S_EntListNode);
SllQueuePush(list->first, list->last, n);
++list->count;
S_Ent *ent = &n->ent;
*ent = S_nil_ent;
switch (i)
{
/* Test player */
case 0:
{
ent->key = player_key;
ent->camera = camera_key;
{
S_Shape *shape = &ent->local_shape;
shape->points_count = 4;
shape->points[0] = VEC2(100, 100);
shape->points[1] = VEC2(200, 100);
shape->points[2] = VEC2(150, 200);
shape->points[3] = VEC2(125, 200);
// shape->radius = 1;
}
} break;
/* Test camera */
case 1:
{
ent->key = camera_key;
} break;
default:
{
Assert(0);
} break;
}
}
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Vis worker //~ Vis worker
@ -95,13 +144,11 @@ JobDef(V_VisWorker, _, __)
String swap_encoded = SwappedStateFromName(scratch.arena, Lit("pp_vis")); String swap_encoded = SwappedStateFromName(scratch.arena, Lit("pp_vis"));
BB_Buff bb = BB_BuffFromString(swap_encoded); BB_Buff bb = BB_BuffFromString(swap_encoded);
BB_Reader br = BB_ReaderFromBuff(&bb); BB_Reader br = BB_ReaderFromBuff(&bb);
String swap_str = BB_ReadString(scratch.arena, &br); String swap_str = BB_ReadString(scratch.arena, &br);
if (swap_str.len == sizeof(Persist)) if (swap_str.len == sizeof(Persist))
{ {
CopyBytes(&persist, swap_str.text, swap_str.len); CopyBytes(&persist, swap_str.text, swap_str.len);
} }
window_restore = BB_ReadString(perm, &br); window_restore = BB_ReadString(perm, &br);
} }
EndScratch(scratch); EndScratch(scratch);
@ -112,12 +159,20 @@ JobDef(V_VisWorker, _, __)
Arena *world_arena = AcquireArena(Gibi(64)); Arena *world_arena = AcquireArena(Gibi(64));
S_World *world = PushStruct(world_arena, S_World); S_World *world = PushStruct(world_arena, S_World);
S_Lookup lookup = ZI;
b32 shutdown = 0; b32 shutdown = 0;
while (!shutdown) while (!shutdown)
{ {
ResetArena(frame_arena); ResetArena(frame_arena);
S_Iter ent_iter = ZI; S_Iter iter = ZI;
S_EntList spawn_ents = ZI;
if (world->tick == 0)
{
V_PushTestEnts(frame_arena, &spawn_ents);
}
////////////////////////////// //////////////////////////////
//- Begin vis frame //- Begin vis frame
@ -175,6 +230,7 @@ JobDef(V_VisWorker, _, __)
{ {
ResetArena(world_arena); ResetArena(world_arena);
world = S_WorldFromSnapshot(world_arena, &sim_output->last_snapshot_node->snapshot); world = S_WorldFromSnapshot(world_arena, &sim_output->last_snapshot_node->snapshot);
lookup = S_LookupFromWorld(world_arena, world);
} }
////////////////////////////// //////////////////////////////
@ -260,8 +316,6 @@ JobDef(V_VisWorker, _, __)
////////////////////////////// //////////////////////////////
//- Process vis commands //- Process vis commands
S_EntList spawn_ents = ZI;
for (V_CmdNode *cmd_node = first_cmd_node; cmd_node; cmd_node = cmd_node->next) for (V_CmdNode *cmd_node = first_cmd_node; cmd_node; cmd_node = cmd_node->next)
{ {
String cmd_name = cmd_node->cmd.name; String cmd_name = cmd_node->cmd.name;
@ -332,14 +386,30 @@ JobDef(V_VisWorker, _, __)
LockTicketMutex(&sim_shared->input_back_tm); LockTicketMutex(&sim_shared->input_back_tm);
{ {
S_InputState *v2s = &sim_shared->input_states[sim_shared->input_back_idx]; S_InputState *v2s = &sim_shared->input_states[sim_shared->input_back_idx];
for (S_EntListNode *ent_node = spawn_ents.first; ent_node; ent_node = ent_node->next)
/* Submit spawn cmds */
if (spawn_ents.count > 0)
{ {
S_CmdNode *cmd_node = PushStruct(v2s->arena, S_CmdNode); S_CmdNode *cmd_node = PushStruct(v2s->arena, S_CmdNode);
cmd_node->cmd.kind = S_CmdKind_Ent; {
cmd_node->cmd.ent = ent_node->ent;
SllQueuePush(v2s->first_cmd_node, v2s->last_cmd_node, cmd_node); SllQueuePush(v2s->first_cmd_node, v2s->last_cmd_node, cmd_node);
++v2s->cmds_count; ++v2s->cmds_count;
} }
S_Cmd *cmd = &cmd_node->cmd;
{
cmd->kind = S_CmdKind_Spawn;
}
S_EntList *dst = &cmd->ents;
for (S_EntListNode *src_n = spawn_ents.first; src_n; src_n = src_n->next)
{
S_EntListNode *dst_n = PushStruct(v2s->arena, S_EntListNode);
{
SllQueuePush(dst->first, dst->last, dst_n);
++dst->count;
}
dst_n->ent = src_n->ent;
}
}
} }
UnlockTicketMutex(&sim_shared->input_back_tm); UnlockTicketMutex(&sim_shared->input_back_tm);
@ -347,8 +417,8 @@ JobDef(V_VisWorker, _, __)
//- Build render data //- Build render data
/* Build shapes */ /* Build shapes */
S_ResetIter(frame_arena, &ent_iter, world, S_RootKey, S_IterKind_Pre); S_ResetIter(frame_arena, &iter, &lookup, S_RootKey, S_IterKind_Pre);
for (S_Ent *ent = S_NextEnt(frame_arena, &ent_iter); !S_IsEntNil(ent); ent = S_NextEnt(frame_arena, &ent_iter)) for (S_Ent *ent = S_NextEnt(frame_arena, &iter); !S_IsEntNil(ent); ent = S_NextEnt(frame_arena, &iter))
{ {
Xform xf = ent->final_local_to_world_xf; Xform xf = ent->final_local_to_world_xf;
S_Shape shape = S_MulXformShape(ent->final_local_to_world_xf, ent->local_shape); S_Shape shape = S_MulXformShape(ent->final_local_to_world_xf, ent->local_shape);

View File

@ -88,9 +88,9 @@ void V_Startup(void);
void V_Shutdown(void); void V_Shutdown(void);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Hotkey helpers //~ Test ents
String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey); void V_PushTestEnts(Arena *arena, S_EntList *list);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Vis worker //~ Vis worker