From ed38adc2a775959ef7a22d79a18c1cfd99da3184 Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Sat, 11 Feb 2023 12:00:05 -0500 Subject: [PATCH] [tie] support per-proto visibility flags (#2212) Jak 2 adds a feature to disable protos in TIE. It's used to hide things like steps for a future mission in ruins, and also to hide the static version of the tower when it switches to the merc version for the cutscene: ![image](https://user-images.githubusercontent.com/48171810/218270077-d8c52235-ddbf-4194-80f6-b8aa1eeeb7ec.png) --- common/custom_data/TFrag3Data.cpp | 3 + common/custom_data/Tfrag3Data.h | 9 +- common/util/Serializer.h | 11 ++ decompiler/level_extractor/extract_tfrag.cpp | 3 +- decompiler/level_extractor/extract_tie.cpp | 31 ++++- .../opengl_renderer/background/Tie3.cpp | 112 +++++++++++++++-- .../opengl_renderer/background/Tie3.h | 22 +++- .../background/background_common.cpp | 118 +++++++++++++++++- .../background/background_common.h | 17 ++- .../opengl_renderer/loader/Loader.cpp | 92 +++++++------- game/kernel/jak2/kprint.cpp | 1 + goal_src/jak2/engine/gfx/tie/tie-methods.gc | 53 ++++++++ goal_src/jak2/engine/load/loader.gc | 2 +- goalc/build_level/gltf_mesh_extract.cpp | 4 +- 14 files changed, 405 insertions(+), 73 deletions(-) diff --git a/common/custom_data/TFrag3Data.cpp b/common/custom_data/TFrag3Data.cpp index 36c65f0e46..e8138d5d0b 100644 --- a/common/custom_data/TFrag3Data.cpp +++ b/common/custom_data/TFrag3Data.cpp @@ -209,6 +209,9 @@ void TieTree::serialize(Serializer& ser) { packed_vertices.serialize(ser); ser.from_pod_vector(&colors); bvh.serialize(ser); + + ser.from_ptr(&has_per_proto_visibility_toggle); + ser.from_string_vector(&proto_names); } void ShrubTree::serialize(Serializer& ser) { diff --git a/common/custom_data/Tfrag3Data.h b/common/custom_data/Tfrag3Data.h index 83133d0596..b7be49e69d 100644 --- a/common/custom_data/Tfrag3Data.h +++ b/common/custom_data/Tfrag3Data.h @@ -73,7 +73,7 @@ struct MemoryUsageTracker { void add(MemoryUsageCategory category, u32 size_bytes) { data[category] += size_bytes; } }; -constexpr int TFRAG3_VERSION = 24; +constexpr int TFRAG3_VERSION = 25; // These vertices should be uploaded to the GPU at load time and don't change struct PreloadedVertex { @@ -188,7 +188,8 @@ struct StripDraw { struct VisGroup { u32 num_inds = 0; // number of vertex indices in this group u32 num_tris = 0; // number of triangles - u32 vis_idx_in_pc_bvh = 0; // the visibility group they belong to (in BVH) + u16 vis_idx_in_pc_bvh = 0; // the visibility group they belong to (in BVH) + u16 tie_proto_idx = 0; // index of tie proto (tie only) }; std::vector vis_groups; @@ -323,6 +324,10 @@ struct TieTree { std::vector instanced_wind_draws; std::vector wind_instance_info; + // jak 2 and later can toggle on and off visibility per proto by name + bool has_per_proto_visibility_toggle = false; + std::vector proto_names; + struct { std::vector vertices; // mesh vertices std::vector indices; diff --git a/common/util/Serializer.h b/common/util/Serializer.h index b8c1fff2d9..0452adc080 100644 --- a/common/util/Serializer.h +++ b/common/util/Serializer.h @@ -156,6 +156,17 @@ class Serializer { from_raw_data(vec->data(), sizeof(T) * vec->size()); } + void from_string_vector(std::vector* vec) { + if (is_saving()) { + save(vec->size()); + } else { + vec->resize(load()); + } + for (auto& str : *vec) { + from_str(&str); + } + } + /*! * Are we saving? */ diff --git a/decompiler/level_extractor/extract_tfrag.cpp b/decompiler/level_extractor/extract_tfrag.cpp index 3b816d8aa8..1172097174 100644 --- a/decompiler/level_extractor/extract_tfrag.cpp +++ b/decompiler/level_extractor/extract_tfrag.cpp @@ -2053,6 +2053,7 @@ void make_tfrag3_data(std::map>& draws, for (auto& strip : draw.strips) { tfrag3::StripDraw::VisGroup vgroup; + ASSERT(strip.tfrag_id < UINT16_MAX); vgroup.vis_idx_in_pc_bvh = strip.tfrag_id; // associate with the tfrag for culling vgroup.num_inds = strip.verts.size() + 1; // one for the primitive restart! vgroup.num_tris = strip.verts.size() - 2; @@ -2231,7 +2232,7 @@ void extract_tfrag(const level_tools::DrawableTreeTfrag* tree, for (auto& str : draw.vis_groups) { auto it = tfrag_parents.find(str.vis_idx_in_pc_bvh); if (it == tfrag_parents.end()) { - str.vis_idx_in_pc_bvh = UINT32_MAX; + str.vis_idx_in_pc_bvh = UINT16_MAX; } else { str.vis_idx_in_pc_bvh = it->second; } diff --git a/decompiler/level_extractor/extract_tie.cpp b/decompiler/level_extractor/extract_tie.cpp index a96fcb04b9..18024b7066 100644 --- a/decompiler/level_extractor/extract_tie.cpp +++ b/decompiler/level_extractor/extract_tie.cpp @@ -2026,14 +2026,24 @@ DrawMode process_draw_mode(const AdgifInfo& info, bool use_atest, bool use_decal void add_vertices_and_static_draw(tfrag3::TieTree& tree, tfrag3::Level& lev, const TextureDB& tdb, - const std::vector& protos) { + const std::vector& protos, + GameVersion version) { // our current approach for static draws is just to flatten to giant mesh, except for wind stuff. // this map sorts these two types of draws by texture. std::unordered_map> static_draws_by_tex; std::unordered_map> wind_draws_by_tex; + if (version > GameVersion::Jak1) { + tree.has_per_proto_visibility_toggle = true; + } + // loop over all prototypes - for (auto& proto : protos) { + for (size_t proto_idx = 0; proto_idx < protos.size(); proto_idx++) { + const auto& proto = protos[proto_idx]; + if (tree.has_per_proto_visibility_toggle) { + tree.proto_names.push_back(proto.name); + } + if (proto.uses_generic) { // generic ties go through generic continue; @@ -2220,7 +2230,15 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree, // now we have a draw, time to add vertices tfrag3::StripDraw::VisGroup vgroup; - vgroup.vis_idx_in_pc_bvh = inst.vis_id; // associate with the instance for culling + ASSERT(inst.vis_id < UINT16_MAX); + vgroup.vis_idx_in_pc_bvh = inst.vis_id; // associate with the instance for culling + + // only bother with tie proto idx if we use it + if (tree.has_per_proto_visibility_toggle) { + ASSERT(proto_idx < UINT16_MAX); + vgroup.tie_proto_idx = proto_idx; + } + vgroup.num_inds = strip.verts.size() + 1; // one for the primitive restart! vgroup.num_tris = strip.verts.size() - 2; draw_to_add_to->num_triangles += strip.verts.size() - 2; @@ -2284,7 +2302,8 @@ void merge_groups(std::vector& grps) { std::vector result; result.push_back(grps.at(0)); for (size_t i = 1; i < grps.size(); i++) { - if (grps[i].vis_idx_in_pc_bvh == result.back().vis_idx_in_pc_bvh) { + if (grps[i].vis_idx_in_pc_bvh == result.back().vis_idx_in_pc_bvh && + grps[i].tie_proto_idx == result.back().tie_proto_idx) { result.back().num_tris += grps[i].num_tris; result.back().num_inds += grps[i].num_inds; } else { @@ -2367,14 +2386,14 @@ void extract_tie(const level_tools::DrawableTreeInstanceTie* tree, auto full_palette = make_big_palette(info); // create draws - add_vertices_and_static_draw(this_tree, out, tex_db, info); + add_vertices_and_static_draw(this_tree, out, tex_db, info, version); // remap vis indices and merge for (auto& draw : this_tree.static_draws) { for (auto& str : draw.vis_groups) { auto it = instance_parents.find(str.vis_idx_in_pc_bvh); if (it == instance_parents.end()) { - str.vis_idx_in_pc_bvh = UINT32_MAX; + str.vis_idx_in_pc_bvh = UINT16_MAX; } else { str.vis_idx_in_pc_bvh = it->second; } diff --git a/game/graphics/opengl_renderer/background/Tie3.cpp b/game/graphics/opengl_renderer/background/Tie3.cpp index 301d676821..1766cf0477 100644 --- a/game/graphics/opengl_renderer/background/Tie3.cpp +++ b/game/graphics/opengl_renderer/background/Tie3.cpp @@ -2,6 +2,7 @@ #include "common/global_profiler/GlobalProfiler.h" #include "common/log/log.h" +#include "common/util/Assert.h" #include "third-party/imgui/imgui.h" @@ -120,6 +121,11 @@ void Tie3::update_load(const LevelData* loader_data) { } } + lod_tree[l_tree].has_proto_visibility = tree.has_per_proto_visibility_toggle; + if (tree.has_per_proto_visibility_toggle) { + lod_tree[l_tree].proto_visibility.init(tree.proto_names); + } + glActiveTexture(GL_TEXTURE10); glGenTextures(1, &lod_tree[l_tree].time_of_day_texture); glBindTexture(GL_TEXTURE_1D, lod_tree[l_tree].time_of_day_texture); @@ -139,6 +145,7 @@ void Tie3::update_load(const LevelData* loader_data) { m_wind_vectors.resize(4 * max_wind_idx + 4); // 4x u32's per wind. m_cache.draw_idx_temp.resize(max_draws); m_cache.index_temp.resize(max_inds); + ASSERT(time_of_day_count <= TIME_OF_DAY_COLOR_COUNT); } @@ -361,7 +368,14 @@ void Tie3::render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfi auto wind_data = dma.read_and_advance(); ASSERT(wind_data.size_bytes == sizeof(WindWork)); memcpy(&m_wind_data, wind_data.data, sizeof(WindWork)); - } else { + } + + const u8* proto_vis_data = nullptr; + size_t proto_vis_data_size = 0; + if (render_state->version == GameVersion::Jak2) { + auto proto_mask_data = dma.read_and_advance(); + proto_vis_data = proto_mask_data.data; + proto_vis_data_size = proto_mask_data.size_bytes; } while (dma.current_tag_offset() != render_state->next_bucket) { @@ -390,20 +404,22 @@ void Tie3::render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfi m_has_level = setup_for_level(m_pc_port_data.level_name, render_state); } - render_all_trees(lod(), settings, render_state, prof); + render_all_trees(lod(), settings, render_state, prof, proto_vis_data, proto_vis_data_size); } void Tie3::render_all_trees(int geom, const TfragRenderSettings& settings, SharedRenderState* render_state, - ScopedProfilerNode& prof) { + ScopedProfilerNode& prof, + const u8* proto_vis_data, + size_t proto_vis_data_size) { Timer all_tree_timer; if (m_override_level && m_pending_user_level) { m_has_level = setup_for_level(*m_pending_user_level, render_state); m_pending_user_level = {}; } for (u32 i = 0; i < m_trees[geom].size(); i++) { - render_tree(i, geom, settings, render_state, prof); + render_tree(i, geom, settings, render_state, prof, proto_vis_data, proto_vis_data_size); } m_all_tree_time.add(all_tree_timer.getSeconds()); } @@ -523,7 +539,9 @@ void Tie3::render_tree(int idx, int geom, const TfragRenderSettings& settings, SharedRenderState* render_state, - ScopedProfilerNode& prof) { + ScopedProfilerNode& prof, + const u8* proto_vis_data, + size_t proto_vis_data_size) { // reset perf Timer tree_timer; auto& tree = m_trees.at(geom).at(idx); @@ -540,6 +558,11 @@ void Tie3::render_tree(int idx, m_color_result.resize(tree.colors->size()); } + // update proto vis mask + if (proto_vis_data) { + tree.proto_visibility.update(proto_vis_data, proto_vis_data_size); + } + Timer interp_timer; if (m_use_fast_time_of_day) { interp_time_of_day_fast(settings.itimes, tree.tod_cache, m_color_result.data()); @@ -588,9 +611,15 @@ void Tie3::render_tree(int idx, make_all_visible_index_list(m_cache.draw_idx_temp.data(), m_cache.index_temp.data(), *tree.draws, tree.index_data, &num_tris); } else { - idx_buffer_size = make_index_list_from_vis_string( - m_cache.draw_idx_temp.data(), m_cache.index_temp.data(), *tree.draws, m_cache.vis_temp, - tree.index_data, &num_tris); + if (tree.has_proto_visibility) { + idx_buffer_size = make_index_list_from_vis_and_proto_string( + m_cache.draw_idx_temp.data(), m_cache.index_temp.data(), *tree.draws, m_cache.vis_temp, + tree.proto_visibility.vis_flags, tree.index_data, &num_tris); + } else { + idx_buffer_size = make_index_list_from_vis_string( + m_cache.draw_idx_temp.data(), m_cache.index_temp.data(), *tree.draws, m_cache.vis_temp, + tree.index_data, &num_tris); + } } glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_buffer_size * sizeof(u32), m_cache.index_temp.data(), @@ -606,9 +635,17 @@ void Tie3::render_tree(int idx, tree.perf.index_time.add(index_timer.getSeconds()); } else { Timer index_timer; - num_tris = make_multidraws_from_vis_string( - m_cache.multidraw_offset_per_stripdraw.data(), m_cache.multidraw_count_buffer.data(), - m_cache.multidraw_index_offset_buffer.data(), *tree.draws, m_cache.vis_temp); + if (tree.has_proto_visibility) { + num_tris = make_multidraws_from_vis_and_proto_string( + m_cache.multidraw_offset_per_stripdraw.data(), m_cache.multidraw_count_buffer.data(), + m_cache.multidraw_index_offset_buffer.data(), *tree.draws, m_cache.vis_temp, + tree.proto_visibility.vis_flags); + } else { + num_tris = make_multidraws_from_vis_string( + m_cache.multidraw_offset_per_stripdraw.data(), m_cache.multidraw_count_buffer.data(), + m_cache.multidraw_index_offset_buffer.data(), *tree.draws, m_cache.vis_temp); + } + tree.perf.index_time.add(index_timer.getSeconds()); } } @@ -731,6 +768,7 @@ void Tie3::draw_debug_window() { ImGui::Text("draw: %d", perf.draws); ImGui::Text("wind draw: %d", perf.wind_draws); ImGui::Text("total: %.2f", perf.tree_time.get()); + ImGui::Text("proto vis: %.2f", perf.proto_vis_time.get() * 1000.f); ImGui::Text("cull: %.2f index: %.2f tod: %.2f setup: %.2f draw: %.2f", perf.cull_time.get() * 1000.f, perf.index_time.get() * 1000.f, perf.tod_time.get() * 1000.f, perf.setup_time.get() * 1000.f, @@ -739,3 +777,55 @@ void Tie3::draw_debug_window() { } ImGui::Text("All trees: %.2f", 1000.f * m_all_tree_time.get()); } + +void TieProtoVisibility::init(const std::vector& names) { + vis_flags.resize(names.size()); + for (auto& x : vis_flags) { + x = 1; + } + all_visible = true; + name_to_idx.clear(); + size_t i = 0; + for (auto& name : names) { + name_to_idx[name].push_back(i++); + } +} + +void TieProtoVisibility::update(const u8* data, size_t size) { + char name_buffer[256]; // ?? + + if (!all_visible) { + for (auto& x : vis_flags) { + x = 1; + } + all_visible = true; + } + + const u8* end = data + size; + + while (true) { + int name_idx = 0; + while (*data) { + name_buffer[name_idx++] = *data; + data++; + } + if (name_idx) { + ASSERT(name_idx < 254); + name_buffer[name_idx] = '\0'; + const auto& it = name_to_idx.find(name_buffer); + if (it != name_to_idx.end()) { + all_visible = false; + for (auto x : name_to_idx.at(name_buffer)) { + vis_flags[x] = 0; + } + } + } + + while (*data == 0) { + if (data >= end) { + return; + } + data++; + } + } +} \ No newline at end of file diff --git a/game/graphics/opengl_renderer/background/Tie3.h b/game/graphics/opengl_renderer/background/Tie3.h index a7354e9a5e..9cf67b4f27 100644 --- a/game/graphics/opengl_renderer/background/Tie3.h +++ b/game/graphics/opengl_renderer/background/Tie3.h @@ -9,6 +9,16 @@ #include "game/graphics/opengl_renderer/background/background_common.h" #include "game/graphics/pipelines/opengl.h" +struct TieProtoVisibility { + void init(const std::vector& names); + void update(const u8* data, size_t size); + + std::vector vis_flags; + std::unordered_map> name_to_idx; + + bool all_visible = true; +}; + class Tie3 : public BucketRenderer { public: Tie3(const std::string& name, int my_id, int level_id); @@ -19,12 +29,16 @@ class Tie3 : public BucketRenderer { void render_all_trees(int geom, const TfragRenderSettings& settings, SharedRenderState* render_state, - ScopedProfilerNode& prof); + ScopedProfilerNode& prof, + const u8* proto_vis_data, + size_t proto_vis_data_size); void render_tree(int idx, int geom, const TfragRenderSettings& settings, SharedRenderState* render_state, - ScopedProfilerNode& prof); + ScopedProfilerNode& prof, + const u8* proto_vis_data, + size_t proto_vis_data_size); bool setup_for_level(const std::string& str, SharedRenderState* render_state); struct WindWork { @@ -70,12 +84,16 @@ class Tie3 : public BucketRenderer { GLuint wind_vertex_index_buffer; std::vector wind_vertex_index_offsets; + bool has_proto_visibility = false; + TieProtoVisibility proto_visibility; + struct { u32 draws = 0; u32 wind_draws = 0; Filtered cull_time; Filtered index_time; Filtered tod_time; + Filtered proto_vis_time; Filtered setup_time; Filtered draw_time; Filtered tree_time; diff --git a/game/graphics/opengl_renderer/background/background_common.cpp b/game/graphics/opengl_renderer/background/background_common.cpp index 1fa9e7b809..5b7bce94e6 100644 --- a/game/graphics/opengl_renderer/background/background_common.cpp +++ b/game/graphics/opengl_renderer/background/background_common.cpp @@ -516,7 +516,64 @@ u32 make_multidraws_from_vis_string(std::pair* draw_ptrs_out, u64 run_start = 0; for (auto& grp : draw.vis_groups) { sanity_check += grp.num_inds; - bool vis = grp.vis_idx_in_pc_bvh == 0xffffffff || vis_data[grp.vis_idx_in_pc_bvh]; + bool vis = grp.vis_idx_in_pc_bvh == UINT16_MAX || vis_data[grp.vis_idx_in_pc_bvh]; + if (vis) { + num_tris += grp.num_tris; + } + + if (building_run) { + if (!vis) { + building_run = false; + counts_out[md_idx] = iidx - run_start; + index_offsets_out[md_idx] = (void*)(run_start * sizeof(u32)); + ds.second++; + md_idx++; + } + } else { + if (vis) { + building_run = true; + run_start = iidx; + } + } + + iidx += grp.num_inds; + } + + if (building_run) { + building_run = false; + counts_out[md_idx] = iidx - run_start; + index_offsets_out[md_idx] = (void*)(run_start * sizeof(u32)); + ds.second++; + md_idx++; + } + + draw_ptrs_out[i] = ds; + } + return num_tris; +} + +u32 make_multidraws_from_vis_and_proto_string(std::pair* draw_ptrs_out, + GLsizei* counts_out, + void** index_offsets_out, + const std::vector& draws, + const std::vector& vis_data, + const std::vector& proto_vis_data) { + u64 md_idx = 0; + u32 num_tris = 0; + u32 sanity_check = 0; + for (size_t i = 0; i < draws.size(); i++) { + const auto& draw = draws[i]; + u64 iidx = draw.unpacked.idx_of_first_idx_in_full_buffer; + ASSERT(sanity_check == iidx); + std::pair ds; + ds.first = md_idx; + ds.second = 0; + bool building_run = false; + u64 run_start = 0; + for (auto& grp : draw.vis_groups) { + sanity_check += grp.num_inds; + bool vis = (grp.vis_idx_in_pc_bvh == UINT16_MAX || vis_data[grp.vis_idx_in_pc_bvh]) && + proto_vis_data[grp.tie_proto_idx]; if (vis) { num_tris += grp.num_tris; } @@ -569,7 +626,64 @@ u32 make_index_list_from_vis_string(std::pair* group_out, int run_start_out = 0; int run_start_in = 0; for (auto& grp : draw.vis_groups) { - bool vis = grp.vis_idx_in_pc_bvh == 0xffffffff || vis_data[grp.vis_idx_in_pc_bvh]; + bool vis = grp.vis_idx_in_pc_bvh == UINT16_MAX || vis_data[grp.vis_idx_in_pc_bvh]; + if (vis) { + num_tris += grp.num_tris; + } + + if (building_run) { + if (vis) { + idx_buffer_ptr += grp.num_inds; + } else { + building_run = false; + memcpy(&idx_out[run_start_out], + idx_in + draw.unpacked.idx_of_first_idx_in_full_buffer + run_start_in, + (idx_buffer_ptr - run_start_out) * sizeof(u32)); + } + } else { + if (vis) { + building_run = true; + run_start_out = idx_buffer_ptr; + run_start_in = vtx_idx; + idx_buffer_ptr += grp.num_inds; + } + } + vtx_idx += grp.num_inds; + } + + if (building_run) { + memcpy(&idx_out[run_start_out], + idx_in + draw.unpacked.idx_of_first_idx_in_full_buffer + run_start_in, + (idx_buffer_ptr - run_start_out) * sizeof(u32)); + } + + ds.second = idx_buffer_ptr - ds.first; + group_out[i] = ds; + } + *num_tris_out = num_tris; + return idx_buffer_ptr; +} + +u32 make_index_list_from_vis_and_proto_string(std::pair* group_out, + u32* idx_out, + const std::vector& draws, + const std::vector& vis_data, + const std::vector& proto_vis_data, + const u32* idx_in, + u32* num_tris_out) { + int idx_buffer_ptr = 0; + u32 num_tris = 0; + for (size_t i = 0; i < draws.size(); i++) { + const auto& draw = draws[i]; + int vtx_idx = 0; + std::pair ds; + ds.first = idx_buffer_ptr; + bool building_run = false; + int run_start_out = 0; + int run_start_in = 0; + for (auto& grp : draw.vis_groups) { + bool vis = (grp.vis_idx_in_pc_bvh == UINT16_MAX || vis_data[grp.vis_idx_in_pc_bvh]) && + proto_vis_data[grp.tie_proto_idx]; if (vis) { num_tris += grp.num_tris; } diff --git a/game/graphics/opengl_renderer/background/background_common.h b/game/graphics/opengl_renderer/background/background_common.h index 6d4c1049e1..49544a62e8 100644 --- a/game/graphics/opengl_renderer/background/background_common.h +++ b/game/graphics/opengl_renderer/background/background_common.h @@ -99,4 +99,19 @@ u32 make_index_list_from_vis_string(std::pair* group_out, u32 make_all_visible_index_list(std::pair* group_out, u32* idx_out, const std::vector& draws, - const u32* idx_in); \ No newline at end of file + const u32* idx_in); + +u32 make_multidraws_from_vis_and_proto_string(std::pair* draw_ptrs_out, + GLsizei* counts_out, + void** index_offsets_out, + const std::vector& draws, + const std::vector& vis_data, + const std::vector& proto_vis_data); + +u32 make_index_list_from_vis_and_proto_string(std::pair* group_out, + u32* idx_out, + const std::vector& draws, + const std::vector& vis_data, + const std::vector& proto_vis_data, + const u32* idx_in, + u32* num_tris_out); \ No newline at end of file diff --git a/game/graphics/opengl_renderer/loader/Loader.cpp b/game/graphics/opengl_renderer/loader/Loader.cpp index dff2e68477..1f802a0be3 100644 --- a/game/graphics/opengl_renderer/loader/Loader.cpp +++ b/game/graphics/opengl_renderer/loader/Loader.cpp @@ -415,61 +415,63 @@ void Loader::update(TexturePool& texture_pool) { Timer unload_timer; if ((int)m_loaded_tfrag3_levels.size() >= m_max_levels) { auto to_unload = get_most_unloadable_level(); - auto& lev = m_loaded_tfrag3_levels.at(*to_unload); - std::unique_lock lk(texture_pool.mutex()); - fmt::print("------------------------- PC unloading {}\n", *to_unload); - for (size_t i = 0; i < lev->level->textures.size(); i++) { - auto& tex = lev->level->textures[i]; - if (tex.load_to_pool) { - texture_pool.unload_texture(PcTextureId::from_combo_id(tex.combo_id), - lev->textures.at(i)); + if (to_unload) { + auto& lev = m_loaded_tfrag3_levels.at(*to_unload); + std::unique_lock lk(texture_pool.mutex()); + fmt::print("------------------------- PC unloading {}\n", *to_unload); + for (size_t i = 0; i < lev->level->textures.size(); i++) { + auto& tex = lev->level->textures[i]; + if (tex.load_to_pool) { + texture_pool.unload_texture(PcTextureId::from_combo_id(tex.combo_id), + lev->textures.at(i)); + } } - } - lk.unlock(); - for (auto tex : lev->textures) { - if (EXTRA_TEX_DEBUG) { - for (auto& slot : texture_pool.all_textures()) { - if (slot.source) { - ASSERT(slot.gpu_texture != tex); - } else { - ASSERT(slot.gpu_texture != tex); + lk.unlock(); + for (auto tex : lev->textures) { + if (EXTRA_TEX_DEBUG) { + for (auto& slot : texture_pool.all_textures()) { + if (slot.source) { + ASSERT(slot.gpu_texture != tex); + } else { + ASSERT(slot.gpu_texture != tex); + } } } + + glBindTexture(GL_TEXTURE_2D, tex); + glDeleteTextures(1, &tex); } - glBindTexture(GL_TEXTURE_2D, tex); - glDeleteTextures(1, &tex); - } - - for (auto& tie_geo : lev->tie_data) { - for (auto& tie_tree : tie_geo) { - glDeleteBuffers(1, &tie_tree.vertex_buffer); - if (tie_tree.has_wind) { - glDeleteBuffers(1, &tie_tree.wind_indices); + for (auto& tie_geo : lev->tie_data) { + for (auto& tie_tree : tie_geo) { + glDeleteBuffers(1, &tie_tree.vertex_buffer); + if (tie_tree.has_wind) { + glDeleteBuffers(1, &tie_tree.wind_indices); + } + glDeleteBuffers(1, &tie_tree.index_buffer); } - glDeleteBuffers(1, &tie_tree.index_buffer); } - } - for (auto& tfrag_geo : lev->tfrag_vertex_data) { - for (auto& tfrag_buff : tfrag_geo) { - glDeleteBuffers(1, &tfrag_buff); + for (auto& tfrag_geo : lev->tfrag_vertex_data) { + for (auto& tfrag_buff : tfrag_geo) { + glDeleteBuffers(1, &tfrag_buff); + } } + + glDeleteBuffers(1, &lev->collide_vertices); + glDeleteBuffers(1, &lev->merc_vertices); + glDeleteBuffers(1, &lev->merc_indices); + + for (auto& model : lev->level->merc_data.models) { + auto& mercs = m_all_merc_models.at(model.name); + MercRef ref{&model, lev->load_id}; + auto it = std::find(mercs.begin(), mercs.end(), ref); + ASSERT_MSG(it != mercs.end(), fmt::format("missing merc: {}\n", model.name)); + mercs.erase(it); + } + + m_loaded_tfrag3_levels.erase(*to_unload); } - - glDeleteBuffers(1, &lev->collide_vertices); - glDeleteBuffers(1, &lev->merc_vertices); - glDeleteBuffers(1, &lev->merc_indices); - - for (auto& model : lev->level->merc_data.models) { - auto& mercs = m_all_merc_models.at(model.name); - MercRef ref{&model, lev->load_id}; - auto it = std::find(mercs.begin(), mercs.end(), ref); - ASSERT_MSG(it != mercs.end(), fmt::format("missing merc: {}\n", model.name)); - mercs.erase(it); - } - - m_loaded_tfrag3_levels.erase(*to_unload); } if (unload_timer.getMs() > 5.f) { diff --git a/game/kernel/jak2/kprint.cpp b/game/kernel/jak2/kprint.cpp index 456566467d..4333284922 100644 --- a/game/kernel/jak2/kprint.cpp +++ b/game/kernel/jak2/kprint.cpp @@ -515,6 +515,7 @@ s32 format_impl_jak2(uint64_t* args) { default: MsgErr("format: unknown code 0x%02x\n", format_ptr[1]); + MsgErr("input was %s\n", format_cstring); ASSERT(false); break; } diff --git a/goal_src/jak2/engine/gfx/tie/tie-methods.gc b/goal_src/jak2/engine/gfx/tie/tie-methods.gc index 55a757cebb..2887240c6c 100644 --- a/goal_src/jak2/engine/gfx/tie/tie-methods.gc +++ b/goal_src/jak2/engine/gfx/tie/tie-methods.gc @@ -58,6 +58,58 @@ ;; definition for function draw-inline-array-prototype-tie-asm ;; ERROR: function was not converted to expressions. Cannot decompile. +(defun pc-add-tie-vis-mask ((lev level) (dma-buf dma-buffer)) + "Add data so Tie3.cpp can hide protos." + (let ((packet (the-as dma-packet (-> dma-buf base)))) + (set! (-> packet vif0) (new 'static 'vif-tag)) + (set! (-> packet vif1) (new 'static 'vif-tag :cmd (vif-cmd pc-port))) + (set! (-> dma-buf base) (the pointer (&+ packet 16))) + + (let ((lev-trees (-> lev bsp drawable-trees)) + (data-ptr (the (pointer uint8) (-> dma-buf base))) + ) + (dotimes (tree-idx (-> lev-trees length)) + (let ((tree (-> lev-trees data tree-idx))) + (when (= (-> tree type) drawable-tree-instance-tie) + (let* ((tie-tree (the drawable-tree-instance-tie tree)) + (protos (-> tie-tree prototypes prototype-array-tie)) + ) + (dotimes (i (-> protos length)) + (let ((proto (-> protos array-data i))) + (when (logtest? (-> proto flags) (prototype-flags visible)) + ;; invisible! + ;(format 0 "invis: ~A~%" (-> proto name)) + (let ((src (-> proto name data))) + (while (nonzero? (-> src)) + (set! (-> data-ptr) (-> src)) + (&+! src 1) + (&+! data-ptr 1) + ) + (set! (-> data-ptr) 0) + (&+! data-ptr 1) + ) + ) + ) + ) + ) + ) + ) + ) + ;; align + (while (nonzero? (logand data-ptr #xf)) + (set! (-> data-ptr) 0) + (&+! data-ptr 1) + ) + (set! (-> packet dma) (new 'static 'dma-tag + :id (dma-tag-id cnt) + :qwc (/ (&- data-ptr (-> dma-buf base)) 16)) + ) + (set! (-> dma-buf base) data-ptr) + #f + ) + ) + ) + (defun instance-tie-patch-buckets ((arg0 dma-buffer) (arg1 level)) ; (when (logtest? (-> *display* vu1-enable-user) (vu1-renderer-mask tie)) ; (when (nonzero? (-> *prototype-tie-work* scissor-count)) @@ -167,6 +219,7 @@ ; ) ; (&+! (-> v1-42 base) 16) (add-pc-tfrag3-data v1-42 arg1) + (pc-add-tie-vis-mask arg1 v1-42) (let ((a3-16 (-> v1-42 base))) (let ((a0-20 (the-as dma-packet (-> v1-42 base)))) (set! (-> a0-20 dma) (new 'static 'dma-tag :id (dma-tag-id next))) diff --git a/goal_src/jak2/engine/load/loader.gc b/goal_src/jak2/engine/load/loader.gc index 23fea32055..6a43d1666b 100644 --- a/goal_src/jak2/engine/load/loader.gc +++ b/goal_src/jak2/engine/load/loader.gc @@ -1117,7 +1117,7 @@ (else (format 0 - "ERROR: ~A in spool anim loop for ~A ~D, but not loaded.~" + "ERROR: ~A in spool anim loop for ~A ~D, but not loaded.~%" ;; fixed missing %. self (-> gp-0 anim name) (-> gp-0 part) diff --git a/goalc/build_level/gltf_mesh_extract.cpp b/goalc/build_level/gltf_mesh_extract.cpp index 82359441e6..5c1914f3e9 100644 --- a/goalc/build_level/gltf_mesh_extract.cpp +++ b/goalc/build_level/gltf_mesh_extract.cpp @@ -556,12 +556,12 @@ void extract(const Input& in, auto& grp = draw.vis_groups.emplace_back(); grp.num_inds += prim_indices.size(); grp.num_tris += draw.num_triangles; - grp.vis_idx_in_pc_bvh = UINT32_MAX; + grp.vis_idx_in_pc_bvh = UINT16_MAX; } else { auto& grp = draw.vis_groups.back(); grp.num_inds += prim_indices.size(); grp.num_tris += draw.num_triangles; - grp.vis_idx_in_pc_bvh = UINT32_MAX; + grp.vis_idx_in_pc_bvh = UINT16_MAX; } draw.plain_indices.insert(draw.plain_indices.end(), prim_indices.begin(),