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"
|
||||
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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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:
|
||||
Rng2I32 S_UpdateWorldFromDelta(Arena *arena, S_World *world, S_Delta *delta)
|
||||
{
|
||||
// FIXME: Bounds check tile deltas
|
||||
Rng2I32 dirty_tile_rect = Zi;
|
||||
if (0)
|
||||
{
|
||||
S_TileKind tile = placement.tile_kind;
|
||||
Rng2I32 range = placement.range;
|
||||
}
|
||||
//- 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);
|
||||
tiles[tile_idx] = (u8)tile;
|
||||
world->tiles[tile_idx] = (u8)tile;
|
||||
}
|
||||
}
|
||||
dirty_rect = range;
|
||||
} break;
|
||||
dirty_tile_rect = range;
|
||||
}
|
||||
return dirty_rect;
|
||||
|
||||
return dirty_tile_rect;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -836,114 +883,43 @@ 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))
|
||||
if (e->key.v == key.v)
|
||||
{
|
||||
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;
|
||||
result = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ 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))
|
||||
allow = 1;
|
||||
}
|
||||
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];
|
||||
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;
|
||||
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
|
||||
{
|
||||
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
|
||||
// Push full tile delta
|
||||
if (!has_sent_initial_tick)
|
||||
{
|
||||
snapshot->tile_placements_count += 1;
|
||||
S_Delta *delta = 0;
|
||||
{
|
||||
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);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node && src_tile_placement_idx < tile_placements_count; cmd_node = cmd_node->next)
|
||||
S_Delta *delta = 0;
|
||||
{
|
||||
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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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) \
|
||||
|
||||
@ -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)
|
||||
{
|
||||
BB_WriteIBits(&bw, world->tick, 64);
|
||||
BB_WriteIBits(&bw, world->time_ns, 64);
|
||||
BB_WriteIBits(&bw, src_world->tick, 64);
|
||||
BB_WriteIBits(&bw, src_world->time_ns, 64);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.unpacked.world.tick = BB_ReadIBits(&br, 64);
|
||||
result.unpacked.world.time_ns = BB_ReadIBits(&br, 64);
|
||||
}
|
||||
result.unpacked->tick = 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
|
||||
|
||||
if (result.ok)
|
||||
{
|
||||
u64 tiles_count = S_WorldSize * S_WorldSize * 4;
|
||||
if (pack)
|
||||
{
|
||||
String tiles_str = Zi;
|
||||
tiles_str.len = tiles_count;
|
||||
tiles_str.text = tiles;
|
||||
tiles_str.len = S_TilesCount;
|
||||
tiles_str.text = src_world->tiles;
|
||||
BB_WriteUBits(&bw, tiles_str.len, 64);
|
||||
BB_WriteBytes(&bw, tiles_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
u8 *raw_tiles = BB_ReadBytesRaw(&br, tiles_count);
|
||||
if (raw_tiles)
|
||||
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)
|
||||
{
|
||||
result.unpacked.tiles = PushStructsNoZero(arena, u8, S_WorldSize * S_WorldSize * 4);
|
||||
CopyStructs(result.unpacked.tiles, raw_tiles, tiles_count);
|
||||
result.unpacked->tiles = PushStructsNoZero(arena, u8, raw_tiles_count);
|
||||
CopyBytes(result.unpacked->tiles, raw_tiles, raw_tiles_count);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.unpacked->tiles = PushStructs(arena, u8, S_TilesCount);
|
||||
result.ok = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Transcode entities
|
||||
|
||||
// TODO: Compress entity data
|
||||
|
||||
// Write entity size & alignment
|
||||
if (result.ok)
|
||||
{
|
||||
if (pack)
|
||||
{
|
||||
u32 ent_size = sizeof(S_Ent);
|
||||
u32 ent_align = alignof(S_Ent);
|
||||
if (result.ok)
|
||||
{
|
||||
if (pack)
|
||||
{
|
||||
i64 ents_count = src_world->ents_count;
|
||||
BB_WriteUBits(&bw, ent_size, 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
|
||||
{
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
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);
|
||||
for (i64 i = 0; i < ents_count; ++i)
|
||||
{
|
||||
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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
{
|
||||
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(
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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) &&
|
||||
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)
|
||||
tile_pos.y <= tile_selection.p1.y
|
||||
)
|
||||
{
|
||||
result = inner_color;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user