diff --git a/src/base/base.cgh b/src/base/base.cgh index 1c4807b9..b47602a4 100644 --- a/src/base/base.cgh +++ b/src/base/base.cgh @@ -750,7 +750,7 @@ #endif //////////////////////////////////////////////////////////// -//~ Basic mixing/hashing +//~ Basic mixing // Based on Jon Maiga's "mx3" // https://jonkagstrom.com/mx3/mx3_rev2.html @@ -768,23 +768,6 @@ Inline u64 MixU64s(u64 seed_a, u64 seed_b) return MixU64((seed_a * 3) + seed_b); } -#if IsLanguageC - #define Fnv64Basis 0xCBF29CE484222325 - - // FNV-1a parameters for different hash sizes: - // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV_hash_parameters - Inline u64 HashFnv64(u64 seed, String str) - { - u64 hash = seed; - for (u64 i = 0; i < str.len; ++i) - { - hash ^= (u8)str.text[i]; - hash *= 0x100000001B3; - } - return hash; - } -#endif - //////////////////////////////////////////////////////////// //~ @hookdecl Core api diff --git a/src/base/base_cmdline.c b/src/base/base_cmdline.c index 7f3ee041..15c492a1 100644 --- a/src/base/base_cmdline.c +++ b/src/base/base_cmdline.c @@ -58,7 +58,7 @@ void BootstrapCmdline(void) { CommandlineArg arg = tmp_args[i]; CommandlineArgNode *n = PushStruct(perm, CommandlineArgNode); - u64 hash = HashFnv64(Fnv64Basis, arg.name); + u64 hash = HashString(arg.name); u64 bin_idx = hash % countof(Base.cmdline.arg_bins); n->arg = arg; n->hash = hash; @@ -85,7 +85,7 @@ String StringFromCommandlineIdx(i32 idx) CommandlineArg CommandlineArgFromName(String name) { CommandlineArg result = Zi; - u64 hash = HashFnv64(Fnv64Basis, name); + u64 hash = HashString(name); for (CommandlineArgNode *n = Base.cmdline.arg_bins[hash % countof(Base.cmdline.arg_bins)]; n; n = n->next) { if (n->hash == hash && MatchString(n->arg.name, name)) diff --git a/src/base/base_resource.c b/src/base/base_resource.c index b7736220..c7e1ae07 100644 --- a/src/base/base_resource.c +++ b/src/base/base_resource.c @@ -19,6 +19,7 @@ void BootstrapResources(u64 archive_strings_count, String *archive_strings) u64 num_entries = BB_ReadUBits(&br, 64); for (u64 i = 0; i < num_entries; ++i) { + u64 store_hash = BB_ReadUBits(&br, 64); u64 name_start = BB_ReadUBits(&br, 64); u64 name_len = BB_ReadUBits(&br, 64); u64 data_start = BB_ReadUBits(&br, 64); @@ -27,7 +28,7 @@ void BootstrapResources(u64 archive_strings_count, String *archive_strings) ResourceEntry *entry = PushStruct(perm, ResourceEntry); entry->name = STRING(name_len, archive.text + name_start); entry->data = STRING(data_len, archive.text + data_start); - entry->hash = HashFnv64(Fnv64Basis, entry->name); + entry->hash = HashStringEx(store_hash, entry->name); ResourceEntryBin *bin = &Base.resource.bins[entry->hash % countof(Base.resource.bins)]; SllQueuePushN(bin->first, bin->last, entry, next_in_bin); @@ -50,7 +51,7 @@ b32 IsResourceNil(ResourceKey resource) ResourceKey ResourceKeyFromStore(ResourceStore *store, String name) { ResourceKey result = Zi; - result.v = HashFnv64(store->v, name); + result.v = HashStringEx(store->v, name); return result; } diff --git a/src/base/base_string.c b/src/base/base_string.c index 16b1a143..81d29dc6 100644 --- a/src/base/base_string.c +++ b/src/base/base_string.c @@ -502,14 +502,21 @@ String PathFromString(Arena *arena, String str, u8 path_delimiter) u64 HashStringEx(u64 seed, String str) { - u64 result = HashFnv64(seed, str); + // FNV-1a parameters for different hash sizes: + // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV_hash_parameters + u64 result = seed + 0xCBF29CE484222325; + for (u64 i = 0; i < str.len; ++i) + { + result ^= (u8)str.text[i]; + result *= 0x100000001B3; + } result = MixU64(result); return result; } u64 HashString(String str) { - return HashStringEx(Fnv64Basis, str); + return HashStringEx(0, str); } u64 HashF_(String fmt, ...) diff --git a/src/base/base_win32/base_win32.c b/src/base/base_win32/base_win32.c index ba918b02..5d200387 100644 --- a/src/base/base_win32/base_win32.c +++ b/src/base/base_win32/base_win32.c @@ -112,7 +112,7 @@ i64 TimeNs(void) void TrueRand(String buffer) { - BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (u8 *)buffer.text, buffer.len, 0); + BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, buffer.text, buffer.len, 0); } CpuTopologyInfo GetCpuTopologyInfo(void) diff --git a/src/meta/meta.c b/src/meta/meta.c index 5e336e93..32d11efc 100644 --- a/src/meta/meta.c +++ b/src/meta/meta.c @@ -111,6 +111,7 @@ EmbedObj Embed(String store_name, String dir_path) EmbedObj result = Zi; // Generate resource archive contents + u64 store_hash = HashString(store_name); String arc_contents = Zi; { StringList files = Zi; @@ -136,7 +137,6 @@ EmbedObj Embed(String store_name, String dir_path) entry_name.len -= dir_path.len + 1; entry_name.text += dir_path.len + 1; } - entry_name = StringF(perm, "%F/%F", FmtString(store_name), FmtString(entry_name)); for (u64 i = 0; i < entry_name.len; ++i) { if (entry_name.text[i] == '\\') @@ -165,6 +165,7 @@ EmbedObj Embed(String store_name, String dir_path) // Reserve entries space u64 entry_size = 0 + + 8 // Store hash + 8 // Name start + 8 // Name end + 8 // Data start @@ -196,6 +197,7 @@ EmbedObj Embed(String store_name, String dir_path) u64 data_len = BB_GetNumBytesWritten(&bw) - data_start; // Write entry + BB_WriteUBits(&entries_bw, store_hash, 64); BB_WriteUBits(&entries_bw, name_start, 64); BB_WriteUBits(&entries_bw, name_len, 64); BB_WriteUBits(&entries_bw, data_start, 64); @@ -457,6 +459,7 @@ void BuildEntryPoint(WaveLaneCtx *lane) String shader_store_name = Lit("ShadersStore"); String c_out_file = F_GetFull(perm, StringF(perm, "%F_gen.c", FmtString(cmdline.leaf_layer_name))); String gpu_out_file = F_GetFull(perm, StringF(perm, "%F_gen.g", FmtString(cmdline.leaf_layer_name))); + u64 shader_store_hash = HashString(shader_store_name); if (lane->idx == 0 && GetBuildStatus() == 0) { @@ -505,8 +508,8 @@ void BuildEntryPoint(WaveLaneCtx *lane) String full = F_GetFullCrossPlatform(perm, StringF(perm, "%F/%F", FmtString(token_parent_dir), FmtString(arg_dir))); if (F_IsDir(full)) { - u64 hash = HashFnv64(Fnv64Basis, StringF(perm, "%F/", FmtString(store_name))); - String line = StringF(perm, "ResourceStore %F = { 0x%F };", FmtString(store_name), FmtHex(hash)); + u64 store_hash = HashString(store_name); + String line = StringF(perm, "ResourceStore %F = { 0x%F };", FmtString(store_name), FmtHex(store_hash)); PushStringToList(perm, &c_store_lines, line); } else @@ -531,8 +534,8 @@ void BuildEntryPoint(WaveLaneCtx *lane) : kind == M_EntryKind_ComputeShader ? Lit("ComputeShader") : Lit(""); String shader_name = arg0_tok->s; - u64 hash = HashFnv64(Fnv64Basis, StringF(perm, "%F/%F", FmtString(shader_store_name), FmtString(shader_name))); - String line = StringF(perm, "%F %F = { 0x%F };", FmtString(shader_type), FmtString(shader_name), FmtHex(hash)); + u64 shader_resource_hash = HashStringEx(shader_store_hash, shader_name); + String line = StringF(perm, "%F %F = { 0x%F };", FmtString(shader_type), FmtString(shader_name), FmtHex(shader_resource_hash)); PushStringToList(perm, &c_shader_lines, line); } else diff --git a/src/meta/meta_lay.c b/src/meta/meta_lay.c index 4eca854b..76089d3e 100644 --- a/src/meta/meta_lay.c +++ b/src/meta/meta_lay.c @@ -97,7 +97,7 @@ M_TokenFileList M_TokensFromSrcDirs(Arena *arena, StringList src_dirs) if (StringEndsWith(file_name, Lit(".lay"))) { String tmp_full = F_GetFull(scratch.arena, file_name); - u64 hash = HashFnv64(Fnv64Basis, tmp_full); + u64 hash = HashString(tmp_full); if (DictValueFromHash(dedup_dict, hash) == 0) { SetDictValue(scratch.arena, dedup_dict, hash, 1); @@ -255,7 +255,7 @@ M_LayerList M_LayersFromTokenFiles(Arena *arena, M_TokenFileList lexed) for (u64 i = 0; i < countof(M_entry_kind_rules); ++i) { char *rule_cstr = M_entry_kind_rules[i]; - u64 rule_hash = HashFnv64(Fnv64Basis, StringFromCstrNoLimit(rule_cstr)); + u64 rule_hash = HashString(StringFromCstrNoLimit(rule_cstr)); SetDictValue(scratch.arena, rules_dict, rule_hash, i + 1); } @@ -280,7 +280,7 @@ M_LayerList M_LayersFromTokenFiles(Arena *arena, M_TokenFileList lexed) { M_Entry *entry = M_PushEntry(arena, layer, M_EntryKind_Unknown, entry_token, args_count, arg_tokens); { - u64 entry_hash = HashFnv64(Fnv64Basis, entry_token->s); + u64 entry_hash = HashString(entry_token->s); u64 kind_plus_1 = DictValueFromHash(rules_dict, entry_hash); if (kind_plus_1 > 0) { @@ -390,7 +390,7 @@ M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList start String name = name_entry->arg_tokens[0]->s; - u64 name_hash = HashFnv64(Fnv64Basis, name); + u64 name_hash = HashString(name); DictEntry *ptr_dict_entry = EnsureDictEntry(scratch.arena, layer_ptr_to_state, (u64)layer); DictEntry *name_dict_entry = EnsureDictEntry(scratch.arena, layer_name_to_state, name_hash); @@ -418,7 +418,7 @@ M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList start for (StringListNode *sln = starting_layer_names.first; sln; sln = sln->next) { String name = sln->s; - u64 name_hash = HashFnv64(Fnv64Basis, name); + u64 name_hash = HashString(name); IterState *state = (IterState *)DictValueOrNilFromHash(layer_name_to_state, name_hash, (u64)&NilIterState); M_Layer *layer = state->layer; if (layer->valid) @@ -497,7 +497,7 @@ M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList start if (should_include) { String downstream_layer_name = downstream_layer_token->s; - u64 hash = HashFnv64(Fnv64Basis, downstream_layer_name); + u64 hash = HashString(downstream_layer_name); IterState *downstream_layer_state = (IterState *)DictValueOrNilFromHash(layer_name_to_state, hash, (u64)&NilIterState); M_Layer *downstream_layer = downstream_layer_state->layer; if (downstream_layer->valid) @@ -538,7 +538,7 @@ M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList start if (dep_token->valid) { String dep_name = dep_token->s; - u64 hash = HashFnv64(Fnv64Basis, dep_name); + u64 hash = HashString(dep_name); IterState *dep_layer_state = (IterState *)DictValueOrNilFromHash(layer_name_to_state, hash, (u64)&NilIterState); M_Layer *dep_layer = dep_layer_state->layer; if (dep_layer->valid) diff --git a/src/net/net.c b/src/net/net.c index ab351996..495814a5 100644 --- a/src/net/net.c +++ b/src/net/net.c @@ -58,7 +58,7 @@ void N_ReleaseHost(N_Host *host) u64 N_HashFromAddress(PLT_Address address) { - return HashFnv64(Fnv64Basis, StringFromStruct(&address)); + return HashString(StringFromStruct(&address)); } N_Channel *N_ChannelFromAddress(N_Host *host, PLT_Address address) @@ -227,9 +227,9 @@ void N_ReleaseChannel(N_Channel *channel) u64 N_HashFromMsg(N_ChannelId channel_id, u64 msg_id) { - u64 result = Fnv64Basis; - result = HashFnv64(result, StringFromStruct(&channel_id)); - result = HashFnv64(result, StringFromStruct(&msg_id)); + u64 result = 0; + result = HashStringEx(result, StringFromStruct(&channel_id)); + result = HashStringEx(result, StringFromStruct(&msg_id)); return result; } diff --git a/src/pp/pp.c b/src/pp/pp.c index 646f3d5b..98809ab1 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -6,6 +6,10 @@ Readonly P_Ent P_NilEnt = { .look = { 0, -1 }, }; +Readonly P_Frame P_NilFrame = { + 0 +}; + //////////////////////////////////////////////////////////// //~ Bootstrap @@ -37,14 +41,19 @@ b32 P_IsEntNil(P_Ent *ent) return ent == 0 || ent == &P_NilEnt; } -b32 P_MatchKey(P_Key a, P_Key b) +b32 P_IsFrameNil(P_Frame *frame) { - return a.v == b.v; + return frame == 0 || frame == &P_NilFrame; } //////////////////////////////////////////////////////////// //~ Key helpers +b32 P_MatchKey(P_Key a, P_Key b) +{ + return a.v == b.v; +} + P_Key P_RandKey(void) { // TODO: Don't use true randomness for entity keys. It's overkill & non-deterministic. @@ -73,91 +82,6 @@ String P_NameFromTileKind(P_TileKind kind) return result; } -//////////////////////////////////////////////////////////// -//~ Delta helpers - -void P_UpdateWorldFromDelta(Arena *arena, P_World *world, P_Delta *delta) -{ - // FIXME: Bounds check tile deltas - if (0) - { - } - //- Reset - if (delta->kind == P_DeltaKind_Reset) - { - // FIXME: Free list entities - world->ents_count = 0; - world->first_ent = 0; - world->last_ent = 0; - ZeroStructs(world->tiles, P_TilesCount); - ZeroStructs(world->ent_bins, world->ent_bins_count); - } - //- Raw ent - if (delta->kind == P_DeltaKind_RawEnt) - { - P_Key key = delta->ent.key; - P_Ent *ent = P_EntFromKey(world, key); - if (!ent->valid) - { - // FIXME: Use ent free list - ent = PushStructNoZero(arena, P_Ent); - *ent = P_NilEnt; - ent->key = key; - P_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; - } - P_Ent *old_next = ent->next; - P_Ent *old_prev = ent->prev; - P_Ent *old_next_in_bin = ent->next_in_bin; - P_Ent *old_prev_in_bin = ent->prev_in_bin; - { - P_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 == P_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; - Vec2 src_tile_pos = VEC2(src_tile_x, src_tile_y); - i32 src_tile_idx = P_TileIdxFromTilePos(src_tile_pos); - u8 src_tile = delta->raw_tiles[src_tile_idx]; - - Vec2 tile_pos = VEC2(tile_x, tile_y); - i32 tile_idx = P_TileIdxFromTilePos(tile_pos); - world->tiles[tile_idx] = src_tile; - } - } - } - //- Tile range - else if (delta->kind == P_DeltaKind_Tile) - { - P_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) - { - Vec2 tile_pos = VEC2(tile_x, tile_y); - i32 tile_idx = P_TileIdxFromTilePos(tile_pos); - world->tiles[tile_idx] = (u8)tile; - } - } - } -} //////////////////////////////////////////////////////////// //~ Shape helpers @@ -1106,12 +1030,14 @@ Vec2 P_EdgePointFromShape(P_Shape shape, Vec2 dir) //////////////////////////////////////////////////////////// //~ Lookup helpers -P_Ent *P_EntFromKeyEx(P_World *world, P_Key key, i64 tick) +P_Ent *P_EntFromKey(P_Frame *frame, P_Key key) { P_Ent *result = &P_NilEnt; - if (!P_IsKeyNil(key) && world->ent_bins_count > 0) + P_World *world = frame->world; + if (!P_IsKeyNil(key) && frame->tick > 0 && frame->ents_count > 0 && frame->ent_bins_count > 0) { - P_EntBin *bin = &world->ent_bins[key.v % world->ent_bins_count]; + i64 tick = frame->tick; + P_EntBin *bin = &frame->ent_bins[key.v % frame->ent_bins_count]; for (P_Ent *e = bin->first; e; e = e->next_in_bin) { if (e->key.v == key.v) @@ -1124,20 +1050,15 @@ P_Ent *P_EntFromKeyEx(P_World *world, P_Key key, i64 tick) return result; } -P_Ent *P_EntFromKey(P_World *world, P_Key key) -{ - return P_EntFromKeyEx(world, key, 0); -} - //////////////////////////////////////////////////////////// //~ Iteration helpers -P_Ent *P_FirstEnt(P_World *world) +P_Ent *P_FirstEnt(P_Frame *frame) { P_Ent *result = &P_NilEnt; - if (world->first_ent) + if (frame->first_ent) { - result = world->first_ent; + result = frame->first_ent; } return result; } @@ -1159,51 +1080,10 @@ P_Ent *P_PushTempEnt(Arena *arena, P_EntList *list) ++list->count; P_Ent *ent = &n->ent; *ent = P_NilEnt; - ent->valid = 1; ent->exists = 1; return ent; } -void P_SpawnEntsFromList(Arena *arena, P_World *world, P_EntList ents) -{ - for (P_EntListNode *n = ents.first; n; n = n->next) - { - P_Ent *src = &n->ent; - P_Key key = src->key; - if (!P_IsKeyNil(src->key)) - { - P_EntBin *bin = &world->ent_bins[key.v % world->ent_bins_count]; - P_Ent *dst = bin->first; - for (; dst; dst = dst->next_in_bin) - { - if (P_MatchKey(dst->key, key)) - { - break; - } - } - if (!dst) - { - // FIXME: Use free list - dst = PushStructNoZero(arena, P_Ent); - DllQueuePush(world->first_ent, world->last_ent, dst); - DllQueuePushNP(bin->first, bin->last, dst, next_in_bin, prev_in_bin); - } - P_Ent *old_next = dst->next; - P_Ent *old_prev = dst->prev; - P_Ent *old_next_in_bin = dst->next_in_bin; - P_Ent *old_prev_in_bin = dst->prev_in_bin; - { - *dst = *src; - } - dst->next = old_next; - dst->prev = old_prev; - dst->next_in_bin = old_next_in_bin; - dst->prev_in_bin = old_prev_in_bin; - ++world->ents_count; - } - } -} - //////////////////////////////////////////////////////////// //~ Debug draw @@ -1267,3 +1147,263 @@ void P_DebugDrawShape(P_Shape shape, Vec4 srgb) P_tl.debug_draw_nodes_count += 1; } } + +//////////////////////////////////////////////////////////// +//~ World + +P_World *P_AcquireWorld(void) +{ + P_World *world = 0; + { + Arena *arena = AcquireArena(Gibi(64)); + world = PushStruct(arena, P_World); + world->arena = arena; + } + world->frames_arena = AcquireArena(Gibi(64)); + world->statics_arena = AcquireArena(Gibi(64)); + + world->first_frame = &P_NilFrame; + world->last_frame = &P_NilFrame; + world->frame_bins_count = Kibi(1); + world->frame_bins = PushStructs(world->arena, P_FrameBin, world->frame_bins_count); + + // TODO + + world->tiles = PushStructs(world->arena, u8, P_TilesCount); + + TrueRand(StringFromStruct(&world->seed)); + return world; +} + +void P_UpdateWorldFromSnapshots(P_World *world, P_SnapshotList snapshots) +{ + b32 tiles_dirty = 0; + for (P_SnapshotNode *n = snapshots.first; n; n = n->next) + { + P_Snapshot *snapshot = &n->snapshot; + // FIXME: Process intermediate ticks + if (snapshot->tick > world->last_frame->tick) + { + P_Frame *src_frame = P_FrameFromTick(world, snapshot->src_tick); + P_Frame *frame = P_PushFrame(world, src_frame, snapshot->tick); + world->seed = snapshot->world_seed; + frame->time_ns = snapshot->time_ns; + + if (frame->ents_count == 0) + { + for (P_DeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next) + { + P_Delta *delta = &dn->delta; + // FIXME: Bounds check tile deltas + if (0) + { + } + //- Reset + else if (delta->kind == P_DeltaKind_Reset) + { + // FIXME: Free list entities + frame->ents_count = 0; + frame->first_ent = 0; + frame->last_ent = 0; + ZeroStructs(world->tiles, P_TilesCount); + ZeroStructs(frame->ent_bins, frame->ent_bins_count); + tiles_dirty = 1; + } + //- Raw ent + else if (delta->kind == P_DeltaKind_RawEnt) + { + P_Ent tmp_ent = delta->ent; + P_EntListNode tmp_ent_node = Zi; + tmp_ent_node.ent = tmp_ent; + P_EntList ent_list = Zi; + ent_list.first = &tmp_ent_node; + ent_list.last = &tmp_ent_node; + P_SpawnEntsFromList(frame, ent_list); + } + //- Raw tiles + else if (delta->kind == P_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; + Vec2 src_tile_pos = VEC2(src_tile_x, src_tile_y); + i32 src_tile_idx = P_TileIdxFromTilePos(src_tile_pos); + u8 src_tile = delta->raw_tiles[src_tile_idx]; + + Vec2 tile_pos = VEC2(tile_x, tile_y); + i32 tile_idx = P_TileIdxFromTilePos(tile_pos); + world->tiles[tile_idx] = src_tile; + } + } + tiles_dirty = 1; + } + //- Tile range + else if (delta->kind == P_DeltaKind_Tile) + { + P_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) + { + Vec2 tile_pos = VEC2(tile_x, tile_y); + i32 tile_idx = P_TileIdxFromTilePos(tile_pos); + world->tiles[tile_idx] = (u8)tile; + } + } + tiles_dirty = 1; + } + } + + + // FIXME: Real prune + // for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) + // { + // ent->exists = 0; + // } + } + } + } + + // TODO: Rehash statics + // if (tiles_dirty) + // { + // } +} + +void P_SpawnEntsFromList(P_Frame *frame, P_EntList ents) +{ + P_World *world = frame->world; + for (P_EntListNode *n = ents.first; n; n = n->next) + { + P_Ent *src = &n->ent; + P_Key key = src->key; + if (!P_IsKeyNil(src->key)) + { + P_EntBin *bin = &frame->ent_bins[key.v % frame->ent_bins_count]; + P_Ent *dst = bin->first; + for (; dst; dst = dst->next_in_bin) + { + if (dst->key.v == key.v) + { + break; + } + } + if (!dst) + { + // FIXME: Use free list + dst = PushStructNoZero(world->arena, P_Ent); + DllQueuePush(frame->first_ent, frame->last_ent, dst); + DllQueuePushNP(bin->first, bin->last, dst, next_in_bin, prev_in_bin); + } + P_Ent *old_next = dst->next; + P_Ent *old_prev = dst->prev; + P_Ent *old_next_in_bin = dst->next_in_bin; + P_Ent *old_prev_in_bin = dst->prev_in_bin; + { + *dst = *src; + } + dst->next = old_next; + dst->prev = old_prev; + dst->next_in_bin = old_next_in_bin; + dst->prev_in_bin = old_prev_in_bin; + ++frame->ents_count; + } + } +} + +P_Frame *P_FrameFromTick(P_World *world, i64 tick) +{ + P_Frame *result = &P_NilFrame; + if (world->frame_bins_count > 0) + { + u64 hash = MixU64(tick); + P_FrameBin *bin = &world->frame_bins[hash % world->frame_bins_count]; + for (P_Frame *frame = bin->first; frame; frame = frame->next_in_bin) + { + if (frame->tick == tick) + { + result = frame; + break; + } + } + } + return result; +} + +void P_ClearFrames(P_World *world, i64 tick_min, i64 tick_max) +{ + // TODO: Fast path for when range encompasses all frames in the world + // TODO: Don't need linear search + P_Frame *frame = world->first_frame; + while (!P_IsFrameNil(frame)) + { + P_Frame *next_frame = frame->next; + if (frame->tick >= tick_min && frame->tick <= tick_max) + { + // FIXME: Freelist ents + + // FIXME: Freelist frame + + u64 hash = MixU64(frame->tick); + P_FrameBin *bin = &world->frame_bins[hash % world->frame_bins_count]; + DllQueueRemoveNPZ(&P_NilFrame, world->first_frame, world->last_frame, frame, next, prev); + DllQueueRemoveNPZ(0, bin->first, bin->last, frame, next_in_bin, prev_in_bin); + } + else + { + break; + } + frame = next_frame; + } +} + +P_Frame *P_PushFrame(P_World *world, P_Frame *src_frame, i64 tick) +{ + Assert(!(src_frame->world == world && tick <= src_frame->tick)); // Can't read from tick that is being overwritten by new tick + P_ClearFrames(world, tick, I64Max); + + P_Frame *frame = PushStruct(world->frames_arena, P_Frame); + { + // FIXME: Pull from freelist + + frame->world = world; + frame->tick = tick; + frame->time_ns = src_frame->time_ns; + + frame->ent_bins_count = Kibi(16); + frame->ent_bins = PushStructs(world->frames_arena, P_EntBin, frame->ent_bins_count); + + u64 hash = MixU64(tick); + P_FrameBin *bin = &world->frame_bins[hash % world->frame_bins_count]; + + DllQueuePushNPZ(&P_NilFrame, world->first_frame, world->last_frame, frame, next, prev); + DllQueuePushNPZ(0, bin->first, bin->last, frame, next_in_bin, prev_in_bin); + } + + for (P_Ent *src = P_FirstEnt(src_frame); !P_IsEntNil(src); src = P_NextEnt(src)) + { + // FIXME: Pull from freelist + P_Ent *dst = PushStruct(world->frames_arena, P_Ent); + *dst = *src; + P_EntBin *bin = &frame->ent_bins[src->key.v % frame->ent_bins_count]; + DllQueuePush(frame->first_ent, frame->last_ent, dst); + DllQueuePushNP(bin->first, bin->last, dst, next_in_bin, prev_in_bin); + ++frame->ents_count; + } + + return frame; +} + +//////////////////////////////////////////////////////////// +//~ Step + +P_Frame *P_StepWorld(P_World *world, P_Frame *prev_frame, P_CmdList cmds) +{ + P_Frame *result = &P_NilFrame; + return result; +} diff --git a/src/pp/pp.h b/src/pp/pp.h index db48a4ec..11446cd7 100644 --- a/src/pp/pp.h +++ b/src/pp/pp.h @@ -52,7 +52,6 @@ Struct(P_Ent) //- Persistent data P_Key key; - b32 valid; ////////////////////////////// //- Build data @@ -62,7 +61,7 @@ Struct(P_Ent) b32 is_player; f32 health; - Xform last_xf; + Xform prev_xf; Xform xf; Vec2 move; @@ -112,9 +111,22 @@ Struct(P_EntBin) //////////////////////////////////////////////////////////// //~ World types -Struct(P_World) +Struct(P_Frame) { - u64 seed; + ////////////////////////////// + //- Internal world state + + struct P_World *world; + + P_Frame *next; + P_Frame *prev; + + P_Frame *next_in_bin; + P_Frame *prev_in_bin; + + ////////////////////////////// + //- Frame state + i64 tick; i64 time_ns; @@ -124,6 +136,28 @@ Struct(P_World) i64 ent_bins_count; P_EntBin *ent_bins; +}; + +Struct(P_FrameBin) +{ + P_Frame *first; + P_Frame *last; +}; + +Struct(P_World) +{ + Arena *arena; + Arena *frames_arena; + Arena *statics_arena; + + u64 seed; + // P_Ent *first_free_ent; + + P_Frame *first_frame; + P_Frame *last_frame; + i64 frame_bins_count; + P_FrameBin *frame_bins; + // P_Frame *first_free_frame; u8 *tiles; }; @@ -155,7 +189,9 @@ Struct(P_DeltaNode) Struct(P_Snapshot) { - u64 seed; + u64 world_seed; + // i64 src_world_tick; + i64 src_tick; i64 tick; i64 time_ns; @@ -170,6 +206,13 @@ Struct(P_SnapshotNode) P_Snapshot snapshot; }; +Struct(P_SnapshotList) +{ + i64 count; + P_SnapshotNode *first; + P_SnapshotNode *last; +}; + //////////////////////////////////////////////////////////// //~ Collision types @@ -306,6 +349,7 @@ Enum(P_CmdKind) Struct(P_Cmd) { + i64 tick; P_CmdKind kind; // Delta @@ -325,20 +369,25 @@ Struct(P_CmdNode) P_Cmd cmd; }; +Struct(P_CmdList) +{ + i64 count; + P_CmdNode *first; + P_CmdNode *last; +}; + Struct(P_InputState) { Arena *arena; - P_CmdNode *first_cmd_node; - P_CmdNode *last_cmd_node; - u64 cmds_count; + + P_CmdList cmds; }; Struct(P_OutputState) { Arena *arena; - P_SnapshotNode *first_snapshot_node; - P_SnapshotNode *last_snapshot_node; - u64 snapshots_count; + + P_SnapshotList snapshots; P_DebugDrawNode *first_debug_draw_node; P_DebugDrawNode *last_debug_draw_node; @@ -363,6 +412,7 @@ Struct(P_Ctx) Struct(P_ThreadLocalCtx) { + // TODO: Move this to world frame Arena *debug_arena; b32 debug_draw_enabled; P_DebugDrawNode *first_debug_draw_node; @@ -373,6 +423,9 @@ Struct(P_ThreadLocalCtx) extern P_Ctx P; extern ThreadLocal P_ThreadLocalCtx P_tl; +extern Readonly P_Ent P_NilEnt; +extern Readonly P_Frame P_NilFrame; + //////////////////////////////////////////////////////////// //~ Bootstrap @@ -383,11 +436,12 @@ void P_Bootstrap(void); b32 P_IsKeyNil(P_Key key); b32 P_IsEntNil(P_Ent *ent); -b32 P_MatchKey(P_Key a, P_Key b); +b32 P_IsFrameNil(P_Frame *frame); //////////////////////////////////////////////////////////// //~ Key helpers +b32 P_MatchKey(P_Key a, P_Key b); P_Key P_RandKey(void); #define P_FmtKey(key) FmtHandle((key).v) @@ -397,11 +451,6 @@ P_Key P_RandKey(void); String P_NameFromTileKind(P_TileKind kind); -//////////////////////////////////////////////////////////// -//~ Delta helpers - -void P_UpdateWorldFromDelta(Arena *arena, P_World *world, P_Delta *delta); - //////////////////////////////////////////////////////////// //~ Shape helpers @@ -431,20 +480,18 @@ Vec2 P_EdgePointFromShape(P_Shape shape, Vec2 dir); //////////////////////////////////////////////////////////// //~ Lookup helpers -P_Ent *P_EntFromKeyEx(P_World *world, P_Key key, i64 tick); -P_Ent *P_EntFromKey(P_World *world, P_Key key); +P_Ent *P_EntFromKey(P_Frame *frame, P_Key key); //////////////////////////////////////////////////////////// //~ Iteration helpers -P_Ent *P_FirstEnt(P_World *world); +P_Ent *P_FirstEnt(P_Frame *frame); P_Ent *P_NextEnt(P_Ent *e); //////////////////////////////////////////////////////////// //~ List helpers P_Ent *P_PushTempEnt(Arena *arena, P_EntList *list); -void P_SpawnEntsFromList(Arena *arena, P_World *world, P_EntList ents); //////////////////////////////////////////////////////////// //~ Debug draw @@ -453,3 +500,19 @@ void P_DebugDrawPoint(Vec2 p, Vec4 srgb); void P_DebugDrawLine(Vec2 p0, Vec2 p1, Vec4 srgb); void P_DebugDrawRect(Rng2 rect, Vec4 srgb); void P_DebugDrawShape(P_Shape shape, Vec4 srgb); + +//////////////////////////////////////////////////////////// +//~ World + +P_World *P_AcquireWorld(void); +void P_UpdateWorldFromSnapshots(P_World *world, P_SnapshotList snapshots); +void P_SpawnEntsFromList(P_Frame *frame, P_EntList ents); + +P_Frame *P_FrameFromTick(P_World *world, i64 tick); +void P_ClearFrames(P_World *world, i64 tick_min, i64 tick_max); +P_Frame *P_PushFrame(P_World *world, P_Frame *src_frame, i64 tick); + +//////////////////////////////////////////////////////////// +//~ Step + +P_Frame *P_StepWorld(P_World *world, P_Frame *prev_frame, P_CmdList cmds); diff --git a/src/pp/pp_sim/pp_sim_core.c b/src/pp/pp_sim/pp_sim_core.c index 57ae4665..7bb6cbda 100644 --- a/src/pp/pp_sim/pp_sim_core.c +++ b/src/pp/pp_sim/pp_sim_core.c @@ -24,13 +24,11 @@ void S_TickForever(WaveLaneCtx *lane) Arena *frame_arena = AcquireArena(Gibi(64)); P_tl.debug_arena = AcquireArena(Gibi(64)); - Arena *world_arena = AcquireArena(Gibi(64)); - P_World *world = 0; + P_World *world = P_AcquireWorld(); // TODO: Real per-client deltas b32 has_sent_initial_tick = 0; - ////////////////////////////// //- Sim loop @@ -39,65 +37,69 @@ void S_TickForever(WaveLaneCtx *lane) { shutdown = Atomic32Fetch(&S.shutdown); P_tl.debug_draw_enabled = TweakBool("Simulation debug draw", 1); - ResetArena(frame_arena); ////////////////////////////// //- Swap - { - b32 swapin = IsSwappedIn(); - b32 swapout = shutdown && IsSwappingOut(); + // { + // b32 swapin = IsSwappedIn(); + // b32 swapout = shutdown && IsSwappingOut(); - //- Swap in - if (!world) - { - String packed = Zi; - if (swapin) - { - packed = SwappedStateFromName(frame_arena, Lit("pp_sim.swp")); - } - P_UnpackedWorld unpacked = P_UnpackWorld(frame_arena, packed); + // //- Swap in + // if (!world) + // { + // String packed = Zi; + // if (swapin) + // { + // packed = SwappedStateFromName(frame_arena, Lit("pp_sim.swp")); + // } + // P_UnpackedWorld unpacked = P_UnpackWorld(frame_arena, packed); - ResetArena(world_arena); - world = PushStruct(world_arena, P_World); - world->seed = unpacked.seed; - world->tick = unpacked.tick; - world->time_ns = unpacked.time_ns; - if (world->seed == 0) - { - TrueRand(StringFromStruct(&world->seed)); - } + // ResetArena(world_arena); + // world = PushStruct(world_arena, P_World); + // world->seed = unpacked.seed; + // world_frame->tick = unpacked.tick; + // world_frame->time_ns = unpacked.time_ns; + // if (world->seed == 0) + // { + // TrueRand(StringFromStruct(&world->seed)); + // } - world->ent_bins_count = Kibi(16); - world->ent_bins = PushStructs(world_arena, P_EntBin, world->ent_bins_count); + // world_frame->ent_bins_count = Kibi(16); + // world_frame->ent_bins = PushStructs(world_arena, P_EntBin, world_frame->ent_bins_count); - // Copy tiles - world->tiles = PushStructsNoZero(world_arena, u8, P_TilesCount); - CopyStructs(world->tiles, unpacked.tiles, P_TilesCount); + // // Copy tiles + // world->tiles = PushStructsNoZero(world_arena, u8, P_TilesCount); + // CopyStructs(world->tiles, unpacked.tiles, P_TilesCount); - // Copy ents - P_SpawnEntsFromList(world_arena, world, unpacked.ents); - } + // // Copy ents + // P_SpawnEntsFromList(world_arena, world, unpacked.ents); + // } - //- Swap out - if (swapout) - { - String packed = P_PackWorld(frame_arena, world); - WriteSwappedState(Lit("pp_sim.swp"), packed); - } - } + // //- Swap out + // if (swapout) + // { + // String packed = P_PackWorld(frame_arena, world); + // WriteSwappedState(Lit("pp_sim.swp"), packed); + // } + // } ////////////////////////////// //- Begin sim frame + P_Frame *prev_world_frame = world->last_frame; + P_Frame *world_frame = P_PushFrame(world, prev_world_frame, prev_world_frame->tick + 1); + + // FIXME: Copy frame + + i64 frame_begin_ns = TimeNs(); i64 sim_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND; f64 sim_dt = SecondsFromNs(sim_dt_ns); - world->tick += 1; ////////////////////////////// - //- Pop sim commands + //- Pop commands P_InputState *input = 0; LockTicketMutex(&P.sim_input_back_tm); @@ -114,9 +116,9 @@ void S_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Update double-buffered entity data - for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent)) + for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) { - ent->last_xf = ent->xf; + ent->prev_xf = ent->xf; } ////////////////////////////// @@ -125,7 +127,7 @@ void S_TickForever(WaveLaneCtx *lane) // FIXME: Only accept save command from local user b32 should_save = 0; - for (P_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next) + for (P_CmdNode *cmd_node = input->cmds.first; cmd_node; cmd_node = cmd_node->next) { P_Cmd *cmd = &cmd_node->cmd; if (cmd->kind == P_CmdKind_Save) @@ -145,9 +147,11 @@ void S_TickForever(WaveLaneCtx *lane) // FIXME: Only accept world deltas from users that can edit + // FIXME: Only apply relevant cmds based on tick + i64 applied_user_deltas_count = 0; - P_Delta **applied_user_deltas = PushStructsNoZero(frame_arena, P_Delta *, input->cmds_count); - for (P_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next) + P_Delta **applied_user_deltas = PushStructsNoZero(frame_arena, P_Delta *, input->cmds.count); + for (P_CmdNode *cmd_node = input->cmds.first; cmd_node; cmd_node = cmd_node->next) { P_Cmd *cmd = &cmd_node->cmd; if (cmd->kind == P_CmdKind_Delta) @@ -176,7 +180,20 @@ void S_TickForever(WaveLaneCtx *lane) } if (allow) { - P_UpdateWorldFromDelta(world_arena, world, delta); + P_DeltaNode tmp_delta_node = Zi; + tmp_delta_node.delta = *delta; + + P_SnapshotNode tmp_snapshot_node = Zi; + tmp_snapshot_node.snapshot.deltas_count = 1; + tmp_snapshot_node.snapshot.first_delta_node = &tmp_delta_node; + tmp_snapshot_node.snapshot.last_delta_node = &tmp_delta_node; + + P_SnapshotList tmp_snapshot_list = Zi; + tmp_snapshot_list.count = 1; + tmp_snapshot_list.first = &tmp_snapshot_node; + tmp_snapshot_list.last = &tmp_snapshot_node; + + P_UpdateWorldFromSnapshots(world, tmp_snapshot_list); } } } @@ -184,18 +201,20 @@ void S_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Update ent controls - for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent)) + // FIXME: Only apply relevant cmds based on tick + + for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) { ent->fire_presses = 0; } - for (P_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next) + for (P_CmdNode *cmd_node = input->cmds.first; cmd_node; cmd_node = cmd_node->next) { P_Cmd cmd = cmd_node->cmd; if (cmd.kind == P_CmdKind_Control) { - P_Ent *target = P_EntFromKey(world, cmd.target); - if (target->valid) + P_Ent *target = P_EntFromKey(world_frame, cmd.target); + if (!P_IsEntNil(target)) { target->move = ClampVec2Len(cmd.move, 1); target->look = cmd.look; @@ -212,7 +231,7 @@ void S_TickForever(WaveLaneCtx *lane) // ////////////////////////////// // //- Push bullets - // for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent)) + // for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) // { // if (ent->fire_held) // { @@ -227,7 +246,7 @@ void S_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Integrate control forces - for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent)) + for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) { // Xform xf = ent->xf; // Xform desired_xf = xf; @@ -300,10 +319,10 @@ void S_TickForever(WaveLaneCtx *lane) constraints = PushStructs(frame_arena, P_Constraint, max_constraints); } - for (P_Ent *ent0 = P_FirstEnt(world); ent0->valid; ent0 = P_NextEnt(ent0)) + for (P_Ent *ent0 = P_FirstEnt(world_frame); !P_IsEntNil(ent0); ent0 = P_NextEnt(ent0)) { P_Shape shape0 = P_WorldShapeFromEnt(ent0); - for (P_Ent *ent1 = P_FirstEnt(world); ent1->valid; ent1 = P_NextEnt(ent1)) + for (P_Ent *ent1 = P_FirstEnt(world_frame); !P_IsEntNil(ent1); ent1 = P_NextEnt(ent1)) { if (ent1 > ent0) { @@ -338,7 +357,7 @@ void S_TickForever(WaveLaneCtx *lane) } if (constraint) { - constraint->last_touched_tick = world->tick; + constraint->last_touched_tick = world_frame->tick; constraint->normal = collision.collision_normal; // constraint->friction = SqrtF32(ent0->friction * ent1->friction); constraint->friction = 0; @@ -416,13 +435,13 @@ void S_TickForever(WaveLaneCtx *lane) // // Debug draw // { - // // P_Ent *ent0 = P_EntFromKey(world, constraint->ent0); - // // P_Ent *ent1 = P_EntFromKey(world, constraint->ent1); + // // P_Ent *ent0 = P_EntFromKey(world_frame, constraint->ent0); + // // P_Ent *ent1 = P_EntFromKey(world_frame, constraint->ent1); // Vec2 normal = constraint->normal; // Vec2 center0 = Zi; // Vec2 center1 = Zi; - // if (ent0->valid) center0 = P_WorldShapeFromEnt(ent0).center_of_mass; - // if (ent1->valid) center1 = P_WorldShapeFromEnt(ent1).center_of_mass; + // if (!P_IsEntNil(ent0)) center0 = P_WorldShapeFromEnt(ent0).center_of_mass; + // if (!P_IsEntNil(ent1)) center1 = P_WorldShapeFromEnt(ent1).center_of_mass; // Vec2 p0 = AddVec2(center0, vcp0); // Vec2 p1 = AddVec2(center1, vcp1); // P_DebugDrawPoint(p0, Color_Cyan); @@ -457,15 +476,15 @@ void S_TickForever(WaveLaneCtx *lane) // constraints = PushStructs(frame_arena, P_Constraint, max_constraints); // } - // for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent)) + // for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) // { // if (ent->is_player) // { - // Xform last_xf = ent->last_xf; + // Xform prev_xf = ent->prev_xf; // Xform xf = ent->xf; // P_Shape local_shape = P_LocalShapeFromEnt(ent); - // P_Shape last_world_shape = P_MulXformShape(last_xf, local_shape); + // P_Shape last_world_shape = P_MulXformShape(prev_xf, local_shape); // P_Shape shape0 = P_WorldShapeFromEnt(ent); // // TODO: Real constraint data @@ -514,7 +533,7 @@ void S_TickForever(WaveLaneCtx *lane) // } // if (constraint) // { - // constraint->last_touched_tick = world->tick; + // constraint->last_touched_tick = world_frame->tick; // constraint->normal = collision.collision_normal; // // TODO: Real masses @@ -589,13 +608,13 @@ void S_TickForever(WaveLaneCtx *lane) // // Debug draw // { - // P_Ent *ent0 = P_EntFromKey(world, constraint->ent0); - // P_Ent *ent1 = P_EntFromKey(world, constraint->ent1); + // P_Ent *ent0 = P_EntFromKey(world_frame, constraint->ent0); + // P_Ent *ent1 = P_EntFromKey(world_frame, constraint->ent1); // Vec2 normal = constraint->normal; // Vec2 center0 = Zi; // Vec2 center1 = Zi; - // if (ent0->valid) center0 = P_WorldShapeFromEnt(ent0).center_of_mass; - // if (ent1->valid) center1 = P_WorldShapeFromEnt(ent1).center_of_mass; + // if (!P_IsEntNil(ent0)) center0 = P_WorldShapeFromEnt(ent0).center_of_mass; + // if (!P_IsEntNil(ent1)) center1 = P_WorldShapeFromEnt(ent1).center_of_mass; // Vec2 p0 = AddVec2(center0, vcp0); // Vec2 p1 = AddVec2(center1, vcp1); // P_DebugDrawPoint(p0, Color_Cyan); @@ -616,9 +635,11 @@ void S_TickForever(WaveLaneCtx *lane) { P_Constraint *constraint = &constraints[constraint_idx]; b32 prune = 1; - if (constraint->last_touched_tick == world->tick) + if (constraint->last_touched_tick == world_frame->tick) { - if (P_EntFromKey(world, constraint->ent0)->valid || P_EntFromKey(world, constraint->ent1)->valid) + P_Ent *ent0 = P_EntFromKey(world_frame, constraint->ent0); + P_Ent *ent1 = P_EntFromKey(world_frame, constraint->ent1); + if (!P_IsEntNil(ent0) && !P_IsEntNil(ent1)) { prune = 0; } @@ -691,8 +712,8 @@ void S_TickForever(WaveLaneCtx *lane) { P_Constraint *constraint = &constraints[constraint_idx]; - P_Ent *ent0 = P_EntFromKey(world, constraint->ent0); - P_Ent *ent1 = P_EntFromKey(world, constraint->ent1); + P_Ent *ent0 = P_EntFromKey(world_frame, constraint->ent0); + P_Ent *ent1 = P_EntFromKey(world_frame, constraint->ent1); Vec2 v0 = ent0->solved_v; Vec2 v1 = ent1->solved_v; @@ -716,12 +737,12 @@ void S_TickForever(WaveLaneCtx *lane) w1 += WedgeVec2(vcp1, impulse) * constraint->inv_i1; } - if (ent0->valid) + if (!P_IsEntNil(ent0)) { ent0->solved_v = v0; ent0->solved_w = w0; } - if (ent1->valid) + if (!P_IsEntNil(ent1)) { ent1->solved_v = v1; ent1->solved_w = w1; @@ -735,8 +756,8 @@ void S_TickForever(WaveLaneCtx *lane) { P_Constraint *constraint = &constraints[constraint_idx]; - P_Ent *ent0 = P_EntFromKey(world, constraint->ent0); - P_Ent *ent1 = P_EntFromKey(world, constraint->ent1); + P_Ent *ent0 = P_EntFromKey(world_frame, constraint->ent0); + P_Ent *ent1 = P_EntFromKey(world_frame, constraint->ent1); f32 inv_m0 = constraint->inv_m0; f32 inv_m1 = constraint->inv_m1; @@ -749,11 +770,11 @@ void S_TickForever(WaveLaneCtx *lane) Vec2 center0 = constraint->static_center0; Vec2 center1 = constraint->static_center1; - if (ent0->valid) + if (!P_IsEntNil(ent0)) { center0 = P_WorldShapeFromEnt(ent0).center_of_mass; } - if (ent1->valid) + if (!P_IsEntNil(ent1)) { center1 = P_WorldShapeFromEnt(ent1).center_of_mass; } @@ -844,12 +865,12 @@ void S_TickForever(WaveLaneCtx *lane) w1 += WedgeVec2(vcp1, impulse) * inv_i1; } - if (ent0->valid) + if (!P_IsEntNil(ent0)) { ent0->solved_v = v0; ent0->solved_w = w0; } - if (ent1->valid) + if (!P_IsEntNil(ent1)) { ent1->solved_v = v1; ent1->solved_w = w1; @@ -859,7 +880,7 @@ void S_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Integrate velocities - for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent)) + for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) { Xform xf = ent->xf; xf.og = AddVec2(xf.og, MulVec2(ent->solved_v, solver_dt)); @@ -884,7 +905,7 @@ void S_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Move bullets - for (P_Ent *bullet = P_FirstEnt(world); bullet->valid; bullet = P_NextEnt(bullet)) + for (P_Ent *bullet = P_FirstEnt(world_frame); !P_IsEntNil(bullet); bullet = P_NextEnt(bullet)) { if (bullet->is_bullet) { @@ -903,12 +924,12 @@ void S_TickForever(WaveLaneCtx *lane) { P_EntList bullets_to_spawn = Zi; - for (P_Ent *firer = P_FirstEnt(world); firer->valid; firer = P_NextEnt(firer)) + for (P_Ent *firer = P_FirstEnt(world_frame); !P_IsEntNil(firer); firer = P_NextEnt(firer)) { if (firer->fire_held) // if (firer->fire_presses) { - // i64 fire_delta_ns = world->time_ns - firer->last_fire_ns; + // i64 fire_delta_ns = world_frame->time_ns - firer->last_fire_ns; // i64 single_bullet_delta_ns = NsFromSeconds(1) / firer->fire_rate; @@ -920,7 +941,7 @@ void S_TickForever(WaveLaneCtx *lane) f32 spread = Tau * 0.01; f32 tweak_speed = TweakFloat("Bullet speed", 100, 1, 100); - b32 can_fire = (firer->last_fire_ns + NsFromSeconds(1.0 / fire_rate)) <= world->time_ns; + b32 can_fire = (firer->last_fire_ns + NsFromSeconds(1.0 / fire_rate)) <= world_frame->time_ns; if (can_fire) { i64 tick_bullets_count = bullets_per_fire; @@ -955,11 +976,11 @@ void S_TickForever(WaveLaneCtx *lane) bullet->bullet_firer = firer->key; } } - firer->last_fire_ns = world->time_ns; + firer->last_fire_ns = world_frame->time_ns; } } } - P_SpawnEntsFromList(world_arena, world, bullets_to_spawn); + P_SpawnEntsFromList(world_frame, bullets_to_spawn); } @@ -970,7 +991,7 @@ void S_TickForever(WaveLaneCtx *lane) // TODO: Separate 'hits' from bullets, so that bullets can have multiple hits - for (P_Ent *bullet = P_FirstEnt(world); bullet->valid; bullet = P_NextEnt(bullet)) + for (P_Ent *bullet = P_FirstEnt(world_frame); !P_IsEntNil(bullet); bullet = P_NextEnt(bullet)) { if (bullet->is_bullet) { @@ -984,7 +1005,7 @@ void S_TickForever(WaveLaneCtx *lane) P_RaycastResult victim_raycast = Zi; { f32 closest_len_sq = Inf; - for (P_Ent *victim = P_FirstEnt(world); victim->valid; victim = P_NextEnt(victim)) + for (P_Ent *victim = P_FirstEnt(world_frame); !P_IsEntNil(victim); victim = P_NextEnt(victim)) { if (victim->is_player && !P_MatchKey(victim->key, bullet->bullet_firer)) { @@ -1013,7 +1034,7 @@ void S_TickForever(WaveLaneCtx *lane) } } - if (closest_victim->valid) + if (!P_IsEntNil(closest_victim)) { bullet->has_hit = 1; bullet->hit_entry = victim_raycast.p; @@ -1064,12 +1085,12 @@ void S_TickForever(WaveLaneCtx *lane) // P_Bullet *bullet = &bullets[bullet_idx]; // // Raycast - // for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent)) + // for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) // { // Xform xf = ent->xf; // P_Shape world_shape = P_MulXformShape(xf, ent->local_shape); - // if (ent == P_FirstEnt(world)) + // if (ent == P_FirstEnt(world_frame)) // { // bullet->start = AddVec2(world_shape.centroid, Vec2WithLen(ent->look, world_shape.radius)); // bullet->dir = NormVec2(ent->look); @@ -1123,12 +1144,12 @@ void S_TickForever(WaveLaneCtx *lane) // // P_Bullet *bullet = &bullets[bullet_idx]; // // // Raycast - // // for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent)) + // // for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) // // { // // Xform xf = ent->xf; // // P_Shape world_shape = P_MulXformShape(xf, ent->local_shape); - // // if (ent == P_FirstEnt(world)) + // // if (ent == P_FirstEnt(world_frame)) // // { // // bullet->start = AddVec2(world_shape.centroid, Vec2WithLen(ent->look, world_shape.radius)); // // bullet->dir = NormVec2(ent->look); @@ -1164,7 +1185,7 @@ void S_TickForever(WaveLaneCtx *lane) if (P_tl.debug_draw_enabled) { - for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent)) + for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) { P_Shape world_shape = P_WorldShapeFromEnt(ent); @@ -1209,12 +1230,12 @@ void S_TickForever(WaveLaneCtx *lane) P_OutputState *output = &P.sim_output_states[P.sim_output_back_idx]; P_SnapshotNode *snapshot_node = PushStruct(output->arena, P_SnapshotNode); P_Snapshot *snapshot = &snapshot_node->snapshot; - SllQueuePush(output->first_snapshot_node, output->last_snapshot_node, snapshot_node); - ++output->snapshots_count; + SllQueuePush(output->snapshots.first, output->snapshots.last, snapshot_node); + ++output->snapshots.count; - snapshot->seed = world->seed; - snapshot->tick = world->tick; - snapshot->time_ns = world->time_ns; + snapshot->world_seed = world->seed; + snapshot->tick = world_frame->tick; + snapshot->time_ns = world_frame->time_ns; // Forward user edit deltas for (i64 applied_user_delta_idx = 0; applied_user_delta_idx < applied_user_deltas_count; ++applied_user_delta_idx) @@ -1248,7 +1269,7 @@ void S_TickForever(WaveLaneCtx *lane) } // Push raw entity deltas - for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent)) + for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) { P_Delta *delta = 0; { @@ -1287,8 +1308,8 @@ void S_TickForever(WaveLaneCtx *lane) { i64 ents_to_prune_count = 0; - P_Ent **ents_to_prune = PushStructsNoZero(frame_arena, P_Ent *, world->ents_count); - for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent)) + P_Ent **ents_to_prune = PushStructsNoZero(frame_arena, P_Ent *, world_frame->ents_count); + for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) { if (ent->exists <= 0) { @@ -1299,13 +1320,13 @@ void S_TickForever(WaveLaneCtx *lane) for (i64 prune_idx = 0; prune_idx < ents_to_prune_count; ++prune_idx) { - // FIXME: Add to free list + // FIXME: Add to freelist // FIXME: Ensure sure prunes are received by user P_Ent *ent = ents_to_prune[prune_idx]; - P_EntBin *bin = &world->ent_bins[ent->key.v % world->ent_bins_count]; + P_EntBin *bin = &world_frame->ent_bins[ent->key.v % world_frame->ent_bins_count]; DllQueueRemoveNP(bin->first, bin->last, ent, next_in_bin, prev_in_bin); - DllQueueRemove(world->first_ent, world->last_ent, ent); - world->ents_count -= 1; + DllQueueRemove(world_frame->first_ent, world_frame->last_ent, ent); + world_frame->ents_count -= 1; } } @@ -1321,7 +1342,7 @@ void S_TickForever(WaveLaneCtx *lane) } i64 frame_end_ns = TimeNs(); - world->time_ns += sim_dt_ns; + world_frame->time_ns += sim_dt_ns; ////////////////////////////// //- Sleep diff --git a/src/pp/pp_transcode.c b/src/pp/pp_transcode.c index ebb757d7..f1b0b6f4 100644 --- a/src/pp/pp_transcode.c +++ b/src/pp/pp_transcode.c @@ -6,19 +6,20 @@ String P_PackWorld(Arena *arena, P_World *src_world) String result = Zi; result.text = ArenaNext(arena, u8); TempArena scratch = BeginScratch(arena); + P_Frame *src_frame = src_world->last_frame; result.len += StringF(arena, "version: %F\n", FmtUint(P_Tv_Latest)).len; result.len += StringF(arena, "\n").len; result.len += StringF(arena, "seed: 0x%F\n", FmtHex(src_world->seed)).len; - result.len += StringF(arena, "tick: %F\n", FmtSint(src_world->tick)).len; - result.len += StringF(arena, "time: %F\n", FmtSint(src_world->time_ns)).len; + result.len += StringF(arena, "tick: %F\n", FmtSint(src_frame->tick)).len; + result.len += StringF(arena, "time: %F\n", FmtSint(src_frame->time_ns)).len; // Pack entities // FIXME: Precision result.len += PushString(arena, Lit("\nentities:\n")).len; result.len += PushString(arena, Lit("{\n")).len; - for (P_Ent *ent = P_FirstEnt(src_world); ent->valid; ent = P_NextEnt(ent)) + for (P_Ent *ent = P_FirstEnt(src_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) { // TODO: Pack bullets if (!ent->is_bullet) diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index ea398104..313ac0fe 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -43,11 +43,12 @@ V_Cmd *V_PushVisCmd(String name) P_Cmd *V_PushSimCmd(P_CmdKind kind) { - V_Frame *frame = V_CurrentFrame(); - P_CmdNode *n = PushStruct(frame->arena, P_CmdNode); + // FIXME: Free list + Arena *perm = PermArena(); + P_CmdNode *n = PushStruct(perm, P_CmdNode); n->cmd.kind = kind; - SllQueuePush(frame->first_sim_cmd_node, frame->last_sim_cmd_node, n); - ++frame->sim_cmds_count; + SllQueuePush(V.sim_cmds.first, V.sim_cmds.last, n); + ++V.sim_cmds.count; return &n->cmd; } @@ -340,11 +341,9 @@ void V_TickForever(WaveLaneCtx *lane) P_DebugDrawNode *first_sim_debug_draw_node = 0; P_DebugDrawNode *last_sim_debug_draw_node = 0; - Arena *world_arena = AcquireArena(Gibi(64)); - P_World *world = PushStruct(world_arena, P_World); - world->ent_bins_count = Kibi(16); - world->ent_bins = PushStructs(world_arena, P_EntBin, world->ent_bins_count); - world->tiles = PushStructs(world_arena, u8, P_TilesCount); + P_World *sim_world = P_AcquireWorld(); + P_World *predict_world = P_AcquireWorld(); + P_World *blend_world = P_AcquireWorld(); Vec2I32 tiles_dims = VEC2I32(P_TilesPitch, P_TilesPitch); Vec2I32 cells_dims = VEC2I32(V_CellsPerMeter * P_WorldPitch, V_CellsPerMeter * P_WorldPitch); @@ -471,7 +470,7 @@ void V_TickForever(WaveLaneCtx *lane) } else { - u64 hotkey_hash = HashFnv64(Fnv64Basis, StringFromStruct(&hotkey)); + u64 hotkey_hash = HashString(StringFromStruct(&hotkey)); V_ShortcutBin *bin = &shortcut_bins[hotkey_hash % shortcut_bins_count]; V_Shortcut *shortcut = PushStruct(perm, V_Shortcut); shortcut->hotkey_hash = hotkey_hash; @@ -632,54 +631,77 @@ void V_TickForever(WaveLaneCtx *lane) frame->ui_dims.y = MaxF32(frame->ui_dims.y, 64); frame->draw_dims = frame->ui_dims; - ////////////////////////////// - //- Pop sim output + // ////////////////////////////// + // //- Pop sim output + + // P_OutputState *sim_output = 0; + // LockTicketMutex(&P.sim_output_back_tm); + // { + // sim_output = &P.sim_output_states[P.sim_output_back_idx]; + // ++P.sim_output_back_idx; + // if (P.sim_output_back_idx >= countof(P.sim_output_states)) + // { + // P.sim_output_back_idx = 0; + // } + // } + // UnlockTicketMutex(&P.sim_output_back_tm); + + // ////////////////////////////// + // //- Apply sim snapshots + + // // FIXME: Only apply latest snapshot + + + + // // FIXME: Real ping + // i64 ping_ns = NsFromSeconds(0.250); + + // // TODO: Remove this (testing) + + + + // // b32 received_unseen_tick = 0; + // // b32 tiles_dirty = 0; + // // b32 should_clear_particles = 0; + // // for (P_SnapshotNode *n = sim_output->first_snapshot_node; n; n = n->next) + // // { + // // P_Snapshot *snapshot = &n->snapshot; + // // if (snapshot->tick > world->tick) + // // { + // // world->seed = snapshot->seed; + // // world->tick = snapshot->tick; + // // world->time_ns = snapshot->time_ns; + // // for (P_DeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next) + // // { + // // P_Delta *delta = &dn->delta; + // // if (delta->kind == P_DeltaKind_Reset) + // // { + // // tiles_dirty = 1; + // // should_clear_particles = 1; + // // } + // // if (delta->kind == P_DeltaKind_RawTiles || delta->kind == P_DeltaKind_Tile) + // // { + // // tiles_dirty = 1; + // // } + // // P_UpdateWorldFromDelta(world, delta); + // // } + // // received_unseen_tick = 1; + // // } + // // } + + + // { + // P_SnapshotList sim_snapshots = sim_output->snapshots; + // P_UpdateWorldFromSnapshots(sim_world, sim_snapshots); + // } + + + + - P_OutputState *sim_output = 0; - LockTicketMutex(&P.sim_output_back_tm); - { - sim_output = &P.sim_output_states[P.sim_output_back_idx]; - ++P.sim_output_back_idx; - if (P.sim_output_back_idx >= countof(P.sim_output_states)) - { - P.sim_output_back_idx = 0; - } - } - UnlockTicketMutex(&P.sim_output_back_tm); - ////////////////////////////// - //- Apply sim snapshots - // FIXME: Only apply latest snapshot - b32 received_unseen_tick = 0; - b32 tiles_dirty = 0; - b32 should_clear_particles = 0; - for (P_SnapshotNode *n = sim_output->first_snapshot_node; n; n = n->next) - { - P_Snapshot *snapshot = &n->snapshot; - if (snapshot->tick > world->tick) - { - world->seed = snapshot->seed; - world->tick = snapshot->tick; - world->time_ns = snapshot->time_ns; - for (P_DeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next) - { - P_Delta *delta = &dn->delta; - if (delta->kind == P_DeltaKind_Reset) - { - tiles_dirty = 1; - should_clear_particles = 1; - } - if (delta->kind == P_DeltaKind_RawTiles || delta->kind == P_DeltaKind_Tile) - { - tiles_dirty = 1; - } - P_UpdateWorldFromDelta(world_arena, world, delta); - } - received_unseen_tick = 1; - } - } // ////////////////////////////// // //- Update tiles from sim @@ -782,7 +804,7 @@ void V_TickForever(WaveLaneCtx *lane) hotkey.shift = frame->held_buttons[Button_Shift]; hotkey.alt = frame->held_buttons[Button_Alt]; { - u64 hotkey_hash = HashFnv64(Fnv64Basis, StringFromStruct(&hotkey)); + u64 hotkey_hash = HashString(StringFromStruct(&hotkey)); V_ShortcutBin *bin = &shortcut_bins[hotkey_hash % shortcut_bins_count]; V_Shortcut *shortcut = bin->first; for (; shortcut; shortcut = shortcut->next_in_bin) @@ -848,7 +870,7 @@ void V_TickForever(WaveLaneCtx *lane) Vec2 look_ratio = Zi; look_ratio.y = 0.25; look_ratio.x = look_ratio.y / (16.0 / 9.0); - P_Ent *player = P_EntFromKey(world, V.player_key); + P_Ent *player = P_EntFromKey(blend_world->last_frame, V.player_key); target_camera_pos = P_WorldShapeFromEnt(player).centroid; target_camera_pos = AddVec2(target_camera_pos, MulVec2Vec2(player->look, look_ratio)); target_camera_zoom = 1; @@ -1001,12 +1023,12 @@ void V_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Query entities - P_Ent *player = P_EntFromKey(world, V.player_key); + P_Ent *player = P_EntFromKey(blend_world->last_frame, V.player_key); P_Ent *hovered_ent = &P_NilEnt; { // TODO: Real world query P_Shape cursor_shape = P_ShapeFromDesc(.count = 1, .points = { frame->world_cursor }); - for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent)) + for (P_Ent *ent = P_FirstEnt(blend_world->last_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) { P_Shape ent_shape = P_WorldShapeFromEnt(ent); b32 is_hovered = P_CollisionResultFromShapes(ent_shape, cursor_shape).collision_points_count > 0; @@ -2212,8 +2234,8 @@ void V_TickForever(WaveLaneCtx *lane) { UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y); { - UI_BuildLabelF("World seed: 0x%F", FmtHex(world->seed)); - UI_BuildLabelF("Entities count: %F", FmtSint(world->ents_count)); + UI_BuildLabelF("World seed: 0x%F", FmtHex(blend_world->seed)); + UI_BuildLabelF("Entities count: %F", FmtSint(blend_world->last_frame->ents_count)); } UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y); { @@ -2535,7 +2557,7 @@ void V_TickForever(WaveLaneCtx *lane) case V_CmdKind_delete: { - if (hovered_ent->valid) + if (!P_IsEntNil(hovered_ent)) { P_Cmd *cmd = V_PushSimCmd(P_CmdKind_Delta); cmd->delta.kind = P_DeltaKind_RawEnt; @@ -2553,10 +2575,10 @@ void V_TickForever(WaveLaneCtx *lane) } } break; - case V_CmdKind_clear_particles: - { - should_clear_particles = 1; - } break; + // case V_CmdKind_clear_particles: + // { + // should_clear_particles = 1; + // } break; } } @@ -2605,23 +2627,189 @@ void V_TickForever(WaveLaneCtx *lane) cmd->fire_presses = frame->fire_presses; } + + + + + ////////////////////////////// + //- Pop sim output + + P_OutputState *sim_output = 0; + LockTicketMutex(&P.sim_output_back_tm); + { + sim_output = &P.sim_output_states[P.sim_output_back_idx]; + ++P.sim_output_back_idx; + if (P.sim_output_back_idx >= countof(P.sim_output_states)) + { + P.sim_output_back_idx = 0; + } + } + UnlockTicketMutex(&P.sim_output_back_tm); + + + + + ////////////////////////////// + //- Apply sim snapshots + + // FIXME: Only apply latest snapshot + + + + // FIXME: Real ping + i64 ping_ns = NsFromSeconds(0.250); + + // TODO: Remove this (testing) + + + + // b32 received_unseen_tick = 0; + // b32 tiles_dirty = 0; + // b32 should_clear_particles = 0; + // for (P_SnapshotNode *n = sim_output->first_snapshot_node; n; n = n->next) + // { + // P_Snapshot *snapshot = &n->snapshot; + // if (snapshot->tick > world->tick) + // { + // world->seed = snapshot->seed; + // world->tick = snapshot->tick; + // world->time_ns = snapshot->time_ns; + // for (P_DeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next) + // { + // P_Delta *delta = &dn->delta; + // if (delta->kind == P_DeltaKind_Reset) + // { + // tiles_dirty = 1; + // should_clear_particles = 1; + // } + // if (delta->kind == P_DeltaKind_RawTiles || delta->kind == P_DeltaKind_Tile) + // { + // tiles_dirty = 1; + // } + // P_UpdateWorldFromDelta(world, delta); + // } + // received_unseen_tick = 1; + // } + // } + + + // Apply snapshots to sim world + { + P_SnapshotList sim_snapshots = sim_output->snapshots; + P_UpdateWorldFromSnapshots(sim_world, sim_snapshots); + } + + + + + + + ////////////////////////////// //- Submit sim commands + i64 predict_to = sim_world->last_frame->tick + 10; + LockTicketMutex(&P.sim_input_back_tm); { P_InputState *v2s = &P.sim_input_states[P.sim_input_back_idx]; - for (P_CmdNode *src = frame->first_sim_cmd_node; src; src = src->next) + for (P_CmdNode *src = V.sim_cmds.first; src; src = src->next) { P_CmdNode *cmd_node = PushStruct(v2s->arena, P_CmdNode); cmd_node->cmd = src->cmd; - SllQueuePush(v2s->first_cmd_node, v2s->last_cmd_node, cmd_node); - ++v2s->cmds_count; + cmd_node->cmd.tick = predict_to; + SllQueuePush(v2s->cmds.first, v2s->cmds.last, cmd_node); + ++v2s->cmds.count; } } UnlockTicketMutex(&P.sim_input_back_tm); + ////////////////////////////// + //- Predict + + + // TODO: Only predict when new sim snapshot is received + + // Predict + P_Frame *predict_frame = 0; + { + // i64 step_count = predict_to - sim_world->last_frame->tick; + + // // TODO: Preserve constraints? + + // P_ClearFrames(predict_world, I64Min, I64Max); + // P_Frame *base_predict_frame = P_PushFrame(predict_world, sim_world->last_frame, sim_world->last_frame->tick); + // P_Frame *prev_predict_frame = base_predict_frame; + // for (i64 step_idx = 0; step_idx < step_count; ++step_idx) + // { + // // P_CmdList step_cmds = V_StepCmdsFromTick(prev_predict_frame->tick + 1); + + // P_CmdList step_cmds = Zi; + // for (P_CmdNode *src = V.sim_cmds.first; src; src = src->next) + // { + // P_CmdNode *n = PushStructNoZero(frame->arena, P_CmdNode); + // *n = *src; + // SllQueuePush(step_cmds.first, step_cmds.last, n); + // ++step_cmds.count; + // } + + + + // P_Frame *stepped = P_StepWorld(predict_world, prev_predict_frame, step_cmds); + // prev_predict_frame = stepped; + // } + + predict_frame = sim_world->last_frame; + } + + + + + + ////////////////////////////// + //- Update blended world + + + + // TODO: Remove this + P_Frame *blend_frame = 0; + { + // P_ResetWorldFromFrame(blended_world, predict_world->last_frame); + // P_Frame *blend_frame = blended_world->last_frame; + blend_frame = predict_frame; + } + + + // FIXME: Compare tile hashes + b32 tiles_dirty = 0; + b32 should_clear_particles = 0; + + + + + + + // { + // i64 delay_ns = NsFromSeconds(100); + + // P_Frame *right_frame = &P_NilFrame; + // P_Frame *left_frame = &P_NilFrame; + + // for (P_Frame *tmp = + + + + + // P_Frame *right_frame = predict_world->last_frame; + // P_Frame *left_frame = predict_world->left_frame; + // } + + + + + + @@ -2636,7 +2824,7 @@ void V_TickForever(WaveLaneCtx *lane) - for (P_Ent *bullet = P_FirstEnt(world); bullet->valid; bullet = P_NextEnt(bullet)) + for (P_Ent *bullet = P_FirstEnt(blend_frame); !P_IsEntNil(bullet); bullet = P_NextEnt(bullet)) { if (bullet->is_bullet) { @@ -2816,7 +3004,7 @@ void V_TickForever(WaveLaneCtx *lane) if (0) { - for (P_Ent *bullet = P_FirstEnt(world); bullet->valid; bullet = P_NextEnt(bullet)) + for (P_Ent *bullet = P_FirstEnt(blend_frame); !P_IsEntNil(bullet); bullet = P_NextEnt(bullet)) { if (bullet->is_bullet && bullet->has_hit) { @@ -2893,7 +3081,7 @@ void V_TickForever(WaveLaneCtx *lane) // { - // for (P_Ent *firer = P_FirstEnt(world); firer->valid; firer = P_NextEnt(firer)) + // for (P_Ent *firer = P_FirstEnt(blend_frame); firer->valid; firer = P_NextEnt(firer)) // { // if (firer->fire_held) // { @@ -2908,7 +3096,7 @@ void V_TickForever(WaveLaneCtx *lane) // P_RaycastResult victim_raycast = Zi; // { // f32 closest_len_sq = Inf; - // for (P_Ent *victim = P_FirstEnt(world); victim->valid; victim = P_NextEnt(victim)) + // for (P_Ent *victim = P_FirstEnt(blend_frame); victim->valid; victim = P_NextEnt(victim)) // { // if (victim != firer) // { @@ -2979,7 +3167,7 @@ void V_TickForever(WaveLaneCtx *lane) // // for (P_QueryResult query = P_FirstRaycast(wrold, ray_start, ray_dir); query. - // // P_RaycastWorldResult hits = P_RaycastWorld(world, ray_start, ray_dir) + // // P_RaycastWorldResult hits = P_RaycastWorld(blend_frame, ray_start, ray_dir) // // { // // } // } @@ -3018,91 +3206,91 @@ void V_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Debug draw - { - // Copy debug draw data from sim - if (received_unseen_tick) - { - ResetArena(sim_debug_arena); - first_sim_debug_draw_node = 0; - last_sim_debug_draw_node = 0; - { - i64 dst_idx = 0; - P_DebugDrawNode *dst_nodes = PushStructsNoZero(sim_debug_arena, P_DebugDrawNode, sim_output->debug_draw_nodes_count); - for (P_DebugDrawNode *src = sim_output->first_debug_draw_node; src; src = src->next) - { - P_DebugDrawNode *dst = &dst_nodes[dst_idx]; - *dst = *src; - dst_idx += 1; - SllQueuePush(first_sim_debug_draw_node, last_sim_debug_draw_node, dst); - } - } - } + // { + // // Copy debug draw data from sim + // if (received_unseen_tick) + // { + // ResetArena(sim_debug_arena); + // first_sim_debug_draw_node = 0; + // last_sim_debug_draw_node = 0; + // { + // i64 dst_idx = 0; + // P_DebugDrawNode *dst_nodes = PushStructsNoZero(sim_debug_arena, P_DebugDrawNode, sim_output->debug_draw_nodes_count); + // for (P_DebugDrawNode *src = sim_output->first_debug_draw_node; src; src = src->next) + // { + // P_DebugDrawNode *dst = &dst_nodes[dst_idx]; + // *dst = *src; + // dst_idx += 1; + // SllQueuePush(first_sim_debug_draw_node, last_sim_debug_draw_node, dst); + // } + // } + // } - // Merge vis debug draws with sim debug draws - P_DebugDrawNode *first_debug_draw_node = first_sim_debug_draw_node; - P_DebugDrawNode *last_debug_draw_node = last_sim_debug_draw_node; - if (P_tl.first_debug_draw_node) - { - if (last_debug_draw_node) - { - last_debug_draw_node->next = P_tl.first_debug_draw_node; - } - else - { - first_debug_draw_node = P_tl.first_debug_draw_node; - } - last_debug_draw_node = P_tl.last_debug_draw_node; - } + // // Merge vis debug draws with sim debug draws + // P_DebugDrawNode *first_debug_draw_node = first_sim_debug_draw_node; + // P_DebugDrawNode *last_debug_draw_node = last_sim_debug_draw_node; + // if (P_tl.first_debug_draw_node) + // { + // if (last_debug_draw_node) + // { + // last_debug_draw_node->next = P_tl.first_debug_draw_node; + // } + // else + // { + // first_debug_draw_node = P_tl.first_debug_draw_node; + // } + // last_debug_draw_node = P_tl.last_debug_draw_node; + // } - // Push draws - for (P_DebugDrawNode *n = first_debug_draw_node; n; n = n->next) - { - Vec4 color = Vec4FromU32(n->srgb32); - i32 detail = 24; - f32 radius = 5; - switch(n->kind) - { - case P_DebugDrawKind_Point: - { - Vec2 ui_p = MulXformV2(frame->xf.world_to_ui, n->point.p); - V_DrawPoint(ui_p, color); - } break; + // // Push draws + // for (P_DebugDrawNode *n = first_debug_draw_node; n; n = n->next) + // { + // Vec4 color = Vec4FromU32(n->srgb32); + // i32 detail = 24; + // f32 radius = 5; + // switch(n->kind) + // { + // case P_DebugDrawKind_Point: + // { + // Vec2 ui_p = MulXformV2(frame->xf.world_to_ui, n->point.p); + // V_DrawPoint(ui_p, color); + // } break; - case P_DebugDrawKind_Line: - { - Vec2 ui_p0 = MulXformV2(frame->xf.world_to_ui, n->line.p0); - Vec2 ui_p1 = MulXformV2(frame->xf.world_to_ui, n->line.p1); - V_DrawLine(ui_p0, ui_p1, color); - } break; + // case P_DebugDrawKind_Line: + // { + // Vec2 ui_p0 = MulXformV2(frame->xf.world_to_ui, n->line.p0); + // Vec2 ui_p1 = MulXformV2(frame->xf.world_to_ui, n->line.p1); + // V_DrawLine(ui_p0, ui_p1, color); + // } break; - case P_DebugDrawKind_Rect: - { - Rng2 ui_rect = Zi; - ui_rect.p0 = MulXformV2(frame->xf.world_to_ui, n->rect.p0); - ui_rect.p1 = MulXformV2(frame->xf.world_to_ui, n->rect.p1); - V_DrawRect(ui_rect, color, V_DrawFlag_Line); - } break; + // case P_DebugDrawKind_Rect: + // { + // Rng2 ui_rect = Zi; + // ui_rect.p0 = MulXformV2(frame->xf.world_to_ui, n->rect.p0); + // ui_rect.p1 = MulXformV2(frame->xf.world_to_ui, n->rect.p1); + // V_DrawRect(ui_rect, color, V_DrawFlag_Line); + // } break; - case P_DebugDrawKind_Shape: - { - P_Shape ui_shape = P_MulXformShape(frame->xf.world_to_ui, n->shape); - V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line); - } break; - } - } + // case P_DebugDrawKind_Shape: + // { + // P_Shape ui_shape = P_MulXformShape(frame->xf.world_to_ui, n->shape); + // V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line); + // } break; + // } + // } - // Reset vis debug draws - ResetArena(P_tl.debug_arena); - P_tl.first_debug_draw_node = 0; - P_tl.last_debug_draw_node = 0; - P_tl.debug_draw_nodes_count = 0; - } + // // Reset vis debug draws + // ResetArena(P_tl.debug_arena); + // P_tl.first_debug_draw_node = 0; + // P_tl.last_debug_draw_node = 0; + // P_tl.debug_draw_nodes_count = 0; + // } ////////////////////////////// //- Draw entities - // for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent)) + // for (P_Ent *ent = P_FirstEnt(blend_frame); ent->valid; ent = P_NextEnt(ent)) // { // Xform ent_to_world_xf = ent->xf; // Xform ent_to_draw_xf = MulXform(frame->xf.world_to_draw, ent_to_world_xf); @@ -3260,7 +3448,7 @@ void V_TickForever(WaveLaneCtx *lane) G_CopyCpuToTexture( frame->cl, gpu_tiles, VEC3I32(0, 0, 0), - world->tiles, VEC3I32(tiles_dims.x, tiles_dims.y, 1), + blend_world->tiles, VEC3I32(tiles_dims.x, tiles_dims.y, 1), RNG3I32(VEC3I32(0, 0, 0), VEC3I32(tiles_dims.x, tiles_dims.y, 1)) ); G_DumbMemoryLayoutSync(frame->cl, gpu_tiles, G_Layout_DirectQueue_ShaderRead); @@ -3372,28 +3560,28 @@ void V_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Prune ents - { - i64 ents_to_prune_count = 0; - P_Ent **ents_to_prune = PushStructsNoZero(frame->arena, P_Ent *, world->ents_count); - for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent)) - { - if (ent->exists <= 0) - { - ents_to_prune[ents_to_prune_count] = ent; - ents_to_prune_count += 1; - } - } + // { + // i64 ents_to_prune_count = 0; + // P_Ent **ents_to_prune = PushStructsNoZero(frame->arena, P_Ent *, world->ents_count); + // for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent)) + // { + // if (ent->exists <= 0) + // { + // ents_to_prune[ents_to_prune_count] = ent; + // ents_to_prune_count += 1; + // } + // } - for (i64 prune_idx = 0; prune_idx < ents_to_prune_count; ++prune_idx) - { - // FIXME: Add to free list - P_Ent *ent = ents_to_prune[prune_idx]; - P_EntBin *bin = &world->ent_bins[ent->key.v % world->ent_bins_count]; - DllQueueRemoveNP(bin->first, bin->last, ent, next_in_bin, prev_in_bin); - DllQueueRemove(world->first_ent, world->last_ent, ent); - world->ents_count -= 1; - } - } + // for (i64 prune_idx = 0; prune_idx < ents_to_prune_count; ++prune_idx) + // { + // // FIXME: Add to free list + // P_Ent *ent = ents_to_prune[prune_idx]; + // P_EntBin *bin = &world->ent_bins[ent->key.v % world->ent_bins_count]; + // DllQueueRemoveNP(bin->first, bin->last, ent, next_in_bin, prev_in_bin); + // DllQueueRemove(world->first_ent, world->last_ent, ent); + // world->ents_count -= 1; + // } + // } ////////////////////////////// //- End frame diff --git a/src/pp/pp_vis/pp_vis_core.h b/src/pp/pp_vis/pp_vis_core.h index 49bfe394..dc621cb0 100644 --- a/src/pp/pp_vis/pp_vis_core.h +++ b/src/pp/pp_vis/pp_vis_core.h @@ -260,7 +260,7 @@ Struct(V_Frame) Rng2 draw_selection; Rng2 world_selection; - // Commands + // Vis commands i64 cmds_count; V_CmdNode *first_cmd_node; V_CmdNode *last_cmd_node; @@ -271,11 +271,6 @@ Struct(V_Frame) f32 fire_held; f32 fire_presses; - // Sim cmds - u64 sim_cmds_count; - P_CmdNode *first_sim_cmd_node; - P_CmdNode *last_sim_cmd_node; - // Emitters i64 emitters_count; V_EmitterNode *first_emitter_node; @@ -291,6 +286,9 @@ Struct(V_Ctx) V_Panel *root_panel; V_Window *dragging_window; + // Sim commands + P_CmdList sim_cmds; + // Atomic monotonically increasing allocation counter sequence for GPU particle ring buffer u32 particle_seq; diff --git a/src/tar/tar.c b/src/tar/tar.c index 2a8ea3c2..0224089a 100644 --- a/src/tar/tar.c +++ b/src/tar/tar.c @@ -94,7 +94,7 @@ TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix) archive.lookup = InitDict(arena, (u64)((f64)num_files * TAR_ArchiveLookupTableCapacityFactor)); for (TAR_Entry *entry = archive.head; entry; entry = entry->next) { - u64 hash = HashFnv64(Fnv64Basis, entry->file_name); + u64 hash = HashString(entry->file_name); SetDictValue(arena, archive.lookup, hash, (u64)entry); } @@ -113,7 +113,7 @@ TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix) { if (parent_dir_name.text[parent_dir_name.len - 1] == '/') { - u64 hash = HashFnv64(Fnv64Basis, parent_dir_name); + u64 hash = HashString(parent_dir_name); parent_entry = (TAR_Entry *)DictValueFromHash(archive.lookup, hash); break; } @@ -133,7 +133,7 @@ TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix) Readonly Global TAR_Entry g_nil_tar_entry = ZI; TAR_Entry *TAR_EntryFromName(TAR_Archive *archive, String name) { - u64 hash = HashFnv64(Fnv64Basis, name); + u64 hash = HashString(name); TAR_Entry *lookup = (TAR_Entry *)DictValueFromHash(archive->lookup, hash); return lookup ? lookup : &g_nil_tar_entry; } diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index e8c10872..f0a6c4b6 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -24,7 +24,7 @@ UI_Key UI_KeyFromString(String str) { u64 top_tag = UI_Top(Tag); UI_Key key = Zi; - key.v = HashFnv64(top_tag, str); + key.v = HashStringEx(top_tag, str); return key; } @@ -340,7 +340,7 @@ void UI_PushDefaults(void) case UI_StyleKind_FontSize: { desc.style.FontSize = 16.0f; } break; case UI_StyleKind_Tint: { desc.style.Tint = Color_White; } break; case UI_StyleKind_TextColor: { desc.style.TextColor = Color_White; } break; - case UI_StyleKind_Tag: { desc.style.Tag = HashFnv64(Fnv64Basis, Lit("root")); } break; + case UI_StyleKind_Tag: { desc.style.Tag = HashString(Lit("root")); } break; case UI_StyleKind_DebugColor: { desc.style.DebugColor = Rgba(1, 0, 1, 0.5); } break; case UI_StyleKind_InvisibleDebugColor: { desc.style.InvisibleDebugColor = Rgba(0, 1, 1, 0.25); } break; case UI_StyleKind_BackgroundTextureSliceUv: { desc.style.BackgroundTextureSliceUv = RNG2(VEC2(0, 0), VEC2(1, 1)); } break;