build ent tree every frame
This commit is contained in:
parent
05a84ddd5a
commit
df2f7f0f1b
@ -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;
|
||||||
for (; n; n = n->next)
|
if (bins_count > 0)
|
||||||
{
|
{
|
||||||
if (S_MatchKey(n->ent->key, key))
|
S_LookupEntNode *n = lookup->bins[key.v.lo % bins_count];
|
||||||
|
for (; n; n = n->next)
|
||||||
{
|
{
|
||||||
ent = n->ent;
|
if (S_MatchKey(n->ent->key, key))
|
||||||
break;
|
{
|
||||||
|
result = n->ent;
|
||||||
|
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)
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -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,13 +386,29 @@ 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);
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user