From 5bc61c585458cccf69b337bc6d40037d6581951c Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Sat, 26 Oct 2024 15:47:34 -0400 Subject: [PATCH] [jak3] Support texture anim in TIE (#3734) Support animated textures in TIE. Apparently this is also used in jak 2 for robotank and we never noticed?? https://github.com/user-attachments/assets/bfa45a1a-4a96-4b25-817a-4327afcc7c98 Co-authored-by: water111 --- common/custom_data/Tfrag3Data.h | 4 +- decompiler/level_extractor/extract_tie.cpp | 26 ++++++++----- .../opengl_renderer/OpenGLRenderer.cpp | 6 ++- .../opengl_renderer/background/Tie3.cpp | 38 ++++++++++++++----- .../opengl_renderer/background/Tie3.h | 3 +- 5 files changed, 53 insertions(+), 24 deletions(-) diff --git a/common/custom_data/Tfrag3Data.h b/common/custom_data/Tfrag3Data.h index 729475fd9a6..2dac7cf479b 100644 --- a/common/custom_data/Tfrag3Data.h +++ b/common/custom_data/Tfrag3Data.h @@ -18,7 +18,7 @@ namespace tfrag3 { // - if changing any large things (vertices, vis, bvh, colors, textures) update get_memory_usage // - if adding a new category to the memory usage, update extract_level to print it. -constexpr int TFRAG3_VERSION = 42; +constexpr int TFRAG3_VERSION = 43; enum MemoryUsageCategory { TEXTURE, @@ -241,7 +241,7 @@ struct ShrubDraw { struct InstancedStripDraw { DrawMode mode; // the OpenGL draw settings. - u32 tree_tex_id = 0; // the texture that should be bound for the draw + s32 tree_tex_id = 0; // the texture that should be bound for the draw // the list of vertices in the draw. This includes the restart code of UINT32_MAX that OpenGL // will use to start a new strip. diff --git a/decompiler/level_extractor/extract_tie.cpp b/decompiler/level_extractor/extract_tie.cpp index 1d0dc08b5b1..577edb2c069 100644 --- a/decompiler/level_extractor/extract_tie.cpp +++ b/decompiler/level_extractor/extract_tie.cpp @@ -2339,7 +2339,7 @@ TieCategoryInfo get_jak1_tie_category(u32 flags) { return result; } -u32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb) { +s32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb) { if (combo_tex == 0) { // untextured combo_tex = (((u32)TextureDB::kPlaceholderWhiteTexturePage) << 16) | @@ -2348,7 +2348,7 @@ u32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb) // try looking it up in the existing textures that we have in the C++ renderer data. // (this is shared with tfrag) - u32 idx_in_lev_data = UINT32_MAX; + s32 idx_in_lev_data = INT32_MAX; for (u32 i = 0; i < lev.textures.size(); i++) { if (lev.textures[i].combo_id == combo_tex) { idx_in_lev_data = i; @@ -2356,7 +2356,7 @@ u32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb) } } - if (idx_in_lev_data == UINT32_MAX) { + if (idx_in_lev_data == INT32_MAX) { // didn't find it, have to add a new one texture. auto tex_it = tdb.textures.find(combo_tex); if (tex_it == tdb.textures.end()) { @@ -2378,14 +2378,20 @@ u32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb) new_tex.debug_tpage_name = tdb.tpage_names.at(tex_it->second.page); new_tex.data = tex_it->second.rgba_bytes; } + const auto& level_tex = lev.textures.at(idx_in_lev_data); + const auto& it = tdb.animated_tex_output_to_anim_slot.find(level_tex.debug_name); + if (it != tdb.animated_tex_output_to_anim_slot.end()) { + // lg::warn("TIE animated texture: {}", level_tex.debug_name); + return -int(it->second) - 1; + } return idx_in_lev_data; } void handle_wind_draw_for_strip( tfrag3::TieTree& tree, - std::unordered_map>& wind_draws_by_tex, + std::unordered_map>& wind_draws_by_tex, const std::vector>>& packed_vert_indices, - u32 idx_in_lev_data, + s32 idx_in_lev_data, DrawMode mode, const TieStrip& strip, const TieInstanceInfo& inst, @@ -2452,7 +2458,7 @@ void handle_wind_draw_for_strip( } void handle_draw_for_strip(tfrag3::TieTree& tree, - std::unordered_map>& static_draws_by_tex, + std::unordered_map>& static_draws_by_tex, std::vector& category_draws, const std::vector>>& packed_vert_indices, DrawMode mode, @@ -2542,8 +2548,8 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree, 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; + std::unordered_map> static_draws_by_tex; + std::unordered_map> wind_draws_by_tex; std::array, tfrag3::kNumTieCategories> draws_by_category; @@ -2632,7 +2638,7 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree, for (size_t strip_idx = 0; strip_idx < frag.strips.size(); strip_idx++) { auto& strip = frag.strips[strip_idx]; - u32 idx_in_lev_data = get_or_add_texture(strip.adgif.combo_tex, lev, tdb); + s32 idx_in_lev_data = get_or_add_texture(strip.adgif.combo_tex, lev, tdb); // determine the draw mode DrawMode mode = process_draw_mode(strip.adgif, frag.prog_info.misc_x == 0, frag.has_magic_tex0_bit, version, info.category); @@ -2649,7 +2655,7 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree, draws_by_category.at((int)info.category), packed_vert_indices, mode, idx_in_lev_data, strip, inst, ifrag, proto_idx, frag_idx, strip_idx, matrix_idx); - u32 envmap_tex_idx = + s32 envmap_tex_idx = get_or_add_texture(proto.envmap_adgif.value().combo_tex, lev, tdb); // second pass envmap draw mode, in envmap bucket, envmap-specific draw list diff --git a/game/graphics/opengl_renderer/OpenGLRenderer.cpp b/game/graphics/opengl_renderer/OpenGLRenderer.cpp index 377b72b1746..756e62275bf 100644 --- a/game/graphics/opengl_renderer/OpenGLRenderer.cpp +++ b/game/graphics/opengl_renderer/OpenGLRenderer.cpp @@ -168,7 +168,8 @@ void OpenGLRenderer::init_bucket_renderers_jak3() { std::vector{tfrag3::TFragmentTreeKind::NORMAL}, false, i, anim_slot_array()); Tie3* tie = init_bucket_renderer( fmt::format("tie-l{}-tfrag", i), BucketCategory::TIE, - GET_BUCKET_ID_FOR_LIST(BucketId::TIE_L0_TFRAG, BucketId::TIE_L1_TFRAG, i), i); + GET_BUCKET_ID_FOR_LIST(BucketId::TIE_L0_TFRAG, BucketId::TIE_L1_TFRAG, i), i, + anim_slot_array()); init_bucket_renderer( fmt::format("etie-l{}-tfrag", i), BucketCategory::TIE, GET_BUCKET_ID_FOR_LIST(BucketId::ETIE_L0_TFRAG, BucketId::ETIE_L1_TFRAG, i), tie, @@ -431,7 +432,8 @@ void OpenGLRenderer::init_bucket_renderers_jak2() { std::vector{tfrag3::TFragmentTreeKind::NORMAL}, false, i, anim_slot_array()); Tie3* tie = init_bucket_renderer( fmt::format("tie-l{}-tfrag", i), BucketCategory::TIE, - GET_BUCKET_ID_FOR_LIST(BucketId::TIE_L0_TFRAG, BucketId::TIE_L1_TFRAG, i), i); + GET_BUCKET_ID_FOR_LIST(BucketId::TIE_L0_TFRAG, BucketId::TIE_L1_TFRAG, i), i, + anim_slot_array()); init_bucket_renderer( fmt::format("etie-l{}-tfrag", i), BucketCategory::TIE, GET_BUCKET_ID_FOR_LIST(BucketId::ETIE_L0_TFRAG, BucketId::ETIE_L1_TFRAG, i), tie, diff --git a/game/graphics/opengl_renderer/background/Tie3.cpp b/game/graphics/opengl_renderer/background/Tie3.cpp index fe81dd91ffd..7ab938bd0ef 100644 --- a/game/graphics/opengl_renderer/background/Tie3.cpp +++ b/game/graphics/opengl_renderer/background/Tie3.cpp @@ -6,8 +6,15 @@ #include "third-party/imgui/imgui.h" -Tie3::Tie3(const std::string& name, int my_id, int level_id, tfrag3::TieCategory category) - : BucketRenderer(name, my_id), m_level_id(level_id), m_default_category(category) { +Tie3::Tie3(const std::string& name, + int my_id, + int level_id, + const std::vector* anim_slot_array, + tfrag3::TieCategory category) + : BucketRenderer(name, my_id), + m_level_id(level_id), + m_default_category(category), + m_anim_slot_array(anim_slot_array) { // regardless of how many we use some fixed max // we won't actually interp or upload to gpu the unused ones, but we need a fixed maximum so // indexing works properly. @@ -573,8 +580,12 @@ void Tie3::draw_matching_draws_for_tree(int idx, } } - if ((int)draw.tree_tex_id != last_texture) { - glBindTexture(GL_TEXTURE_2D, m_textures->at(draw.tree_tex_id)); + if (draw.tree_tex_id != last_texture) { + if (draw.tree_tex_id >= 0) { + glBindTexture(GL_TEXTURE_2D, m_textures->at(draw.tree_tex_id)); + } else { + glBindTexture(GL_TEXTURE_2D, m_anim_slot_array->at(-(draw.tree_tex_id + 1))); + } last_texture = draw.tree_tex_id; } @@ -665,8 +676,13 @@ void Tie3::envmap_second_pass_draw(const Tree& tree, } } - if ((int)draw.tree_tex_id != last_texture) { - glBindTexture(GL_TEXTURE_2D, m_textures->at(draw.tree_tex_id)); + if (draw.tree_tex_id != last_texture) { + if (draw.tree_tex_id >= 0) { + glBindTexture(GL_TEXTURE_2D, m_textures->at(draw.tree_tex_id)); + } else { + glBindTexture(GL_TEXTURE_2D, m_anim_slot_array->at(-(draw.tree_tex_id + 1))); + } + last_texture = draw.tree_tex_id; } @@ -922,8 +938,12 @@ void Tie3::render_tree_wind(int idx, for (size_t draw_idx = 0; draw_idx < tree.wind_draws->size(); draw_idx++) { const auto& draw = tree.wind_draws->operator[](draw_idx); - if ((int)draw.tree_tex_id != last_texture) { - glBindTexture(GL_TEXTURE_2D, m_textures->at(draw.tree_tex_id)); + if (draw.tree_tex_id != last_texture) { + if (draw.tree_tex_id >= 0) { + glBindTexture(GL_TEXTURE_2D, m_textures->at(draw.tree_tex_id)); + } else { + glBindTexture(GL_TEXTURE_2D, m_anim_slot_array->at(-(draw.tree_tex_id + 1))); + } last_texture = draw.tree_tex_id; } auto double_draw = setup_tfrag_shader(render_state, draw.mode, ShaderId::TFRAG3); @@ -993,7 +1013,7 @@ void Tie3AnotherCategory::render(DmaFollower& dma, } Tie3WithEnvmapJak1::Tie3WithEnvmapJak1(const std::string& name, int my_id, int level_id) - : Tie3(name, my_id, level_id, tfrag3::TieCategory::NORMAL) {} + : Tie3(name, my_id, level_id, nullptr, tfrag3::TieCategory::NORMAL) {} void Tie3WithEnvmapJak1::render(DmaFollower& dma, SharedRenderState* render_state, diff --git a/game/graphics/opengl_renderer/background/Tie3.h b/game/graphics/opengl_renderer/background/Tie3.h index e6e2b12f65d..cd1f49793da 100644 --- a/game/graphics/opengl_renderer/background/Tie3.h +++ b/game/graphics/opengl_renderer/background/Tie3.h @@ -30,6 +30,7 @@ class Tie3 : public BucketRenderer { Tie3(const std::string& name, int my_id, int level_id, + const std::vector* anim_slot_array, tfrag3::TieCategory category = tfrag3::TieCategory::NORMAL); void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override; void draw_debug_window() override; @@ -169,7 +170,7 @@ class Tie3 : public BucketRenderer { } m_uniforms; EtieUniforms m_etie_uniforms, m_etie_base_uniforms; - + const std::vector* m_anim_slot_array; static_assert(sizeof(WindWork) == 84 * 16); };