From 6a305b48034ee8d1d9da163d3800046ac8f59834 Mon Sep 17 00:00:00 2001 From: jacob Date: Mon, 5 Jan 2026 01:45:10 -0600 Subject: [PATCH] update user & sim worlds via structured deltas --- build.bat | 2 +- src/base/base.cgh | 7 +- src/gpu/gpu_dx12/gpu_dx12_core.h | 8 +- src/pp/pp_sim/pp_sim_core.c | 476 ++++++++++++++----------------- src/pp/pp_sim/pp_sim_core.h | 166 ++++------- src/pp/pp_sim/pp_sim_tiles.cg | 6 +- src/pp/pp_sim/pp_sim_tiles.cgh | 4 +- src/pp/pp_sim/pp_sim_transcode.c | 122 ++++---- src/pp/pp_sim/pp_sim_transcode.h | 9 +- src/pp/pp_vis/pp_vis_core.c | 192 ++++++++++--- src/pp/pp_vis/pp_vis_core.h | 11 +- src/pp/pp_vis/pp_vis_shaders.cgh | 1 - src/pp/pp_vis/pp_vis_shaders.g | 20 +- 13 files changed, 522 insertions(+), 502 deletions(-) diff --git a/build.bat b/build.bat index 15d2661d..25f67ed1 100644 --- a/build.bat +++ b/build.bat @@ -6,7 +6,7 @@ pushd build for %%a in (%*) do set "%%a=1" 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_rebuild_code=1317212284 diff --git a/src/base/base.cgh b/src/base/base.cgh index 67759453..802e23a0 100644 --- a/src/base/base.cgh +++ b/src/base/base.cgh @@ -484,7 +484,6 @@ typedef double f64; typedef i8 b8; typedef u32 b32; - Struct(U128) { u64 hi; u64 lo; }; #elif IsLanguageG typedef int i32; typedef uint u32; @@ -516,6 +515,12 @@ #define IsNan(x) isnan(x) #endif +//- u128 +#if IsLanguageC + Struct(u128) { u64 lo; u64 hi; }; + #define U128(_hi, _lo) ((u128) { .hi = (_hi), .lo = (_lo) }) +#endif + //////////////////////////////////////////////////////////// //~ Atomics diff --git a/src/gpu/gpu_dx12/gpu_dx12_core.h b/src/gpu/gpu_dx12/gpu_dx12_core.h index 7dd329d4..5eb2e8ae 100644 --- a/src/gpu/gpu_dx12/gpu_dx12_core.h +++ b/src/gpu/gpu_dx12/gpu_dx12_core.h @@ -15,10 +15,10 @@ #define G_D12_TearingIsAllowed 1 #define G_D12_FrameLatency 1 -#define G_D12_SwapchainBufferCount 3 -#define G_D12_SwapchainFlags (0 \ - | ((G_D12_TearingIsAllowed != 0) * DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) \ - | ((G_D12_FrameLatency != 0) * DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) \ +#define G_D12_SwapchainBufferCount 2 +#define G_D12_SwapchainFlags ( \ + ((G_D12_TearingIsAllowed != 0) * DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) | \ + ((G_D12_FrameLatency != 0) * DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) \ ) #define G_D12_MaxCbvSrvUavDescriptors (1024 * 128) diff --git a/src/pp/pp_sim/pp_sim_core.c b/src/pp/pp_sim/pp_sim_core.c index ee23ba4e..166023a6 100644 --- a/src/pp/pp_sim/pp_sim_core.c +++ b/src/pp/pp_sim/pp_sim_core.c @@ -1,9 +1,7 @@ S_Ctx S = Zi; -Readonly S_ReadonlyCtx S_ro = { - .nil_ent = { - .xf = CompXformIdentity - } +Readonly S_Ent S_NilEnt = { + .xf = CompXformIdentity, }; //////////////////////////////////////////////////////////// @@ -39,17 +37,17 @@ void S_Shutdown(void) 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) { - return ent == 0 || ent == &S_ro.nil_ent; + return ent == 0 || ent == &S_NilEnt; } 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; } -Rng2I32 S_UpdateTilesInPlaceFromPlacement(u8 *tiles, S_TilePlacement placement) -{ - 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; +//////////////////////////////////////////////////////////// +//~ Delta helpers - case S_TilePlacementKind_Range: - { - S_TileKind tile = placement.tile_kind; - Rng2I32 range = placement.range; - 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) - { - Vec2I32 tile_pos = VEC2I32(tile_x, tile_y); - i32 tile_idx = S_TileIdxFromTilePos(tile_pos); - tiles[tile_idx] = (u8)tile; - } - } - dirty_rect = range; - } break; +Rng2I32 S_UpdateWorldFromDelta(Arena *arena, S_World *world, S_Delta *delta) +{ + // FIXME: Bounds check tile deltas + Rng2I32 dirty_tile_rect = Zi; + if (0) + { } - return dirty_rect; + //- 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_x = range.p0.x; tile_x < range.p1.x; ++tile_x) + { + Vec2I32 tile_pos = VEC2I32(tile_x, tile_y); + i32 tile_idx = S_TileIdxFromTilePos(tile_pos); + world->tiles[tile_idx] = (u8)tile; + } + } + dirty_tile_rect = range; + } + + return dirty_tile_rect; } //////////////////////////////////////////////////////////// @@ -836,44 +883,18 @@ S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1) //////////////////////////////////////////////////////////// //~ 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; - - 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 *result = &S_NilEnt; + if (!S_IsKeyNil(key) && world->ent_bins_count > 0) { - S_Ent *ent = &world->ents[ent_idx]; - if (ent->active) + S_EntBin *bin = &world->ent_bins[key.v % world->ent_bins_count]; + for (S_Ent *e = bin->first; e; e = e->next_in_bin) { - 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_ro.nil_ent; - 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 (e->key.v == key.v) { - if (S_MatchKey(n->ent->key, key)) - { - result = n->ent; - break; - } + result = e; + break; } } } @@ -883,67 +904,22 @@ S_Ent *S_EntFromKey(S_Lookup *lookup, S_Key key) //////////////////////////////////////////////////////////// //~ Iteration helpers -S_Ent *S_FirstEnt(S_Iter *iter, S_World *world) +S_Ent *S_FirstEnt(S_World *world) { - ZeroStruct(iter); - iter->world = world; - return S_NextEnt(iter); -} - -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 *result = &S_NilEnt; + if (world->first_ent) { - S_Ent *ent = &world->ents[ent_idx]; - if (ent->active) - { - result = ent; - break; - } + result = world->first_ent; } - iter->cur_idx = ent_idx + 1; - return result; } -//////////////////////////////////////////////////////////// -//~ Snapshot helpers - -S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot) +S_Ent *S_NextEnt(S_Ent *e) { - S_World *world = PushStruct(arena, S_World); - - // 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; - 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) + S_Ent *result = &S_NilEnt; + if (e && e->next) { - 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)); + result = e->next; } return result; } @@ -1006,13 +982,8 @@ void S_TickForever(WaveLaneCtx *lane) S.debug_draw_descs_arena = AcquireArena(Gibi(64)); - //- World data - Arena *ents_arena = AcquireArena(Gibi(64)); - 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)); + Arena *world_arena = AcquireArena(Gibi(64)); + S_World *world = 0; // TODO: Real per-client deltas b32 has_sent_initial_tick = 0; @@ -1027,8 +998,55 @@ void S_TickForever(WaveLaneCtx *lane) S.debug_draw_enabled = TweakBool("Simulation debug draw", 1); 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 @@ -1038,46 +1056,6 @@ void S_TickForever(WaveLaneCtx *lane) f64 sim_dt = SecondsFromNs(sim_dt_ns); 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 @@ -1094,60 +1072,43 @@ void S_TickForever(WaveLaneCtx *lane) 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; } ////////////////////////////// - //- 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) { S_Cmd *cmd = &cmd_node->cmd; - - // Spawn entity - if (cmd->kind == S_CmdKind_Spawn) + if (cmd->kind == S_CmdKind_Delta) { - S_Ent *src = &cmd->ent; - S_Key key = src->key; - if (!S_IsKeyNil(key)) + S_Delta *delta = &cmd->delta; + b32 allow = 0; + if (delta->kind == S_DeltaKind_RawEnt) { - 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_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; + allow = 1; + } + if (delta->kind == S_DeltaKind_Tile) + { + allow = 1; + applied_user_tile_deltas[applied_user_tile_deltas_count] = delta; + applied_user_tile_deltas_count += 1; + } + if (allow) + { + S_UpdateWorldFromDelta(world_arena, world, delta); } } - - // 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 @@ -1157,8 +1118,8 @@ void S_TickForever(WaveLaneCtx *lane) S_Cmd cmd = cmd_node->cmd; if (cmd.kind == S_CmdKind_Control) { - S_Ent *target = S_EntFromKey(&lookup, cmd.target); - if (target->active) + S_Ent *target = S_EntFromKey(world, cmd.target); + if (target->valid) { target->move = ClampVec2Len(cmd.move, 1); target->look = cmd.look; @@ -1169,7 +1130,7 @@ void S_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- 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; @@ -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; 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_Ent *ent0 = S_EntFromKey(&lookup, constraint->ent0); - S_Ent *ent1 = S_EntFromKey(&lookup, constraint->ent1); + S_Ent *ent0 = S_EntFromKey(world, constraint->ent0); + S_Ent *ent1 = S_EntFromKey(world, constraint->ent1); Vec2 old_dv0 = ent0->solved_dv; Vec2 old_dv1 = ent1->solved_dv; @@ -1330,12 +1291,12 @@ void S_TickForever(WaveLaneCtx *lane) } // Update solved velocity - if (ent0->active) + if (ent0->valid) { ent0->solved_dv = AddVec2(ent0->solved_dv, dv0); ent0->solved_dw += dw0; } - if (ent1->active) + if (ent1->valid) { ent1->solved_dv = AddVec2(ent1->solved_dv, dv1); ent1->solved_dw += dw1; @@ -1345,7 +1306,7 @@ void S_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- 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; xf.og = AddVec2(xf.og, ent->solved_dv); @@ -1358,7 +1319,7 @@ void S_TickForever(WaveLaneCtx *lane) 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; 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; SllQueuePush(output->first_snapshot_node, output->last_snapshot_node, snapshot_node); ++output->snapshots_count; - snapshot->ents_count = world->ents_count; + snapshot->tick = world->tick; - snapshot->ents = PushStructsNoZero(output->arena, S_Ent, snapshot->ents_count); - for (i64 ent_idx = 0; ent_idx < snapshot->ents_count; ++ent_idx) + snapshot->time_ns = world->time_ns; + + + // 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_Ent *dst = &snapshot->ents[ent_idx]; - *dst = *src; + S_Delta *delta = 0; + { + 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 + if (!has_sent_initial_tick) { - 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) + S_Delta *delta = 0; { - snapshot->tile_placements_count += 1; - { - S_TilePlacement *dst = &snapshot->tile_placements[dst_tile_placement_idx]; - dst->placement_kind = S_TilePlacementKind_Raw; - dst->raw_tiles = PushStructsNoZero(output->arena, u8, S_WorldSize * S_WorldSize * 4); - CopyBytes(dst->raw_tiles, tiles, S_WorldSize * S_WorldSize * 4); - } - dst_tile_placement_idx += 1; - has_sent_initial_tick = 1; + 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; } + 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; + } - // Forward range tile placements + // Push full entity deltas + for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent)) + { + S_Delta *delta = 0; { - u64 src_tile_placement_idx = 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; - if (cmd->kind == S_CmdKind_Tile) - { - S_TilePlacement *dst = &snapshot->tile_placements[src_tile_placement_idx]; - *dst = cmd->tile_placement; - dst_tile_placement_idx += 1; - src_tile_placement_idx += 1; - } - } + 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; } + delta->kind = S_DeltaKind_RawEnt; + delta->ent = *ent; } // Push debug draw information diff --git a/src/pp/pp_sim/pp_sim_core.h b/src/pp/pp_sim/pp_sim_core.h index 4aafdde2..2782fb3a 100644 --- a/src/pp/pp_sim/pp_sim_core.h +++ b/src/pp/pp_sim/pp_sim_core.h @@ -5,26 +5,7 @@ Struct(S_Key) { - U128 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; + u64 v; }; //////////////////////////////////////////////////////////// @@ -56,15 +37,27 @@ Struct(S_Shape) 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 - b32 active; S_Key key; ////////////////////////////// //- Build data + f32 exists; + Xform last_xf; Xform xf; @@ -81,33 +74,12 @@ Struct(S_Ent) Vec2 solved_dv; f32 solved_dw; - - ////////////////////////////// - //- Internal sim data - - i64 next_free_ent_num; }; -//////////////////////////////////////////////////////////// -//~ Ent container types - -Struct(S_EntArray) +Struct(S_EntBin) { - u64 count; - S_Ent *ents; -}; - -Struct(S_EntListNode) -{ - S_EntListNode *next; - S_Ent ent; -}; - -Struct(S_EntList) -{ - S_EntListNode *first; - S_EntListNode *last; - u64 count; + S_Ent *first; + S_Ent *last; }; //////////////////////////////////////////////////////////// @@ -168,21 +140,6 @@ Struct(S_Constraint) 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 @@ -191,8 +148,38 @@ Struct(S_World) i64 tick; i64 time_ns; - S_Ent *ents; 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) @@ -200,11 +187,9 @@ Struct(S_Snapshot) i64 tick; i64 time_ns; - S_Ent *ents; - i64 ents_count; - - S_TilePlacement *tile_placements; - u64 tile_placements_count; + i64 deltas_count; + S_DeltaNode *first_delta_node; + S_DeltaNode *last_delta_node; }; Struct(S_SnapshotNode) @@ -213,23 +198,13 @@ Struct(S_SnapshotNode) S_Snapshot snapshot; }; -//////////////////////////////////////////////////////////// -//~ Iterator types - -Struct(S_Iter) -{ - S_World *world; - i64 cur_idx; -}; - //////////////////////////////////////////////////////////// //~ Command types Enum(S_CmdKind) { S_CmdKind_Nop, - S_CmdKind_Tile, - S_CmdKind_Spawn, + S_CmdKind_Delta, S_CmdKind_Control, }; @@ -237,11 +212,8 @@ Struct(S_Cmd) { S_CmdKind kind; - // Tiles - S_TilePlacement tile_placement; - - // Spawn - S_Ent ent; + // Delta + S_Delta delta; // Control S_Key target; @@ -331,13 +303,8 @@ Struct(S_Ctx) S_OutputState output_states[2]; }; -Struct(S_ReadonlyCtx) -{ - S_Ent nil_ent; -}; - extern S_Ctx S; -extern Readonly S_ReadonlyCtx S_ro; +extern Readonly S_Ent S_NilEnt; //////////////////////////////////////////////////////////// //~ Bootstrap @@ -361,7 +328,11 @@ S_Key S_RandKey(void); //~ Tile helpers 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 @@ -385,24 +356,13 @@ S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1); //////////////////////////////////////////////////////////// //~ Lookup helpers -S_Lookup S_LookupFromWorld(Arena *arena, S_World *world); -S_Ent *S_EntFromKey(S_Lookup *lookup, S_Key key); +S_Ent *S_EntFromKey(S_World *world, S_Key key); //////////////////////////////////////////////////////////// //~ Iteration helpers -S_Ent *S_FirstEnt(S_Iter *iter, S_World *world); -S_Ent *S_NextEnt(S_Iter *iter); - -//////////////////////////////////////////////////////////// -//~ Snapshot helpers - -S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot); - -//////////////////////////////////////////////////////////// -//~ Sorting - -MergesortCompareFuncDef(S_SortEntsByKeyCmp, arg_a, arg_b, _); +S_Ent *S_FirstEnt(S_World *world); +S_Ent *S_NextEnt(S_Ent *e); //////////////////////////////////////////////////////////// //~ Debug draw diff --git a/src/pp/pp_sim/pp_sim_tiles.cg b/src/pp/pp_sim/pp_sim_tiles.cg index 83b0c90a..30f2cb31 100644 --- a/src/pp/pp_sim/pp_sim_tiles.cg +++ b/src/pp/pp_sim/pp_sim_tiles.cg @@ -4,13 +4,13 @@ Vec2I32 S_TilePosFromWorldPos(Vec2 p) { Vec2I32 result; - result.x = ClampI32((p.x + S_WorldSize / 2) * 2, 0, (S_WorldSize * 2) - 1); - result.y = ClampI32((p.y + 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_WorldPitch * ((f32)S_WorldPitch / (f32)S_TilesPitch)) * 2, 0, S_TilesPitch - 1); return result; } 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; } diff --git a/src/pp/pp_sim/pp_sim_tiles.cgh b/src/pp/pp_sim/pp_sim_tiles.cgh index 0bba81b6..51184f05 100644 --- a/src/pp/pp_sim/pp_sim_tiles.cgh +++ b/src/pp/pp_sim/pp_sim_tiles.cgh @@ -1,7 +1,9 @@ //////////////////////////////////////////////////////////// //~ 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) \ X(Empty) \ diff --git a/src/pp/pp_sim/pp_sim_transcode.c b/src/pp/pp_sim/pp_sim_transcode.c index 5595a36a..8ddf7dd8 100644 --- a/src/pp/pp_sim/pp_sim_transcode.c +++ b/src/pp/pp_sim/pp_sim_transcode.c @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// //~ 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; result.ok = 1; @@ -24,27 +24,25 @@ S_TranscodeResult S_TranscodeLevel(Arena *arena, b32 pack, String packed, S_Worl } else { - bb = BB_BuffFromString(packed); + bb = BB_BuffFromString(src_packed); br = BB_ReaderFromBuff(&bb); result.ok = BB_ReadUBits(&br, 32) == level_magic; result.version = (S_Tv)BB_ReadUBits(&br, 32); + result.unpacked = PushStruct(arena, S_World); } ////////////////////////////// //- Transcode world metadata - if (result.ok) + if (pack) { - if (pack) - { - BB_WriteIBits(&bw, world->tick, 64); - BB_WriteIBits(&bw, world->time_ns, 64); - } - else - { - result.unpacked.world.tick = BB_ReadIBits(&br, 64); - result.unpacked.world.time_ns = BB_ReadIBits(&br, 64); - } + BB_WriteIBits(&bw, src_world->tick, 64); + BB_WriteIBits(&bw, src_world->time_ns, 64); + } + else + { + result.unpacked->tick = BB_ReadIBits(&br, 64); + result.unpacked->time_ns = BB_ReadIBits(&br, 64); } ////////////////////////////// @@ -52,28 +50,27 @@ S_TranscodeResult S_TranscodeLevel(Arena *arena, b32 pack, String packed, S_Worl // TODO: Compress tile data - if (result.ok) + if (pack) { - u64 tiles_count = S_WorldSize * S_WorldSize * 4; - if (pack) + String tiles_str = Zi; + tiles_str.len = S_TilesCount; + tiles_str.text = src_world->tiles; + BB_WriteUBits(&bw, tiles_str.len, 64); + BB_WriteBytes(&bw, tiles_str); + } + else + { + u64 raw_tiles_count = BB_ReadUBits(&br, 64); + u8 *raw_tiles = BB_ReadBytesRaw(&br, raw_tiles_count); + if (raw_tiles && raw_tiles_count == S_TilesCount) { - String tiles_str = Zi; - tiles_str.len = tiles_count; - tiles_str.text = tiles; - BB_WriteBytes(&bw, tiles_str); + result.unpacked->tiles = PushStructsNoZero(arena, u8, raw_tiles_count); + CopyBytes(result.unpacked->tiles, raw_tiles, raw_tiles_count); } else { - u8 *raw_tiles = BB_ReadBytesRaw(&br, tiles_count); - if (raw_tiles) - { - result.unpacked.tiles = PushStructsNoZero(arena, u8, S_WorldSize * S_WorldSize * 4); - CopyStructs(result.unpacked.tiles, raw_tiles, tiles_count); - } - else - { - result.ok = 0; - } + result.unpacked->tiles = PushStructs(arena, u8, S_TilesCount); + result.ok = 0; } } @@ -82,47 +79,46 @@ S_TranscodeResult S_TranscodeLevel(Arena *arena, b32 pack, String packed, S_Worl // TODO: Compress entity data - // Write entity size & alignment - u32 ent_size = sizeof(S_Ent); - u32 ent_align = alignof(S_Ent); if (result.ok) { if (pack) { + u32 ent_size = sizeof(S_Ent); + u32 ent_align = alignof(S_Ent); + i64 ents_count = src_world->ents_count; BB_WriteUBits(&bw, ent_size, 32); BB_WriteUBits(&bw, ent_align, 32); - } - else - { - ent_size = BB_ReadUBits(&br, 32); - ent_align = BB_ReadUBits(&br, 32); - } - } - - 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) + BB_WriteUBits(&bw, ents_count, 64); + for (S_Ent *ent = S_FirstEnt(src_world); ent->valid; ent = S_NextEnt(ent)) { - if (ent_size == sizeof(S_Ent) && ent_align == alignof(S_Ent)) + BB_WriteBytes(&bw, StringFromStruct(ent)); + } + } + else + { + i64 ent_size = BB_ReadUBits(&br, 32); + i64 ent_align = BB_ReadUBits(&br, 32); + i64 ents_count = BB_ReadUBits(&br, 64); + if (ent_size == sizeof(S_Ent) && ent_align == alignof(S_Ent)) + { + for (i64 i = 0; i < ents_count; ++i) { - result.unpacked.world.ents_count = ents_count; - 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 diff --git a/src/pp/pp_sim/pp_sim_transcode.h b/src/pp/pp_sim/pp_sim_transcode.h index a3663119..548a79e6 100644 --- a/src/pp/pp_sim/pp_sim_transcode.h +++ b/src/pp/pp_sim/pp_sim_transcode.h @@ -14,15 +14,12 @@ Struct(S_TranscodeResult) { b32 ok; S_Tv version; + String packed; - struct - { - S_World world; - u8 *tiles; - } unpacked; + S_World *unpacked; }; //////////////////////////////////////////////////////////// //~ 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); diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 05aeee34..52aff2b7 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -289,7 +289,7 @@ void V_TickForever(WaveLaneCtx *lane) Arena *perm = 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 min_zoom = 0.03; const f32 max_zoom = 15.0; @@ -298,11 +298,17 @@ void V_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Init vis state - V.world_arena = AcquireArena(Gibi(64)); - V.world = PushStruct(V.world_arena, S_World); + Arena *sim_debug_arena = AcquireArena(Gibi(64)); + 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_Texture2DRef gpu_tiles_ref = Zi; { @@ -319,7 +325,7 @@ void V_TickForever(WaveLaneCtx *lane) G_CopyCpuToTexture( cl, 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)) ); } @@ -373,7 +379,6 @@ void V_TickForever(WaveLaneCtx *lane) while (!shutdown) { shutdown = Atomic32Fetch(&V.shutdown); - S_Iter iter = Zi; ////////////////////////////// //- Begin frame @@ -450,8 +455,7 @@ void V_TickForever(WaveLaneCtx *lane) //- Transcode swap state if (swapout) { - BB_WriteUBits(&bw, V.player_key.v.hi, 64); - BB_WriteUBits(&bw, V.player_key.v.lo, 64); + BB_WriteUBits(&bw, V.player_key.v, 64); BB_WriteBit(&bw, last_frame->is_editing); BB_WriteF32(&bw, last_frame->edit_camera_pos.x); BB_WriteF32(&bw, last_frame->edit_camera_pos.y); @@ -460,8 +464,7 @@ void V_TickForever(WaveLaneCtx *lane) } else { - V.player_key.v.hi = BB_ReadUBits(&br, 64); - V.player_key.v.lo = BB_ReadUBits(&br, 64); + V.player_key.v = BB_ReadUBits(&br, 64); frame->is_editing = BB_ReadBit(&br); frame->edit_camera_pos.x = 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); ////////////////////////////// - //- 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; + if (snapshot->tick > world->tick) { - S_Snapshot *snapshot = &n->snapshot; - if (snapshot->tick > V.world->tick) + world->tick = snapshot->tick; + world->time_ns = snapshot->time_ns; + for (S_DeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next) { - for (u64 placement_idx = 0; placement_idx < snapshot->tile_placements_count; ++placement_idx) + 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( 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)) + gpu_tiles, VEC3I32(dirty_tile_rect.p0.x, dirty_tile_rect.p0.y, 0), + world->tiles, VEC3I32(tiles_dims.x, tiles_dims.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); - V.world = S_WorldFromSnapshot(V.world_arena, &sim_output->last_snapshot_node->snapshot); - V.lookup = S_LookupFromWorld(V.world_arena, V.world); + ResetArena(sim_debug_arena); // Copy sim debug info - V.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); - CopyStructs(V.debug_draw_descs, sim_output->debug_draw_descs, V.debug_draw_descs_count); + sim_debug_draw_descs_count = sim_output->debug_draw_descs_count; + sim_debug_draw_descs = PushStructsNoZero(sim_debug_arena, S_DebugDrawDesc, sim_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 @@ -688,8 +742,8 @@ void V_TickForever(WaveLaneCtx *lane) Vec2 diff = SubVec2(last_target_cursor, target_cursor); 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.y = ClampF32(frame->edit_camera_pos.y, -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_pitch / 2, world_pitch / 2); target_camera_pos = frame->edit_camera_pos; target_camera_zoom = frame->edit_camera_zoom; } @@ -698,13 +752,13 @@ void V_TickForever(WaveLaneCtx *lane) Vec2 look_ratio = Zi; look_ratio.y = 0.25; 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 = AddVec2(target_camera_pos, MulVec2Vec2(player->look, look_ratio)); target_camera_zoom = 1; } - target_camera_pos.x = ClampF32(target_camera_pos.x, -world_size / 2, world_size / 2); - target_camera_pos.y = ClampF32(target_camera_pos.y, -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_pitch / 2, world_pitch / 2); target_camera_zoom = ClampF32(target_camera_zoom, min_zoom, max_zoom); // 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 = AddVec2I32(tile_range.p1, VEC2I32(1, 1)); - S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Tile); - cmd->tile_placement.placement_kind = S_TilePlacementKind_Range; - cmd->tile_placement.tile_kind = last_frame->equipped_tile; - cmd->tile_placement.range = tile_range; + S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Delta); + cmd->delta.kind = S_DeltaKind_Tile; + cmd->delta.tile_kind = last_frame->equipped_tile; + 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: { - S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Spawn); - S_Ent *ent = &cmd->ent; - *ent = *S_EntFromKey(&V.lookup, V.player_key); + S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Delta); + cmd->delta.kind = S_DeltaKind_RawEnt; + S_Ent *ent = &cmd->delta.ent; ent->key = V.player_key; + ent->xf = XformFromPos(frame->world_cursor); ent->move_speed = 0.05; ent->local_shape = S_ShapeFromDesc( .mass = 10, .count = 1, .radius = 0.3, ); - ent->xf = XformFromPos(frame->world_cursor); ent->has_weapon = 1; } 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; { - S_Ent *player = S_EntFromKey(&V.lookup, V.player_key); Vec2 center = MulXformV2(player->xf, player->local_shape.centroid); look = SubVec2(frame->world_cursor, center); } @@ -2372,7 +2471,7 @@ void V_TickForever(WaveLaneCtx *lane) //- Draw entities // 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_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 - 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); i32 detail = 24; f32 radius = 5; @@ -2513,7 +2612,6 @@ void V_TickForever(WaveLaneCtx *lane) params.camera_pos = frame->camera_pos; params.camera_zoom = frame->camera_zoom; - params.world_size = world_size; params.tiles = gpu_tiles_ref; params.shape_verts = dverts_ro; } diff --git a/src/pp/pp_vis/pp_vis_core.h b/src/pp/pp_vis/pp_vis_core.h index 9c28656e..626be30b 100644 --- a/src/pp/pp_vis/pp_vis_core.h +++ b/src/pp/pp_vis/pp_vis_core.h @@ -12,8 +12,10 @@ 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_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 @@ -279,12 +281,7 @@ Struct(V_Frame) Struct(V_Ctx) { - Arena *world_arena; - S_World *world; - S_Lookup lookup; S_Key player_key; - u64 debug_draw_descs_count; - S_DebugDrawDesc *debug_draw_descs; i64 panels_count; i64 windows_count; diff --git a/src/pp/pp_vis/pp_vis_shaders.cgh b/src/pp/pp_vis/pp_vis_shaders.cgh index 853d67a3..a361c3b9 100644 --- a/src/pp/pp_vis/pp_vis_shaders.cgh +++ b/src/pp/pp_vis/pp_vis_shaders.cgh @@ -33,7 +33,6 @@ Struct(V_DParams) Vec2 camera_pos; f32 camera_zoom; - f32 world_size; G_Texture2DRef tiles; G_StructuredBufferRef quads; G_StructuredBufferRef shape_verts; diff --git a/src/pp/pp_vis/pp_vis_shaders.g b/src/pp/pp_vis/pp_vis_shaders.g index 8603b0c0..56e2aa48 100644 --- a/src/pp/pp_vis/pp_vis_shaders.g +++ b/src/pp/pp_vis/pp_vis_shaders.g @@ -22,7 +22,7 @@ ComputeShader2D(V_BackdropCS, 8, 8) Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos); 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_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) && @@ -253,14 +253,16 @@ PixelShader(V_OverlayPS, V_OverlayPSOutput, V_OverlayPSInput input) // } // else { - if (world_pos.x > -(S_WorldSize / 2) && - world_pos.y > -(S_WorldSize / 2) && - world_pos.x < (S_WorldSize / 2) && - world_pos.y < (S_WorldSize / 2) && - tile_pos.x >= tile_selection.p0.x && - tile_pos.x <= tile_selection.p1.x && - tile_pos.y >= tile_selection.p0.y && - tile_pos.y <= tile_selection.p1.y) + if ( + world_pos.x > -(S_WorldPitch / 2) && + world_pos.y > -(S_WorldPitch / 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.p1.x && + tile_pos.y >= tile_selection.p0.y && + tile_pos.y <= tile_selection.p1.y + ) { result = inner_color; }