update user & sim worlds via structured deltas
This commit is contained in:
parent
54f77c87be
commit
6a305b4803
@ -6,7 +6,7 @@ pushd build
|
|||||||
|
|
||||||
for %%a in (%*) do set "%%a=1"
|
for %%a in (%*) do set "%%a=1"
|
||||||
set program_build_cmd=meta.exe %*
|
set program_build_cmd=meta.exe %*
|
||||||
set meta_build_warnings=-W4 -WX -wd4244 -wd4201 -wd4324 -wd4100 -wd4101 -wd4189
|
set meta_build_warnings=-W4 -WX -we4668 -wd4244 -wd4201 -wd4324 -wd4100 -wd4101 -wd4189 -wd4200 -wd4702 -wd4305
|
||||||
set meta_build_cmd=cl.exe ../src/meta/meta.c -Od -Z7 -nologo -diagnostics:column %meta_build_warnings% -link -DEBUG:FULL -INCREMENTAL:NO
|
set meta_build_cmd=cl.exe ../src/meta/meta.c -Od -Z7 -nologo -diagnostics:column %meta_build_warnings% -link -DEBUG:FULL -INCREMENTAL:NO
|
||||||
set meta_rebuild_code=1317212284
|
set meta_rebuild_code=1317212284
|
||||||
|
|
||||||
|
|||||||
@ -484,7 +484,6 @@
|
|||||||
typedef double f64;
|
typedef double f64;
|
||||||
typedef i8 b8;
|
typedef i8 b8;
|
||||||
typedef u32 b32;
|
typedef u32 b32;
|
||||||
Struct(U128) { u64 hi; u64 lo; };
|
|
||||||
#elif IsLanguageG
|
#elif IsLanguageG
|
||||||
typedef int i32;
|
typedef int i32;
|
||||||
typedef uint u32;
|
typedef uint u32;
|
||||||
@ -516,6 +515,12 @@
|
|||||||
#define IsNan(x) isnan(x)
|
#define IsNan(x) isnan(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//- u128
|
||||||
|
#if IsLanguageC
|
||||||
|
Struct(u128) { u64 lo; u64 hi; };
|
||||||
|
#define U128(_hi, _lo) ((u128) { .hi = (_hi), .lo = (_lo) })
|
||||||
|
#endif
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Atomics
|
//~ Atomics
|
||||||
|
|
||||||
|
|||||||
@ -15,10 +15,10 @@
|
|||||||
|
|
||||||
#define G_D12_TearingIsAllowed 1
|
#define G_D12_TearingIsAllowed 1
|
||||||
#define G_D12_FrameLatency 1
|
#define G_D12_FrameLatency 1
|
||||||
#define G_D12_SwapchainBufferCount 3
|
#define G_D12_SwapchainBufferCount 2
|
||||||
#define G_D12_SwapchainFlags (0 \
|
#define G_D12_SwapchainFlags ( \
|
||||||
| ((G_D12_TearingIsAllowed != 0) * DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) \
|
((G_D12_TearingIsAllowed != 0) * DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) | \
|
||||||
| ((G_D12_FrameLatency != 0) * DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) \
|
((G_D12_FrameLatency != 0) * DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) \
|
||||||
)
|
)
|
||||||
|
|
||||||
#define G_D12_MaxCbvSrvUavDescriptors (1024 * 128)
|
#define G_D12_MaxCbvSrvUavDescriptors (1024 * 128)
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
S_Ctx S = Zi;
|
S_Ctx S = Zi;
|
||||||
|
|
||||||
Readonly S_ReadonlyCtx S_ro = {
|
Readonly S_Ent S_NilEnt = {
|
||||||
.nil_ent = {
|
.xf = CompXformIdentity,
|
||||||
.xf = CompXformIdentity
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
@ -39,17 +37,17 @@ void S_Shutdown(void)
|
|||||||
|
|
||||||
b32 S_IsKeyNil(S_Key key)
|
b32 S_IsKeyNil(S_Key key)
|
||||||
{
|
{
|
||||||
return key.v.hi == 0 && key.v.lo == 0;
|
return key.v == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 S_IsEntNil(S_Ent *ent)
|
b32 S_IsEntNil(S_Ent *ent)
|
||||||
{
|
{
|
||||||
return ent == 0 || ent == &S_ro.nil_ent;
|
return ent == 0 || ent == &S_NilEnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 S_MatchKey(S_Key a, S_Key b)
|
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 == b.v;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
@ -83,37 +81,86 @@ String S_NameFromTileKind(S_TileKind kind)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rng2I32 S_UpdateTilesInPlaceFromPlacement(u8 *tiles, S_TilePlacement placement)
|
////////////////////////////////////////////////////////////
|
||||||
{
|
//~ Delta helpers
|
||||||
Rng2I32 dirty_rect = Zi;
|
|
||||||
switch (placement.placement_kind)
|
|
||||||
{
|
|
||||||
case S_TilePlacementKind_Raw:
|
|
||||||
{
|
|
||||||
CopyBytes(tiles, placement.raw_tiles, S_WorldSize * S_WorldSize * 4);
|
|
||||||
dirty_rect = RNG2I32(
|
|
||||||
VEC2I32(0, 0),
|
|
||||||
VEC2I32(S_WorldSize * 2, S_WorldSize * 2)
|
|
||||||
);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case S_TilePlacementKind_Range:
|
Rng2I32 S_UpdateWorldFromDelta(Arena *arena, S_World *world, S_Delta *delta)
|
||||||
{
|
{
|
||||||
S_TileKind tile = placement.tile_kind;
|
// FIXME: Bounds check tile deltas
|
||||||
Rng2I32 range = placement.range;
|
Rng2I32 dirty_tile_rect = Zi;
|
||||||
|
if (0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
//- Raw ent
|
||||||
|
if (delta->kind == S_DeltaKind_RawEnt)
|
||||||
|
{
|
||||||
|
S_Key key = delta->ent.key;
|
||||||
|
S_Ent *ent = S_EntFromKey(world, key);
|
||||||
|
if (!ent->valid)
|
||||||
|
{
|
||||||
|
// FIXME: Use ent free list
|
||||||
|
ent = PushStructNoZero(arena, S_Ent);
|
||||||
|
*ent = S_NilEnt;
|
||||||
|
ent->key = key;
|
||||||
|
ent->exists = 1;
|
||||||
|
S_EntBin *bin = &world->ent_bins[ent->key.v % world->ent_bins_count];
|
||||||
|
DllQueuePushNP(bin->first, bin->last, ent, next_in_bin, prev_in_bin);
|
||||||
|
DllQueuePush(world->first_ent, world->last_ent, ent);
|
||||||
|
++world->ents_count;
|
||||||
|
}
|
||||||
|
S_Ent *old_next = ent->next;
|
||||||
|
S_Ent *old_prev = ent->prev;
|
||||||
|
S_Ent *old_next_in_bin = ent->next_in_bin;
|
||||||
|
S_Ent *old_prev_in_bin = ent->prev_in_bin;
|
||||||
|
{
|
||||||
|
S_Ent *src = &delta->ent;
|
||||||
|
*ent = *src;
|
||||||
|
}
|
||||||
|
ent->next = old_next;
|
||||||
|
ent->prev = old_prev;
|
||||||
|
ent->next_in_bin = old_next_in_bin;
|
||||||
|
ent->prev_in_bin = old_prev_in_bin;
|
||||||
|
ent->valid = 1;
|
||||||
|
}
|
||||||
|
//- Raw tiles
|
||||||
|
else if (delta->kind == S_DeltaKind_RawTiles)
|
||||||
|
{
|
||||||
|
Rng2I32 range = delta->tile_range;
|
||||||
|
for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y)
|
||||||
|
{
|
||||||
|
i32 src_tile_y = tile_y - range.p0.y;
|
||||||
|
for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
|
||||||
|
{
|
||||||
|
i32 src_tile_x = tile_x - range.p0.x;
|
||||||
|
Vec2I32 src_tile_pos = VEC2I32(src_tile_x, src_tile_y);
|
||||||
|
i32 src_tile_idx = S_TileIdxFromTilePos(src_tile_pos);
|
||||||
|
u8 src_tile = delta->raw_tiles[src_tile_idx];
|
||||||
|
|
||||||
|
Vec2I32 tile_pos = VEC2I32(tile_x, tile_y);
|
||||||
|
i32 tile_idx = S_TileIdxFromTilePos(tile_pos);
|
||||||
|
world->tiles[tile_idx] = src_tile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dirty_tile_rect = range;
|
||||||
|
}
|
||||||
|
//- Tile range
|
||||||
|
else if (delta->kind == S_DeltaKind_Tile)
|
||||||
|
{
|
||||||
|
S_TileKind tile = delta->tile_kind;
|
||||||
|
Rng2I32 range = delta->tile_range;
|
||||||
for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y)
|
for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y)
|
||||||
{
|
{
|
||||||
for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
|
for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
|
||||||
{
|
{
|
||||||
Vec2I32 tile_pos = VEC2I32(tile_x, tile_y);
|
Vec2I32 tile_pos = VEC2I32(tile_x, tile_y);
|
||||||
i32 tile_idx = S_TileIdxFromTilePos(tile_pos);
|
i32 tile_idx = S_TileIdxFromTilePos(tile_pos);
|
||||||
tiles[tile_idx] = (u8)tile;
|
world->tiles[tile_idx] = (u8)tile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dirty_rect = range;
|
dirty_tile_rect = range;
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
return dirty_rect;
|
|
||||||
|
return dirty_tile_rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
@ -836,114 +883,43 @@ S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Lookup helpers
|
//~ Lookup helpers
|
||||||
|
|
||||||
S_Lookup S_LookupFromWorld(Arena *arena, S_World *world)
|
S_Ent *S_EntFromKey(S_World *world, S_Key key)
|
||||||
{
|
{
|
||||||
S_Lookup lookup = Zi;
|
S_Ent *result = &S_NilEnt;
|
||||||
|
if (!S_IsKeyNil(key) && world->ent_bins_count > 0)
|
||||||
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];
|
S_EntBin *bin = &world->ent_bins[key.v % world->ent_bins_count];
|
||||||
if (ent->active)
|
for (S_Ent *e = bin->first; e; e = e->next_in_bin)
|
||||||
{
|
{
|
||||||
S_Key key = ent->key;
|
if (e->key.v == key.v)
|
||||||
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_ro.nil_ent;
|
result = e;
|
||||||
if (!S_IsKeyNil(key))
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (S_MatchKey(n->ent->key, key))
|
|
||||||
{
|
|
||||||
result = n->ent;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Iteration helpers
|
//~ Iteration helpers
|
||||||
|
|
||||||
S_Ent *S_FirstEnt(S_Iter *iter, S_World *world)
|
S_Ent *S_FirstEnt(S_World *world)
|
||||||
{
|
{
|
||||||
ZeroStruct(iter);
|
S_Ent *result = &S_NilEnt;
|
||||||
iter->world = world;
|
if (world->first_ent)
|
||||||
return S_NextEnt(iter);
|
{
|
||||||
|
result = world->first_ent;
|
||||||
}
|
}
|
||||||
|
|
||||||
S_Ent *S_NextEnt(S_Iter *iter)
|
|
||||||
{
|
|
||||||
S_World *world = iter->world;
|
|
||||||
S_Ent *result = &S_ro.nil_ent;
|
|
||||||
|
|
||||||
i64 ent_idx = iter->cur_idx;
|
|
||||||
for (; ent_idx < world->ents_count; ++ent_idx)
|
|
||||||
{
|
|
||||||
S_Ent *ent = &world->ents[ent_idx];
|
|
||||||
if (ent->active)
|
|
||||||
{
|
|
||||||
result = ent;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
iter->cur_idx = ent_idx + 1;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
S_Ent *S_NextEnt(S_Ent *e)
|
||||||
//~ Snapshot helpers
|
|
||||||
|
|
||||||
S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot)
|
|
||||||
{
|
{
|
||||||
S_World *world = PushStruct(arena, S_World);
|
S_Ent *result = &S_NilEnt;
|
||||||
|
if (e && e->next)
|
||||||
// Copy ents
|
|
||||||
world->ents = PushStructsNoZero(arena, S_Ent, snapshot->ents_count);
|
|
||||||
CopyStructs(world->ents, snapshot->ents, snapshot->ents_count);
|
|
||||||
world->ents_count = snapshot->ents_count;
|
|
||||||
world->tick = snapshot->tick;
|
|
||||||
world->time_ns = snapshot->time_ns;
|
|
||||||
|
|
||||||
return world;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Sorting
|
|
||||||
|
|
||||||
MergesortCompareFuncDef(S_SortEntsByKeyCmp, arg_a, arg_b, _)
|
|
||||||
{
|
{
|
||||||
S_Ent *a = *(S_Ent **)arg_a;
|
result = e->next;
|
||||||
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;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1006,13 +982,8 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
|
|
||||||
S.debug_draw_descs_arena = AcquireArena(Gibi(64));
|
S.debug_draw_descs_arena = AcquireArena(Gibi(64));
|
||||||
|
|
||||||
//- 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;
|
|
||||||
|
|
||||||
u8 *tiles = PushBytes(perm, S_WorldSize * S_WorldSize * 4, alignof(S_TileKind));
|
|
||||||
|
|
||||||
// TODO: Real per-client deltas
|
// TODO: Real per-client deltas
|
||||||
b32 has_sent_initial_tick = 0;
|
b32 has_sent_initial_tick = 0;
|
||||||
@ -1027,8 +998,55 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
S.debug_draw_enabled = TweakBool("Simulation debug draw", 1);
|
S.debug_draw_enabled = TweakBool("Simulation debug draw", 1);
|
||||||
|
|
||||||
ResetArena(frame_arena);
|
ResetArena(frame_arena);
|
||||||
S_Iter iter = Zi;
|
|
||||||
S_Lookup lookup = Zi;
|
//////////////////////////////
|
||||||
|
//- Swap
|
||||||
|
|
||||||
|
{
|
||||||
|
b32 swapin = IsSwappedIn();
|
||||||
|
b32 swapout = shutdown && IsSwappingOut();
|
||||||
|
|
||||||
|
//- Swap in
|
||||||
|
if (!world)
|
||||||
|
{
|
||||||
|
String packed = Zi;
|
||||||
|
if (swapin)
|
||||||
|
{
|
||||||
|
packed = SwappedStateFromName(frame_arena, Lit("pp_sim.swp"));
|
||||||
|
}
|
||||||
|
S_TranscodeResult tr = S_TranscodeWorld(frame_arena, 0, packed, 0);
|
||||||
|
|
||||||
|
ResetArena(world_arena);
|
||||||
|
world = PushStruct(world_arena, S_World);
|
||||||
|
world->tick = tr.unpacked->tick;
|
||||||
|
world->time_ns = tr.unpacked->time_ns;
|
||||||
|
|
||||||
|
world->ent_bins_count = Kibi(16);
|
||||||
|
world->ent_bins = PushStructs(world_arena, S_EntBin, world->ent_bins_count);
|
||||||
|
|
||||||
|
// Copy tiles
|
||||||
|
world->tiles = PushStructsNoZero(world_arena, u8, S_TilesCount);
|
||||||
|
CopyStructs(world->tiles, tr.unpacked->tiles, S_TilesCount);
|
||||||
|
|
||||||
|
// Copy ents
|
||||||
|
world->ents_count = tr.unpacked->ents_count;
|
||||||
|
for (S_Ent *src = tr.unpacked->first_ent; src; src = src->next)
|
||||||
|
{
|
||||||
|
S_Ent *dst = PushStructNoZero(world_arena, S_Ent);
|
||||||
|
*dst = *src;
|
||||||
|
S_EntBin *bin = &world->ent_bins[dst->key.v % world->ent_bins_count];
|
||||||
|
DllQueuePush(world->first_ent, world->last_ent, dst);
|
||||||
|
DllQueuePushNP(bin->first, bin->last, dst, next_in_bin, prev_in_bin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Swap out
|
||||||
|
if (swapout)
|
||||||
|
{
|
||||||
|
S_TranscodeResult tr = S_TranscodeWorld(frame_arena, world, Zstr, 1);
|
||||||
|
WriteSwappedState(Lit("pp_sim.swp"), tr.packed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Begin sim frame
|
//- Begin sim frame
|
||||||
@ -1038,46 +1056,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;
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- Swap
|
|
||||||
|
|
||||||
{
|
|
||||||
b32 swapin = world->tick == 1 && IsSwappedIn();
|
|
||||||
b32 swapout = !swapin && shutdown && IsSwappingOut();
|
|
||||||
|
|
||||||
//- Swap out
|
|
||||||
if (swapout)
|
|
||||||
{
|
|
||||||
S_TranscodeResult tr = S_TranscodeLevel(frame_arena, 1, Zstr, world, tiles);
|
|
||||||
if (tr.ok)
|
|
||||||
{
|
|
||||||
WriteSwappedState(Lit("pp_sim.swp"), tr.packed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- Swap in
|
|
||||||
if (swapin)
|
|
||||||
{
|
|
||||||
String packed = SwappedStateFromName(frame_arena, Lit("pp_sim.swp"));
|
|
||||||
S_TranscodeResult tr = S_TranscodeLevel(frame_arena, 0, packed, world, tiles);
|
|
||||||
if (tr.ok)
|
|
||||||
{
|
|
||||||
// Unpack tiles
|
|
||||||
CopyBytes(tiles, tr.unpacked.tiles, S_WorldSize * S_WorldSize * 4);
|
|
||||||
|
|
||||||
// Unpack world
|
|
||||||
world->tick = tr.unpacked.world.tick;
|
|
||||||
world->time_ns = tr.unpacked.world.time_ns;
|
|
||||||
world->ents_count = tr.unpacked.world.ents_count;
|
|
||||||
ResetArena(ents_arena);
|
|
||||||
PushStructsNoZero(ents_arena, S_Ent, world->ents_count);
|
|
||||||
CopyStructs(world->ents, tr.unpacked.world.ents, world->ents_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lookup = S_LookupFromWorld(frame_arena, world);
|
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Pop sim commands
|
//- Pop sim commands
|
||||||
|
|
||||||
@ -1094,60 +1072,43 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
UnlockTicketMutex(&S.input_back_tm);
|
UnlockTicketMutex(&S.input_back_tm);
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Store double-buffered entity data
|
//- Update double-buffered entity data
|
||||||
|
|
||||||
for (S_Ent *ent = S_FirstEnt(&iter, world); ent->active; ent = S_NextEnt(&iter))
|
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||||
{
|
{
|
||||||
ent->last_xf = ent->xf;
|
ent->last_xf = ent->xf;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Process world edit commands
|
//- Process user world delta commands
|
||||||
|
|
||||||
u64 tile_placements_count = 0;
|
// FIXME: Only accept world deltas from users that can edit
|
||||||
|
|
||||||
|
i64 applied_user_tile_deltas_count = 0;
|
||||||
|
S_Delta **applied_user_tile_deltas = PushStructsNoZero(frame_arena, S_Delta *, input->cmds_count);
|
||||||
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;
|
||||||
|
if (cmd->kind == S_CmdKind_Delta)
|
||||||
// Spawn entity
|
|
||||||
if (cmd->kind == S_CmdKind_Spawn)
|
|
||||||
{
|
{
|
||||||
S_Ent *src = &cmd->ent;
|
S_Delta *delta = &cmd->delta;
|
||||||
S_Key key = src->key;
|
b32 allow = 0;
|
||||||
if (!S_IsKeyNil(key))
|
if (delta->kind == S_DeltaKind_RawEnt)
|
||||||
{
|
{
|
||||||
S_Ent *dst = S_EntFromKey(&lookup, key);
|
allow = 1;
|
||||||
if (S_IsEntNil(dst))
|
}
|
||||||
|
if (delta->kind == S_DeltaKind_Tile)
|
||||||
{
|
{
|
||||||
if (first_free_ent_num > 0)
|
allow = 1;
|
||||||
|
applied_user_tile_deltas[applied_user_tile_deltas_count] = delta;
|
||||||
|
applied_user_tile_deltas_count += 1;
|
||||||
|
}
|
||||||
|
if (allow)
|
||||||
{
|
{
|
||||||
dst = &world->ents[first_free_ent_num - 1];
|
S_UpdateWorldFromDelta(world_arena, world, delta);
|
||||||
first_free_ent_num = dst->next_free_ent_num;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dst = PushStructNoZero(ents_arena, S_Ent);
|
|
||||||
}
|
|
||||||
*dst = S_ro.nil_ent;
|
|
||||||
dst->key = key;
|
|
||||||
++world->ents_count;
|
|
||||||
}
|
|
||||||
*dst = *src;
|
|
||||||
dst->local_shape.points_count = MaxI32(dst->local_shape.points_count, 1);
|
|
||||||
|
|
||||||
dst->active = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Place tiles
|
|
||||||
if (cmd->kind == S_CmdKind_Tile)
|
|
||||||
{
|
|
||||||
tile_placements_count += 1;
|
|
||||||
S_TilePlacement placement = cmd->tile_placement;
|
|
||||||
S_UpdateTilesInPlaceFromPlacement(tiles, placement);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
lookup = S_LookupFromWorld(frame_arena, world);
|
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Update ent controls
|
//- Update ent controls
|
||||||
@ -1157,8 +1118,8 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
S_Cmd cmd = cmd_node->cmd;
|
S_Cmd cmd = cmd_node->cmd;
|
||||||
if (cmd.kind == S_CmdKind_Control)
|
if (cmd.kind == S_CmdKind_Control)
|
||||||
{
|
{
|
||||||
S_Ent *target = S_EntFromKey(&lookup, cmd.target);
|
S_Ent *target = S_EntFromKey(world, cmd.target);
|
||||||
if (target->active)
|
if (target->valid)
|
||||||
{
|
{
|
||||||
target->move = ClampVec2Len(cmd.move, 1);
|
target->move = ClampVec2Len(cmd.move, 1);
|
||||||
target->look = cmd.look;
|
target->look = cmd.look;
|
||||||
@ -1169,7 +1130,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Integrate control forces
|
//- Integrate control forces
|
||||||
|
|
||||||
for (S_Ent *ent = S_FirstEnt(&iter, world); ent->active; ent = S_NextEnt(&iter))
|
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||||
{
|
{
|
||||||
Xform xf = ent->xf;
|
Xform xf = ent->xf;
|
||||||
|
|
||||||
@ -1215,7 +1176,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (S_Ent *ent = S_FirstEnt(&iter, world); ent->active; ent = S_NextEnt(&iter))
|
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||||
{
|
{
|
||||||
Xform last_xf = ent->last_xf;
|
Xform last_xf = ent->last_xf;
|
||||||
S_Shape last_world_shape = S_MulXformShape(last_xf, ent->local_shape);
|
S_Shape last_world_shape = S_MulXformShape(last_xf, ent->local_shape);
|
||||||
@ -1260,8 +1221,8 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
{
|
{
|
||||||
S_Constraint *constraint = &constraints[constraint_idx];
|
S_Constraint *constraint = &constraints[constraint_idx];
|
||||||
|
|
||||||
S_Ent *ent0 = S_EntFromKey(&lookup, constraint->ent0);
|
S_Ent *ent0 = S_EntFromKey(world, constraint->ent0);
|
||||||
S_Ent *ent1 = S_EntFromKey(&lookup, constraint->ent1);
|
S_Ent *ent1 = S_EntFromKey(world, constraint->ent1);
|
||||||
|
|
||||||
Vec2 old_dv0 = ent0->solved_dv;
|
Vec2 old_dv0 = ent0->solved_dv;
|
||||||
Vec2 old_dv1 = ent1->solved_dv;
|
Vec2 old_dv1 = ent1->solved_dv;
|
||||||
@ -1330,12 +1291,12 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update solved velocity
|
// Update solved velocity
|
||||||
if (ent0->active)
|
if (ent0->valid)
|
||||||
{
|
{
|
||||||
ent0->solved_dv = AddVec2(ent0->solved_dv, dv0);
|
ent0->solved_dv = AddVec2(ent0->solved_dv, dv0);
|
||||||
ent0->solved_dw += dw0;
|
ent0->solved_dw += dw0;
|
||||||
}
|
}
|
||||||
if (ent1->active)
|
if (ent1->valid)
|
||||||
{
|
{
|
||||||
ent1->solved_dv = AddVec2(ent1->solved_dv, dv1);
|
ent1->solved_dv = AddVec2(ent1->solved_dv, dv1);
|
||||||
ent1->solved_dw += dw1;
|
ent1->solved_dw += dw1;
|
||||||
@ -1345,7 +1306,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Integrate velocities
|
//- Integrate velocities
|
||||||
|
|
||||||
for (S_Ent *ent = S_FirstEnt(&iter, world); ent->active; ent = S_NextEnt(&iter))
|
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||||
{
|
{
|
||||||
Xform xf = ent->xf;
|
Xform xf = ent->xf;
|
||||||
xf.og = AddVec2(xf.og, ent->solved_dv);
|
xf.og = AddVec2(xf.og, ent->solved_dv);
|
||||||
@ -1358,7 +1319,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
|
|
||||||
if (S.debug_draw_enabled)
|
if (S.debug_draw_enabled)
|
||||||
{
|
{
|
||||||
for (S_Ent *ent = S_FirstEnt(&iter, world); ent->active; ent = S_NextEnt(&iter))
|
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||||
{
|
{
|
||||||
Xform xf = ent->xf;
|
Xform xf = ent->xf;
|
||||||
S_Shape world_shape = S_MulXformShape(xf, ent->local_shape);
|
S_Shape world_shape = S_MulXformShape(xf, ent->local_shape);
|
||||||
@ -1398,51 +1359,54 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
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->ents_count;
|
|
||||||
snapshot->tick = world->tick;
|
snapshot->tick = world->tick;
|
||||||
snapshot->ents = PushStructsNoZero(output->arena, S_Ent, snapshot->ents_count);
|
snapshot->time_ns = world->time_ns;
|
||||||
for (i64 ent_idx = 0; ent_idx < snapshot->ents_count; ++ent_idx)
|
|
||||||
|
|
||||||
|
// Forward user tile deltas
|
||||||
|
for (i64 applied_user_tile_delta_idx = 0; applied_user_tile_delta_idx < applied_user_tile_deltas_count; ++applied_user_tile_delta_idx)
|
||||||
{
|
{
|
||||||
S_Ent *src = &world->ents[ent_idx];
|
S_Delta *delta = 0;
|
||||||
S_Ent *dst = &snapshot->ents[ent_idx];
|
{
|
||||||
*dst = *src;
|
S_DeltaNode *dn = PushStruct(output->arena, S_DeltaNode);
|
||||||
|
snapshot->deltas_count += 1;
|
||||||
|
SllQueuePush(snapshot->first_delta_node, snapshot->last_delta_node, dn);
|
||||||
|
delta = &dn->delta;
|
||||||
|
}
|
||||||
|
S_Delta *src = applied_user_tile_deltas[applied_user_tile_delta_idx];
|
||||||
|
*delta = *src;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push tile map
|
// Push full tile delta
|
||||||
{
|
|
||||||
u64 dst_tile_placement_idx = 0;
|
|
||||||
snapshot->tile_placements_count = tile_placements_count;
|
|
||||||
snapshot->tile_placements = PushStructs(output->arena, S_TilePlacement, tile_placements_count + 1);
|
|
||||||
|
|
||||||
// Send raw tile map
|
|
||||||
if (!has_sent_initial_tick)
|
if (!has_sent_initial_tick)
|
||||||
{
|
{
|
||||||
snapshot->tile_placements_count += 1;
|
S_Delta *delta = 0;
|
||||||
{
|
{
|
||||||
S_TilePlacement *dst = &snapshot->tile_placements[dst_tile_placement_idx];
|
S_DeltaNode *dn = PushStruct(output->arena, S_DeltaNode);
|
||||||
dst->placement_kind = S_TilePlacementKind_Raw;
|
snapshot->deltas_count += 1;
|
||||||
dst->raw_tiles = PushStructsNoZero(output->arena, u8, S_WorldSize * S_WorldSize * 4);
|
SllQueuePush(snapshot->first_delta_node, snapshot->last_delta_node, dn);
|
||||||
CopyBytes(dst->raw_tiles, tiles, S_WorldSize * S_WorldSize * 4);
|
delta = &dn->delta;
|
||||||
}
|
}
|
||||||
dst_tile_placement_idx += 1;
|
delta->kind = S_DeltaKind_RawTiles;
|
||||||
|
delta->raw_tiles = PushStructsNoZero(output->arena, u8, S_TilesCount);
|
||||||
|
delta->tile_range = RNG2I32(VEC2I32(0, 0), VEC2I32(S_TilesPitch, S_TilesPitch));
|
||||||
|
CopyBytes(delta->raw_tiles, world->tiles, S_TilesCount);
|
||||||
has_sent_initial_tick = 1;
|
has_sent_initial_tick = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forward range tile placements
|
// Push full entity deltas
|
||||||
|
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||||
{
|
{
|
||||||
u64 src_tile_placement_idx = 0;
|
S_Delta *delta = 0;
|
||||||
for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node && src_tile_placement_idx < tile_placements_count; cmd_node = cmd_node->next)
|
|
||||||
{
|
{
|
||||||
S_Cmd *cmd = &cmd_node->cmd;
|
S_DeltaNode *dn = PushStruct(output->arena, S_DeltaNode);
|
||||||
if (cmd->kind == S_CmdKind_Tile)
|
snapshot->deltas_count += 1;
|
||||||
{
|
SllQueuePush(snapshot->first_delta_node, snapshot->last_delta_node, dn);
|
||||||
S_TilePlacement *dst = &snapshot->tile_placements[src_tile_placement_idx];
|
delta = &dn->delta;
|
||||||
*dst = cmd->tile_placement;
|
|
||||||
dst_tile_placement_idx += 1;
|
|
||||||
src_tile_placement_idx += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
delta->kind = S_DeltaKind_RawEnt;
|
||||||
|
delta->ent = *ent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push debug draw information
|
// Push debug draw information
|
||||||
|
|||||||
@ -5,26 +5,7 @@
|
|||||||
|
|
||||||
Struct(S_Key)
|
Struct(S_Key)
|
||||||
{
|
{
|
||||||
U128 v;
|
u64 v;
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Tile types
|
|
||||||
|
|
||||||
Enum(S_TilePlacementKind)
|
|
||||||
{
|
|
||||||
S_TilePlacementKind_Raw,
|
|
||||||
S_TilePlacementKind_Range,
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(S_TilePlacement)
|
|
||||||
{
|
|
||||||
S_TilePlacementKind placement_kind;
|
|
||||||
|
|
||||||
u8 *raw_tiles;
|
|
||||||
|
|
||||||
S_TileKind tile_kind;
|
|
||||||
Rng2I32 range;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
@ -56,15 +37,27 @@ Struct(S_Shape)
|
|||||||
|
|
||||||
Struct(S_Ent)
|
Struct(S_Ent)
|
||||||
{
|
{
|
||||||
|
//////////////////////////////
|
||||||
|
//- Internal world state
|
||||||
|
|
||||||
|
S_Ent *next;
|
||||||
|
S_Ent *prev;
|
||||||
|
|
||||||
|
S_Ent *next_in_bin;
|
||||||
|
S_Ent *prev_in_bin;
|
||||||
|
|
||||||
|
b32 valid;
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Persistent data
|
//- Persistent data
|
||||||
|
|
||||||
b32 active;
|
|
||||||
S_Key key;
|
S_Key key;
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Build data
|
//- Build data
|
||||||
|
|
||||||
|
f32 exists;
|
||||||
|
|
||||||
Xform last_xf;
|
Xform last_xf;
|
||||||
Xform xf;
|
Xform xf;
|
||||||
|
|
||||||
@ -81,33 +74,12 @@ Struct(S_Ent)
|
|||||||
|
|
||||||
Vec2 solved_dv;
|
Vec2 solved_dv;
|
||||||
f32 solved_dw;
|
f32 solved_dw;
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- Internal sim data
|
|
||||||
|
|
||||||
i64 next_free_ent_num;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
Struct(S_EntBin)
|
||||||
//~ Ent container types
|
|
||||||
|
|
||||||
Struct(S_EntArray)
|
|
||||||
{
|
{
|
||||||
u64 count;
|
S_Ent *first;
|
||||||
S_Ent *ents;
|
S_Ent *last;
|
||||||
};
|
|
||||||
|
|
||||||
Struct(S_EntListNode)
|
|
||||||
{
|
|
||||||
S_EntListNode *next;
|
|
||||||
S_Ent ent;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(S_EntList)
|
|
||||||
{
|
|
||||||
S_EntListNode *first;
|
|
||||||
S_EntListNode *last;
|
|
||||||
u64 count;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
@ -168,21 +140,6 @@ Struct(S_Constraint)
|
|||||||
S_Shape shape1;
|
S_Shape shape1;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Lookup types
|
|
||||||
|
|
||||||
Struct(S_LookupEntNode)
|
|
||||||
{
|
|
||||||
S_LookupEntNode *next;
|
|
||||||
S_Ent *ent;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(S_Lookup)
|
|
||||||
{
|
|
||||||
S_LookupEntNode **bins;
|
|
||||||
i64 bins_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ World types
|
//~ World types
|
||||||
|
|
||||||
@ -191,8 +148,38 @@ Struct(S_World)
|
|||||||
i64 tick;
|
i64 tick;
|
||||||
i64 time_ns;
|
i64 time_ns;
|
||||||
|
|
||||||
S_Ent *ents;
|
|
||||||
i64 ents_count;
|
i64 ents_count;
|
||||||
|
S_Ent *first_ent;
|
||||||
|
S_Ent *last_ent;
|
||||||
|
|
||||||
|
i64 ent_bins_count;
|
||||||
|
S_EntBin *ent_bins;
|
||||||
|
|
||||||
|
u8 *tiles;
|
||||||
|
};
|
||||||
|
|
||||||
|
Enum(S_DeltaKind)
|
||||||
|
{
|
||||||
|
S_DeltaKind_RawEnt,
|
||||||
|
S_DeltaKind_RawTiles,
|
||||||
|
S_DeltaKind_Tile,
|
||||||
|
};
|
||||||
|
|
||||||
|
Struct(S_Delta)
|
||||||
|
{
|
||||||
|
S_DeltaKind kind;
|
||||||
|
|
||||||
|
S_Ent ent;
|
||||||
|
|
||||||
|
u8 *raw_tiles;
|
||||||
|
S_TileKind tile_kind;
|
||||||
|
Rng2I32 tile_range;
|
||||||
|
};
|
||||||
|
|
||||||
|
Struct(S_DeltaNode)
|
||||||
|
{
|
||||||
|
S_DeltaNode *next;
|
||||||
|
S_Delta delta;
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(S_Snapshot)
|
Struct(S_Snapshot)
|
||||||
@ -200,11 +187,9 @@ Struct(S_Snapshot)
|
|||||||
i64 tick;
|
i64 tick;
|
||||||
i64 time_ns;
|
i64 time_ns;
|
||||||
|
|
||||||
S_Ent *ents;
|
i64 deltas_count;
|
||||||
i64 ents_count;
|
S_DeltaNode *first_delta_node;
|
||||||
|
S_DeltaNode *last_delta_node;
|
||||||
S_TilePlacement *tile_placements;
|
|
||||||
u64 tile_placements_count;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(S_SnapshotNode)
|
Struct(S_SnapshotNode)
|
||||||
@ -213,23 +198,13 @@ Struct(S_SnapshotNode)
|
|||||||
S_Snapshot snapshot;
|
S_Snapshot snapshot;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Iterator types
|
|
||||||
|
|
||||||
Struct(S_Iter)
|
|
||||||
{
|
|
||||||
S_World *world;
|
|
||||||
i64 cur_idx;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Command types
|
//~ Command types
|
||||||
|
|
||||||
Enum(S_CmdKind)
|
Enum(S_CmdKind)
|
||||||
{
|
{
|
||||||
S_CmdKind_Nop,
|
S_CmdKind_Nop,
|
||||||
S_CmdKind_Tile,
|
S_CmdKind_Delta,
|
||||||
S_CmdKind_Spawn,
|
|
||||||
S_CmdKind_Control,
|
S_CmdKind_Control,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -237,11 +212,8 @@ Struct(S_Cmd)
|
|||||||
{
|
{
|
||||||
S_CmdKind kind;
|
S_CmdKind kind;
|
||||||
|
|
||||||
// Tiles
|
// Delta
|
||||||
S_TilePlacement tile_placement;
|
S_Delta delta;
|
||||||
|
|
||||||
// Spawn
|
|
||||||
S_Ent ent;
|
|
||||||
|
|
||||||
// Control
|
// Control
|
||||||
S_Key target;
|
S_Key target;
|
||||||
@ -331,13 +303,8 @@ Struct(S_Ctx)
|
|||||||
S_OutputState output_states[2];
|
S_OutputState output_states[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(S_ReadonlyCtx)
|
|
||||||
{
|
|
||||||
S_Ent nil_ent;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern S_Ctx S;
|
extern S_Ctx S;
|
||||||
extern Readonly S_ReadonlyCtx S_ro;
|
extern Readonly S_Ent S_NilEnt;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Bootstrap
|
//~ Bootstrap
|
||||||
@ -361,7 +328,11 @@ S_Key S_RandKey(void);
|
|||||||
//~ Tile helpers
|
//~ Tile helpers
|
||||||
|
|
||||||
String S_NameFromTileKind(S_TileKind kind);
|
String S_NameFromTileKind(S_TileKind kind);
|
||||||
Rng2I32 S_UpdateTilesInPlaceFromPlacement(u8 *tiles, S_TilePlacement placement);
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//~ Delta helpers
|
||||||
|
|
||||||
|
Rng2I32 S_UpdateWorldFromDelta(Arena *arena, S_World *world, S_Delta *delta);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Shape helpers
|
//~ Shape helpers
|
||||||
@ -385,24 +356,13 @@ S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1);
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Lookup helpers
|
//~ Lookup helpers
|
||||||
|
|
||||||
S_Lookup S_LookupFromWorld(Arena *arena, S_World *world);
|
S_Ent *S_EntFromKey(S_World *world, S_Key key);
|
||||||
S_Ent *S_EntFromKey(S_Lookup *lookup, S_Key key);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Iteration helpers
|
//~ Iteration helpers
|
||||||
|
|
||||||
S_Ent *S_FirstEnt(S_Iter *iter, S_World *world);
|
S_Ent *S_FirstEnt(S_World *world);
|
||||||
S_Ent *S_NextEnt(S_Iter *iter);
|
S_Ent *S_NextEnt(S_Ent *e);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Snapshot helpers
|
|
||||||
|
|
||||||
S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Sorting
|
|
||||||
|
|
||||||
MergesortCompareFuncDef(S_SortEntsByKeyCmp, arg_a, arg_b, _);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Debug draw
|
//~ Debug draw
|
||||||
|
|||||||
@ -4,13 +4,13 @@
|
|||||||
Vec2I32 S_TilePosFromWorldPos(Vec2 p)
|
Vec2I32 S_TilePosFromWorldPos(Vec2 p)
|
||||||
{
|
{
|
||||||
Vec2I32 result;
|
Vec2I32 result;
|
||||||
result.x = ClampI32((p.x + S_WorldSize / 2) * 2, 0, (S_WorldSize * 2) - 1);
|
result.x = ClampI32((p.x + S_WorldPitch * ((f32)S_WorldPitch / (f32)S_TilesPitch)) * 2, 0, S_TilesPitch - 1);
|
||||||
result.y = ClampI32((p.y + S_WorldSize / 2) * 2, 0, (S_WorldSize * 2) - 1);
|
result.y = ClampI32((p.y + S_WorldPitch * ((f32)S_WorldPitch / (f32)S_TilesPitch)) * 2, 0, S_TilesPitch - 1);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 S_TileIdxFromTilePos(Vec2I32 p)
|
i32 S_TileIdxFromTilePos(Vec2I32 p)
|
||||||
{
|
{
|
||||||
i32 result = ClampI32(p.x + (p.y * S_WorldSize * 2), 0, S_WorldSize * S_WorldSize * 4);
|
i32 result = ClampI32(p.x + (p.y * S_TilesPitch), 0, S_TilesCount);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Tile types
|
//~ Tile types
|
||||||
|
|
||||||
#define S_WorldSize 96
|
#define S_WorldPitch 96
|
||||||
|
#define S_TilesPitch (S_WorldPitch * 2)
|
||||||
|
#define S_TilesCount (S_TilesPitch * S_TilesPitch)
|
||||||
|
|
||||||
#define S_TilesXMacro(X) \
|
#define S_TilesXMacro(X) \
|
||||||
X(Empty) \
|
X(Empty) \
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Transcode
|
//~ Transcode
|
||||||
|
|
||||||
S_TranscodeResult S_TranscodeLevel(Arena *arena, b32 pack, String packed, S_World *world, u8 *tiles)
|
S_TranscodeResult S_TranscodeWorld(Arena *arena, S_World *src_world, String src_packed, b32 pack)
|
||||||
{
|
{
|
||||||
S_TranscodeResult result = Zi;
|
S_TranscodeResult result = Zi;
|
||||||
result.ok = 1;
|
result.ok = 1;
|
||||||
@ -24,27 +24,25 @@ S_TranscodeResult S_TranscodeLevel(Arena *arena, b32 pack, String packed, S_Worl
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bb = BB_BuffFromString(packed);
|
bb = BB_BuffFromString(src_packed);
|
||||||
br = BB_ReaderFromBuff(&bb);
|
br = BB_ReaderFromBuff(&bb);
|
||||||
result.ok = BB_ReadUBits(&br, 32) == level_magic;
|
result.ok = BB_ReadUBits(&br, 32) == level_magic;
|
||||||
result.version = (S_Tv)BB_ReadUBits(&br, 32);
|
result.version = (S_Tv)BB_ReadUBits(&br, 32);
|
||||||
|
result.unpacked = PushStruct(arena, S_World);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Transcode world metadata
|
//- Transcode world metadata
|
||||||
|
|
||||||
if (result.ok)
|
|
||||||
{
|
|
||||||
if (pack)
|
if (pack)
|
||||||
{
|
{
|
||||||
BB_WriteIBits(&bw, world->tick, 64);
|
BB_WriteIBits(&bw, src_world->tick, 64);
|
||||||
BB_WriteIBits(&bw, world->time_ns, 64);
|
BB_WriteIBits(&bw, src_world->time_ns, 64);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result.unpacked.world.tick = BB_ReadIBits(&br, 64);
|
result.unpacked->tick = BB_ReadIBits(&br, 64);
|
||||||
result.unpacked.world.time_ns = BB_ReadIBits(&br, 64);
|
result.unpacked->time_ns = BB_ReadIBits(&br, 64);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
@ -52,77 +50,75 @@ S_TranscodeResult S_TranscodeLevel(Arena *arena, b32 pack, String packed, S_Worl
|
|||||||
|
|
||||||
// TODO: Compress tile data
|
// TODO: Compress tile data
|
||||||
|
|
||||||
if (result.ok)
|
|
||||||
{
|
|
||||||
u64 tiles_count = S_WorldSize * S_WorldSize * 4;
|
|
||||||
if (pack)
|
if (pack)
|
||||||
{
|
{
|
||||||
String tiles_str = Zi;
|
String tiles_str = Zi;
|
||||||
tiles_str.len = tiles_count;
|
tiles_str.len = S_TilesCount;
|
||||||
tiles_str.text = tiles;
|
tiles_str.text = src_world->tiles;
|
||||||
|
BB_WriteUBits(&bw, tiles_str.len, 64);
|
||||||
BB_WriteBytes(&bw, tiles_str);
|
BB_WriteBytes(&bw, tiles_str);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u8 *raw_tiles = BB_ReadBytesRaw(&br, tiles_count);
|
u64 raw_tiles_count = BB_ReadUBits(&br, 64);
|
||||||
if (raw_tiles)
|
u8 *raw_tiles = BB_ReadBytesRaw(&br, raw_tiles_count);
|
||||||
|
if (raw_tiles && raw_tiles_count == S_TilesCount)
|
||||||
{
|
{
|
||||||
result.unpacked.tiles = PushStructsNoZero(arena, u8, S_WorldSize * S_WorldSize * 4);
|
result.unpacked->tiles = PushStructsNoZero(arena, u8, raw_tiles_count);
|
||||||
CopyStructs(result.unpacked.tiles, raw_tiles, tiles_count);
|
CopyBytes(result.unpacked->tiles, raw_tiles, raw_tiles_count);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
result.unpacked->tiles = PushStructs(arena, u8, S_TilesCount);
|
||||||
result.ok = 0;
|
result.ok = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Transcode entities
|
//- Transcode entities
|
||||||
|
|
||||||
// TODO: Compress entity data
|
// TODO: Compress entity data
|
||||||
|
|
||||||
// Write entity size & alignment
|
if (result.ok)
|
||||||
|
{
|
||||||
|
if (pack)
|
||||||
|
{
|
||||||
u32 ent_size = sizeof(S_Ent);
|
u32 ent_size = sizeof(S_Ent);
|
||||||
u32 ent_align = alignof(S_Ent);
|
u32 ent_align = alignof(S_Ent);
|
||||||
if (result.ok)
|
i64 ents_count = src_world->ents_count;
|
||||||
{
|
|
||||||
if (pack)
|
|
||||||
{
|
|
||||||
BB_WriteUBits(&bw, ent_size, 32);
|
BB_WriteUBits(&bw, ent_size, 32);
|
||||||
BB_WriteUBits(&bw, ent_align, 32);
|
BB_WriteUBits(&bw, ent_align, 32);
|
||||||
|
BB_WriteUBits(&bw, ents_count, 64);
|
||||||
|
for (S_Ent *ent = S_FirstEnt(src_world); ent->valid; ent = S_NextEnt(ent))
|
||||||
|
{
|
||||||
|
BB_WriteBytes(&bw, StringFromStruct(ent));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ent_size = BB_ReadUBits(&br, 32);
|
i64 ent_size = BB_ReadUBits(&br, 32);
|
||||||
ent_align = BB_ReadUBits(&br, 32);
|
i64 ent_align = BB_ReadUBits(&br, 32);
|
||||||
}
|
i64 ents_count = BB_ReadUBits(&br, 64);
|
||||||
}
|
|
||||||
|
|
||||||
if (result.ok)
|
|
||||||
{
|
|
||||||
if (pack)
|
|
||||||
{
|
|
||||||
String ents_str = Zi;
|
|
||||||
ents_str.len = sizeof(S_Ent) * world->ents_count;
|
|
||||||
ents_str.text = (u8 *)world->ents;
|
|
||||||
|
|
||||||
BB_WriteUBits(&bw, world->ents_count, 64);
|
|
||||||
BB_WriteAlignBytes(&bw, alignof(S_Ent));
|
|
||||||
BB_WriteBytes(&bw, ents_str);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
u64 ents_count = BB_ReadUBits(&br, 64);
|
|
||||||
BB_ReadAlignBytes(&br, alignof(S_Ent));
|
|
||||||
S_Ent *ents_raw = (S_Ent *)BB_ReadBytesRaw(&br, ents_count * sizeof(S_Ent));
|
|
||||||
if (ents_raw)
|
|
||||||
{
|
|
||||||
if (ent_size == sizeof(S_Ent) && ent_align == alignof(S_Ent))
|
if (ent_size == sizeof(S_Ent) && ent_align == alignof(S_Ent))
|
||||||
{
|
{
|
||||||
result.unpacked.world.ents_count = ents_count;
|
for (i64 i = 0; i < ents_count; ++i)
|
||||||
result.unpacked.world.ents = PushStructsNoZero(arena, S_Ent, ents_count);
|
{
|
||||||
CopyStructs(result.unpacked.world.ents, ents_raw, ents_count);
|
S_Ent *raw_ent = (S_Ent *)BB_ReadBytesRaw(&br, ents_count * sizeof(S_Ent));
|
||||||
|
if (raw_ent)
|
||||||
|
{
|
||||||
|
S_Ent *ent = PushStructNoZero(arena, S_Ent);
|
||||||
|
{
|
||||||
|
CopyBytes(ent, raw_ent, ent_size);
|
||||||
|
ent->valid = 1;
|
||||||
|
}
|
||||||
|
DllQueuePush(result.unpacked->first_ent, result.unpacked->last_ent, ent);
|
||||||
|
result.unpacked->ents_count += 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.ok = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@ -14,15 +14,12 @@ Struct(S_TranscodeResult)
|
|||||||
{
|
{
|
||||||
b32 ok;
|
b32 ok;
|
||||||
S_Tv version;
|
S_Tv version;
|
||||||
|
|
||||||
String packed;
|
String packed;
|
||||||
struct
|
S_World *unpacked;
|
||||||
{
|
|
||||||
S_World world;
|
|
||||||
u8 *tiles;
|
|
||||||
} unpacked;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Transcode
|
//~ Transcode
|
||||||
|
|
||||||
S_TranscodeResult S_TranscodeLevel(Arena *arena, b32 pack, String packed, S_World *world, u8 *tiles);
|
S_TranscodeResult S_TranscodeWorld(Arena *arena, S_World *world, String packed, b32 pack);
|
||||||
|
|||||||
@ -289,7 +289,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
Arena *perm = PermArena();
|
Arena *perm = PermArena();
|
||||||
G_ArenaHandle gpu_perm = G_PermArena();
|
G_ArenaHandle gpu_perm = G_PermArena();
|
||||||
|
|
||||||
const i32 world_size = S_WorldSize;
|
const i32 world_pitch = S_WorldPitch;
|
||||||
const f32 zoom_rate = 1.50;
|
const f32 zoom_rate = 1.50;
|
||||||
const f32 min_zoom = 0.03;
|
const f32 min_zoom = 0.03;
|
||||||
const f32 max_zoom = 15.0;
|
const f32 max_zoom = 15.0;
|
||||||
@ -298,11 +298,17 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Init vis state
|
//- Init vis state
|
||||||
|
|
||||||
V.world_arena = AcquireArena(Gibi(64));
|
Arena *sim_debug_arena = AcquireArena(Gibi(64));
|
||||||
V.world = PushStruct(V.world_arena, S_World);
|
u64 sim_debug_draw_descs_count = 0;
|
||||||
|
S_DebugDrawDesc *sim_debug_draw_descs = 0;
|
||||||
|
|
||||||
|
Arena *world_arena = AcquireArena(Gibi(64));
|
||||||
|
S_World *world = PushStruct(world_arena, S_World);
|
||||||
|
world->ent_bins_count = Kibi(16);
|
||||||
|
world->ent_bins = PushStructs(world_arena, S_EntBin, world->ent_bins_count);
|
||||||
|
world->tiles = PushStructs(world_arena, u8, S_TilesCount);
|
||||||
|
Vec2I32 tiles_dims = VEC2I32(S_TilesPitch, S_TilesPitch);
|
||||||
|
|
||||||
Vec2I32 tiles_dims = VEC2I32(world_size * 2, world_size * 2);
|
|
||||||
u8 *tiles = PushBytes(perm, tiles_dims.x * tiles_dims.y, alignof(S_TileKind));
|
|
||||||
G_ResourceHandle gpu_tiles = Zi;
|
G_ResourceHandle gpu_tiles = Zi;
|
||||||
G_Texture2DRef gpu_tiles_ref = Zi;
|
G_Texture2DRef gpu_tiles_ref = Zi;
|
||||||
{
|
{
|
||||||
@ -319,7 +325,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
G_CopyCpuToTexture(
|
G_CopyCpuToTexture(
|
||||||
cl,
|
cl,
|
||||||
gpu_tiles, VEC3I32(0, 0, 0),
|
gpu_tiles, VEC3I32(0, 0, 0),
|
||||||
tiles, VEC3I32(tiles_dims.x, tiles_dims.y, 1),
|
world->tiles, VEC3I32(tiles_dims.x, tiles_dims.y, 1),
|
||||||
RNG3I32(VEC3I32(0, 0, 0), VEC3I32(tiles_dims.x, tiles_dims.y, 1))
|
RNG3I32(VEC3I32(0, 0, 0), VEC3I32(tiles_dims.x, tiles_dims.y, 1))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -373,7 +379,6 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
while (!shutdown)
|
while (!shutdown)
|
||||||
{
|
{
|
||||||
shutdown = Atomic32Fetch(&V.shutdown);
|
shutdown = Atomic32Fetch(&V.shutdown);
|
||||||
S_Iter iter = Zi;
|
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Begin frame
|
//- Begin frame
|
||||||
@ -450,8 +455,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
//- Transcode swap state
|
//- Transcode swap state
|
||||||
if (swapout)
|
if (swapout)
|
||||||
{
|
{
|
||||||
BB_WriteUBits(&bw, V.player_key.v.hi, 64);
|
BB_WriteUBits(&bw, V.player_key.v, 64);
|
||||||
BB_WriteUBits(&bw, V.player_key.v.lo, 64);
|
|
||||||
BB_WriteBit(&bw, last_frame->is_editing);
|
BB_WriteBit(&bw, last_frame->is_editing);
|
||||||
BB_WriteF32(&bw, last_frame->edit_camera_pos.x);
|
BB_WriteF32(&bw, last_frame->edit_camera_pos.x);
|
||||||
BB_WriteF32(&bw, last_frame->edit_camera_pos.y);
|
BB_WriteF32(&bw, last_frame->edit_camera_pos.y);
|
||||||
@ -460,8 +464,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
V.player_key.v.hi = BB_ReadUBits(&br, 64);
|
V.player_key.v = BB_ReadUBits(&br, 64);
|
||||||
V.player_key.v.lo = BB_ReadUBits(&br, 64);
|
|
||||||
frame->is_editing = BB_ReadBit(&br);
|
frame->is_editing = BB_ReadBit(&br);
|
||||||
frame->edit_camera_pos.x = BB_ReadF32(&br);
|
frame->edit_camera_pos.x = BB_ReadF32(&br);
|
||||||
frame->edit_camera_pos.y = BB_ReadF32(&br);
|
frame->edit_camera_pos.y = BB_ReadF32(&br);
|
||||||
@ -532,44 +535,95 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
UnlockTicketMutex(&S.output_back_tm);
|
UnlockTicketMutex(&S.output_back_tm);
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Update tiles from sim
|
//- Apply sim snapshots
|
||||||
|
|
||||||
{
|
// FIXME: Only apply latest snapshot
|
||||||
|
|
||||||
|
b32 received_unseen_tick = 0;
|
||||||
for (S_SnapshotNode *n = sim_output->first_snapshot_node; n; n = n->next)
|
for (S_SnapshotNode *n = sim_output->first_snapshot_node; n; n = n->next)
|
||||||
{
|
{
|
||||||
S_Snapshot *snapshot = &n->snapshot;
|
S_Snapshot *snapshot = &n->snapshot;
|
||||||
if (snapshot->tick > V.world->tick)
|
if (snapshot->tick > world->tick)
|
||||||
{
|
{
|
||||||
for (u64 placement_idx = 0; placement_idx < snapshot->tile_placements_count; ++placement_idx)
|
world->tick = snapshot->tick;
|
||||||
|
world->time_ns = snapshot->time_ns;
|
||||||
|
for (S_DeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next)
|
||||||
|
{
|
||||||
|
S_Delta *delta = &dn->delta;
|
||||||
|
Rng2I32 dirty_tile_rect = S_UpdateWorldFromDelta(world_arena, world, delta);
|
||||||
|
Vec2I32 dirty_tile_dims = DimsFromRng2I32(dirty_tile_rect);
|
||||||
|
if (dirty_tile_dims.x != 0 || dirty_tile_dims.y != 0)
|
||||||
{
|
{
|
||||||
S_TilePlacement placement = snapshot->tile_placements[placement_idx];
|
|
||||||
Rng2I32 dirty_rect = S_UpdateTilesInPlaceFromPlacement(tiles, placement);
|
|
||||||
G_CopyCpuToTexture(
|
G_CopyCpuToTexture(
|
||||||
frame->cl,
|
frame->cl,
|
||||||
gpu_tiles, VEC3I32(dirty_rect.p0.x, dirty_rect.p0.y, 0),
|
gpu_tiles, VEC3I32(dirty_tile_rect.p0.x, dirty_tile_rect.p0.y, 0),
|
||||||
tiles, VEC3I32(tiles_dims.x, tiles_dims.y, 1),
|
world->tiles, VEC3I32(tiles_dims.x, tiles_dims.y, 1),
|
||||||
RNG3I32(VEC3I32(dirty_rect.p0.x, dirty_rect.p0.y, 0), VEC3I32(dirty_rect.p1.x, dirty_rect.p1.y, 1))
|
RNG3I32(VEC3I32(dirty_tile_rect.p0.x, dirty_tile_rect.p0.y, 0), VEC3I32(dirty_tile_rect.p1.x, dirty_tile_rect.p1.y, 1))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
received_unseen_tick = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Update world from sim
|
//- Prune entities
|
||||||
|
|
||||||
if (sim_output->last_snapshot_node && sim_output->last_snapshot_node->snapshot.tick > V.world->tick)
|
// TODO
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- Copy sim debug info
|
||||||
|
|
||||||
|
if (received_unseen_tick)
|
||||||
{
|
{
|
||||||
ResetArena(V.world_arena);
|
ResetArena(sim_debug_arena);
|
||||||
V.world = S_WorldFromSnapshot(V.world_arena, &sim_output->last_snapshot_node->snapshot);
|
|
||||||
V.lookup = S_LookupFromWorld(V.world_arena, V.world);
|
|
||||||
|
|
||||||
// Copy sim debug info
|
// Copy sim debug info
|
||||||
V.debug_draw_descs_count = sim_output->debug_draw_descs_count;
|
sim_debug_draw_descs_count = sim_output->debug_draw_descs_count;
|
||||||
V.debug_draw_descs = PushStructsNoZero(V.world_arena, S_DebugDrawDesc, V.debug_draw_descs_count);
|
sim_debug_draw_descs = PushStructsNoZero(sim_debug_arena, S_DebugDrawDesc, sim_debug_draw_descs_count);
|
||||||
CopyStructs(V.debug_draw_descs, sim_output->debug_draw_descs, V.debug_draw_descs_count);
|
CopyStructs(sim_debug_draw_descs, sim_output->debug_draw_descs, sim_debug_draw_descs_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// //////////////////////////////
|
||||||
|
// //- Update tiles from sim
|
||||||
|
|
||||||
|
// {
|
||||||
|
// for (S_SnapshotNode *n = sim_output->first_snapshot_node; n; n = n->next)
|
||||||
|
// {
|
||||||
|
// S_Snapshot *snapshot = &n->snapshot;
|
||||||
|
// if (snapshot->tick > world->tick)
|
||||||
|
// {
|
||||||
|
// for (u64 placement_idx = 0; placement_idx < snapshot->tile_placements_count; ++placement_idx)
|
||||||
|
// {
|
||||||
|
// S_TilePlacement placement = snapshot->tile_placements[placement_idx];
|
||||||
|
// Rng2I32 dirty_rect = S_UpdateTilesInPlaceFromPlacement(tiles, placement);
|
||||||
|
// G_CopyCpuToTexture(
|
||||||
|
// frame->cl,
|
||||||
|
// gpu_tiles, VEC3I32(dirty_rect.p0.x, dirty_rect.p0.y, 0),
|
||||||
|
// tiles, VEC3I32(tiles_dims.x, tiles_dims.y, 1),
|
||||||
|
// RNG3I32(VEC3I32(dirty_rect.p0.x, dirty_rect.p0.y, 0), VEC3I32(dirty_rect.p1.x, dirty_rect.p1.y, 1))
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //////////////////////////////
|
||||||
|
// //- Update world from sim
|
||||||
|
|
||||||
|
// if (sim_output->last_snapshot_node && sim_output->last_snapshot_node->snapshot.tick > world->tick)
|
||||||
|
// {
|
||||||
|
// ResetArena(world_arena);
|
||||||
|
// world = S_WorldFromSnapshot(world_arena, &sim_output->last_snapshot_node->snapshot);
|
||||||
|
// V.lookup = S_LookupFromWorld(world_arena, world);
|
||||||
|
|
||||||
|
// // Copy sim debug info
|
||||||
|
// sim_debug_draw_descs_count = sim_output->debug_draw_descs_count;
|
||||||
|
// sim_debug_draw_descs = PushStructsNoZero(world_arena, S_DebugDrawDesc, sim_debug_draw_descs_count);
|
||||||
|
// CopyStructs(sim_debug_draw_descs, sim_output->debug_draw_descs, sim_debug_draw_descs_count);
|
||||||
|
// }
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Process controller events into vis cmds
|
//- Process controller events into vis cmds
|
||||||
|
|
||||||
@ -688,8 +742,8 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
Vec2 diff = SubVec2(last_target_cursor, target_cursor);
|
Vec2 diff = SubVec2(last_target_cursor, target_cursor);
|
||||||
frame->edit_camera_pos = AddVec2(frame->edit_camera_pos, diff);
|
frame->edit_camera_pos = AddVec2(frame->edit_camera_pos, diff);
|
||||||
}
|
}
|
||||||
frame->edit_camera_pos.x = ClampF32(frame->edit_camera_pos.x, -world_size / 2, world_size / 2);
|
frame->edit_camera_pos.x = ClampF32(frame->edit_camera_pos.x, -world_pitch / 2, world_pitch / 2);
|
||||||
frame->edit_camera_pos.y = ClampF32(frame->edit_camera_pos.y, -world_size / 2, world_size / 2);
|
frame->edit_camera_pos.y = ClampF32(frame->edit_camera_pos.y, -world_pitch / 2, world_pitch / 2);
|
||||||
target_camera_pos = frame->edit_camera_pos;
|
target_camera_pos = frame->edit_camera_pos;
|
||||||
target_camera_zoom = frame->edit_camera_zoom;
|
target_camera_zoom = frame->edit_camera_zoom;
|
||||||
}
|
}
|
||||||
@ -698,13 +752,13 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
Vec2 look_ratio = Zi;
|
Vec2 look_ratio = Zi;
|
||||||
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);
|
||||||
S_Ent *player = S_EntFromKey(&V.lookup, V.player_key);
|
S_Ent *player = S_EntFromKey(world, V.player_key);
|
||||||
target_camera_pos = MulXformV2(player->xf, player->local_shape.centroid);
|
target_camera_pos = MulXformV2(player->xf, player->local_shape.centroid);
|
||||||
target_camera_pos = AddVec2(target_camera_pos, MulVec2Vec2(player->look, look_ratio));
|
target_camera_pos = AddVec2(target_camera_pos, MulVec2Vec2(player->look, look_ratio));
|
||||||
target_camera_zoom = 1;
|
target_camera_zoom = 1;
|
||||||
}
|
}
|
||||||
target_camera_pos.x = ClampF32(target_camera_pos.x, -world_size / 2, world_size / 2);
|
target_camera_pos.x = ClampF32(target_camera_pos.x, -world_pitch / 2, world_pitch / 2);
|
||||||
target_camera_pos.y = ClampF32(target_camera_pos.y, -world_size / 2, world_size / 2);
|
target_camera_pos.y = ClampF32(target_camera_pos.y, -world_pitch / 2, world_pitch / 2);
|
||||||
target_camera_zoom = ClampF32(target_camera_zoom, min_zoom, max_zoom);
|
target_camera_zoom = ClampF32(target_camera_zoom, min_zoom, max_zoom);
|
||||||
|
|
||||||
// Create world <-> ui xforms
|
// Create world <-> ui xforms
|
||||||
@ -816,10 +870,28 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
tile_range.p1 = S_TilePosFromWorldPos(last_frame->world_selection.p1);
|
tile_range.p1 = S_TilePosFromWorldPos(last_frame->world_selection.p1);
|
||||||
tile_range.p1 = AddVec2I32(tile_range.p1, VEC2I32(1, 1));
|
tile_range.p1 = AddVec2I32(tile_range.p1, VEC2I32(1, 1));
|
||||||
|
|
||||||
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Tile);
|
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Delta);
|
||||||
cmd->tile_placement.placement_kind = S_TilePlacementKind_Range;
|
cmd->delta.kind = S_DeltaKind_Tile;
|
||||||
cmd->tile_placement.tile_kind = last_frame->equipped_tile;
|
cmd->delta.tile_kind = last_frame->equipped_tile;
|
||||||
cmd->tile_placement.range = tile_range;
|
cmd->delta.tile_range = tile_range;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- Query entities
|
||||||
|
|
||||||
|
S_Ent *player = S_EntFromKey(world, V.player_key);
|
||||||
|
S_Ent *hovered_ent = &S_NilEnt;
|
||||||
|
{
|
||||||
|
S_Shape cursor_shape = S_ShapeFromDesc(.count = 1, .points = { frame->world_cursor });
|
||||||
|
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||||
|
{
|
||||||
|
S_Shape ent_shape = S_MulXformShape(ent->xf, ent->local_shape);
|
||||||
|
b32 is_hovered = S_CollisionDataFromShapes(ent_shape, cursor_shape).collision_points_count > 0;
|
||||||
|
if (is_hovered)
|
||||||
|
{
|
||||||
|
hovered_ent = ent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2292,19 +2364,47 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
|
|
||||||
case V_CmdKind_spawn:
|
case V_CmdKind_spawn:
|
||||||
{
|
{
|
||||||
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Spawn);
|
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Delta);
|
||||||
S_Ent *ent = &cmd->ent;
|
cmd->delta.kind = S_DeltaKind_RawEnt;
|
||||||
*ent = *S_EntFromKey(&V.lookup, V.player_key);
|
S_Ent *ent = &cmd->delta.ent;
|
||||||
ent->key = V.player_key;
|
ent->key = V.player_key;
|
||||||
|
ent->xf = XformFromPos(frame->world_cursor);
|
||||||
ent->move_speed = 0.05;
|
ent->move_speed = 0.05;
|
||||||
ent->local_shape = S_ShapeFromDesc(
|
ent->local_shape = S_ShapeFromDesc(
|
||||||
.mass = 10,
|
.mass = 10,
|
||||||
.count = 1,
|
.count = 1,
|
||||||
.radius = 0.3,
|
.radius = 0.3,
|
||||||
);
|
);
|
||||||
ent->xf = XformFromPos(frame->world_cursor);
|
|
||||||
ent->has_weapon = 1;
|
ent->has_weapon = 1;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case V_CmdKind_spawn_dummy:
|
||||||
|
{
|
||||||
|
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Delta);
|
||||||
|
cmd->delta.kind = S_DeltaKind_RawEnt;
|
||||||
|
S_Ent *ent = &cmd->delta.ent;
|
||||||
|
ent->key = S_RandKey();
|
||||||
|
ent->xf = XformFromPos(frame->world_cursor);
|
||||||
|
ent->move_speed = 0.05;
|
||||||
|
ent->local_shape = S_ShapeFromDesc(
|
||||||
|
.mass = 10,
|
||||||
|
.count = 1,
|
||||||
|
.radius = 0.3,
|
||||||
|
);
|
||||||
|
ent->has_weapon = 1;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case V_CmdKind_delete:
|
||||||
|
{
|
||||||
|
if (hovered_ent->valid)
|
||||||
|
{
|
||||||
|
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Delta);
|
||||||
|
cmd->delta.kind = S_DeltaKind_RawEnt;
|
||||||
|
S_Ent *ent = &cmd->delta.ent;
|
||||||
|
ent->key = hovered_ent->key;
|
||||||
|
ent->exists = 0;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2321,7 +2421,6 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
}
|
}
|
||||||
Vec2 look = Zi;
|
Vec2 look = Zi;
|
||||||
{
|
{
|
||||||
S_Ent *player = S_EntFromKey(&V.lookup, V.player_key);
|
|
||||||
Vec2 center = MulXformV2(player->xf, player->local_shape.centroid);
|
Vec2 center = MulXformV2(player->xf, player->local_shape.centroid);
|
||||||
look = SubVec2(frame->world_cursor, center);
|
look = SubVec2(frame->world_cursor, center);
|
||||||
}
|
}
|
||||||
@ -2372,7 +2471,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
//- Draw entities
|
//- Draw entities
|
||||||
|
|
||||||
// Build shape buffers
|
// Build shape buffers
|
||||||
for (S_Ent *ent = S_FirstEnt(&iter, V.world); ent->active; ent = S_NextEnt(&iter))
|
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||||
{
|
{
|
||||||
Xform ent_to_world_xf = ent->xf;
|
Xform ent_to_world_xf = ent->xf;
|
||||||
Xform ent_to_draw_xf = MulXform(frame->world_to_draw_xf, ent_to_world_xf);
|
Xform ent_to_draw_xf = MulXform(frame->world_to_draw_xf, ent_to_world_xf);
|
||||||
@ -2424,9 +2523,9 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Draw sim debug shapes
|
//- Draw sim debug shapes
|
||||||
|
|
||||||
for (u64 desc_idx = 0; desc_idx < V.debug_draw_descs_count; ++desc_idx)
|
for (u64 desc_idx = 0; desc_idx < sim_debug_draw_descs_count; ++desc_idx)
|
||||||
{
|
{
|
||||||
S_DebugDrawDesc *desc = &V.debug_draw_descs[desc_idx];
|
S_DebugDrawDesc *desc = &sim_debug_draw_descs[desc_idx];
|
||||||
Vec4 color = Vec4FromU32(desc->srgb32);
|
Vec4 color = Vec4FromU32(desc->srgb32);
|
||||||
i32 detail = 24;
|
i32 detail = 24;
|
||||||
f32 radius = 5;
|
f32 radius = 5;
|
||||||
@ -2513,7 +2612,6 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
params.camera_pos = frame->camera_pos;
|
params.camera_pos = frame->camera_pos;
|
||||||
params.camera_zoom = frame->camera_zoom;
|
params.camera_zoom = frame->camera_zoom;
|
||||||
|
|
||||||
params.world_size = world_size;
|
|
||||||
params.tiles = gpu_tiles_ref;
|
params.tiles = gpu_tiles_ref;
|
||||||
params.shape_verts = dverts_ro;
|
params.shape_verts = dverts_ro;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,8 +12,10 @@
|
|||||||
X(toggle_console, Toggle Developer Console, V_CmdDescFlag_None, V_HOTKEY( Button_GraveAccent ), ) \
|
X(toggle_console, Toggle Developer Console, V_CmdDescFlag_None, V_HOTKEY( Button_GraveAccent ), ) \
|
||||||
X(toggle_fullscreen, Toggle Fullscreen Mode, V_CmdDescFlag_None, V_HOTKEY( Button_Enter, .alt = 1 ) ) \
|
X(toggle_fullscreen, Toggle Fullscreen Mode, V_CmdDescFlag_None, V_HOTKEY( Button_Enter, .alt = 1 ) ) \
|
||||||
X(toggle_window_topmost, Toggle Window Topmost, V_CmdDescFlag_None, V_HOTKEY( Button_F4 ), ) \
|
X(toggle_window_topmost, Toggle Window Topmost, V_CmdDescFlag_None, V_HOTKEY( Button_F4 ), ) \
|
||||||
X(spawn, Spawn/Teleport Player to Cursor, V_CmdDescFlag_None, V_HOTKEY( Button_T ), ) \
|
X(spawn, Spawn/Teleport Player, V_CmdDescFlag_None, V_HOTKEY( Button_T ), ) \
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
X(spawn_dummy, Spawn Dummy, V_CmdDescFlag_None, V_HOTKEY( Button_R ), ) \
|
||||||
|
X(delete, Delete entity at cursor, V_CmdDescFlag_None, V_HOTKEY( Button_M2 ), ) \
|
||||||
|
/* --------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Theme types
|
//~ Theme types
|
||||||
@ -279,12 +281,7 @@ Struct(V_Frame)
|
|||||||
|
|
||||||
Struct(V_Ctx)
|
Struct(V_Ctx)
|
||||||
{
|
{
|
||||||
Arena *world_arena;
|
|
||||||
S_World *world;
|
|
||||||
S_Lookup lookup;
|
|
||||||
S_Key player_key;
|
S_Key player_key;
|
||||||
u64 debug_draw_descs_count;
|
|
||||||
S_DebugDrawDesc *debug_draw_descs;
|
|
||||||
|
|
||||||
i64 panels_count;
|
i64 panels_count;
|
||||||
i64 windows_count;
|
i64 windows_count;
|
||||||
|
|||||||
@ -33,7 +33,6 @@ Struct(V_DParams)
|
|||||||
Vec2 camera_pos;
|
Vec2 camera_pos;
|
||||||
f32 camera_zoom;
|
f32 camera_zoom;
|
||||||
|
|
||||||
f32 world_size;
|
|
||||||
G_Texture2DRef tiles;
|
G_Texture2DRef tiles;
|
||||||
G_StructuredBufferRef quads;
|
G_StructuredBufferRef quads;
|
||||||
G_StructuredBufferRef shape_verts;
|
G_StructuredBufferRef shape_verts;
|
||||||
|
|||||||
@ -22,7 +22,7 @@ ComputeShader2D(V_BackdropCS, 8, 8)
|
|||||||
Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos);
|
Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos);
|
||||||
|
|
||||||
f32 half_thickness = 1;
|
f32 half_thickness = 1;
|
||||||
f32 half_bounds_size = params.world_size * 0.5;
|
f32 half_bounds_size = S_WorldPitch * 0.5;
|
||||||
Vec2 bounds_screen_p0 = mul(params.world_to_draw_xf, Vec3(-half_bounds_size, -half_bounds_size, 1));
|
Vec2 bounds_screen_p0 = mul(params.world_to_draw_xf, Vec3(-half_bounds_size, -half_bounds_size, 1));
|
||||||
Vec2 bounds_screen_p1 = mul(params.world_to_draw_xf, Vec3(half_bounds_size, half_bounds_size, 1));
|
Vec2 bounds_screen_p1 = mul(params.world_to_draw_xf, Vec3(half_bounds_size, half_bounds_size, 1));
|
||||||
bool is_in_bounds = screen_pos.x > (bounds_screen_p0.x - half_thickness) &&
|
bool is_in_bounds = screen_pos.x > (bounds_screen_p0.x - half_thickness) &&
|
||||||
@ -253,14 +253,16 @@ PixelShader(V_OverlayPS, V_OverlayPSOutput, V_OverlayPSInput input)
|
|||||||
// }
|
// }
|
||||||
// else
|
// else
|
||||||
{
|
{
|
||||||
if (world_pos.x > -(S_WorldSize / 2) &&
|
if (
|
||||||
world_pos.y > -(S_WorldSize / 2) &&
|
world_pos.x > -(S_WorldPitch / 2) &&
|
||||||
world_pos.x < (S_WorldSize / 2) &&
|
world_pos.y > -(S_WorldPitch / 2) &&
|
||||||
world_pos.y < (S_WorldSize / 2) &&
|
world_pos.x < (S_WorldPitch / 2) &&
|
||||||
|
world_pos.y < (S_WorldPitch / 2) &&
|
||||||
tile_pos.x >= tile_selection.p0.x &&
|
tile_pos.x >= tile_selection.p0.x &&
|
||||||
tile_pos.x <= tile_selection.p1.x &&
|
tile_pos.x <= tile_selection.p1.x &&
|
||||||
tile_pos.y >= tile_selection.p0.y &&
|
tile_pos.y >= tile_selection.p0.y &&
|
||||||
tile_pos.y <= tile_selection.p1.y)
|
tile_pos.y <= tile_selection.p1.y
|
||||||
|
)
|
||||||
{
|
{
|
||||||
result = inner_color;
|
result = inner_color;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user