From 46c634686c512ef4197595ab9e2e742be5ef37a4 Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Mon, 4 Sep 2023 10:29:10 -0400 Subject: [PATCH] [gltf export] Export TIE wind models (#2960) Export models with "wind". The levels with wind models are: firecanyon (9), beach (5), village1 (7), lavatube (2). Sometimes a single object is made up of multiple models - for example the tree in sandover is actually several meshes. --- decompiler/level_extractor/fr3_to_gltf.cpp | 87 ++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/decompiler/level_extractor/fr3_to_gltf.cpp b/decompiler/level_extractor/fr3_to_gltf.cpp index ffeb7cc0e..ad6fddade 100644 --- a/decompiler/level_extractor/fr3_to_gltf.cpp +++ b/decompiler/level_extractor/fr3_to_gltf.cpp @@ -50,6 +50,28 @@ void unstrip_shrub_draws(const std::vector& stripped_indices, } } +void unstrip_tie_wind(std::vector& unstripped, + std::vector& draw_to_start, + std::vector& draw_to_count, + const std::vector& draws) { + for (auto& draw : draws) { + draw_to_start.push_back(unstripped.size()); + + for (size_t i = 2; i < draw.vertex_index_stream.size(); i++) { + u32 a = draw.vertex_index_stream[i]; + u32 b = draw.vertex_index_stream[i - 1]; + u32 c = draw.vertex_index_stream[i - 2]; + if (a == UINT32_MAX || b == UINT32_MAX || c == UINT32_MAX) { + continue; + } + unstripped.push_back(a); + unstripped.push_back(b); + unstripped.push_back(c); + } + draw_to_count.push_back(unstripped.size() - draw_to_start.back()); + } +} + /*! * Convert merc strips. Doesn't assume anything about strips. Output is [model][effect][draw] format */ @@ -384,6 +406,32 @@ int make_tfrag_tie_index_buffer_view(const std::vector& indices, return buffer_view_idx; } +int make_tie_wind_index_buffer_view(const std::vector& draws, + tinygltf::Model& model, + std::vector& draw_to_start, + std::vector& draw_to_count) { + std::vector unstripped; + unstrip_tie_wind(unstripped, draw_to_start, draw_to_count, draws); + + // first create a buffer: + int buffer_idx = (int)model.buffers.size(); + auto& buffer = model.buffers.emplace_back(); + buffer.data.resize(sizeof(u32) * unstripped.size()); + + // and fill it + memcpy(buffer.data.data(), unstripped.data(), buffer.data.size()); + + // create a view of this buffer + int buffer_view_idx = (int)model.bufferViews.size(); + auto& buffer_view = model.bufferViews.emplace_back(); + buffer_view.buffer = buffer_idx; + buffer_view.byteOffset = 0; + buffer_view.byteLength = buffer.data.size(); + buffer_view.byteStride = 0; // tightly packed + buffer_view.target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER; + return buffer_view_idx; +} + /*! * Create a tinygltf buffer and buffer view for indices, and convert to gltf format. * The map can be used to go from slots in the old index buffer to new. @@ -616,6 +664,45 @@ void add_tie(const tfrag3::Level& level, } prim.mode = TINYGLTF_MODE_TRIANGLES; } + + if (!tie.instanced_wind_draws.empty()) { + std::vector draw_to_start, draw_to_count; + int wind_index_buffer_view = make_tie_wind_index_buffer_view(tie.instanced_wind_draws, model, + draw_to_start, draw_to_count); + + for (size_t draw_idx = 0; draw_idx < tie.instanced_wind_draws.size(); draw_idx++) { + const auto& wind_draw = tie.instanced_wind_draws[draw_idx]; + int mat = + add_material_for_tex(level, model, wind_draw.tree_tex_id, tex_image_map, wind_draw.mode); + for (const auto& grp : wind_draw.instance_groups) { + int c_node_idx = (int)model.nodes.size(); + auto& c_node = model.nodes.emplace_back(); + model.nodes[node_idx].children.push_back(c_node_idx); + int c_mesh_idx = (int)model.meshes.size(); + auto& c_mesh = model.meshes.emplace_back(); + c_node.mesh = c_mesh_idx; + auto& prim = c_mesh.primitives.emplace_back(); + + const auto& info = tie.wind_instance_info.at(grp.instance_idx); + for (int i = 0; i < 4; i++) { + float scale = i == 3 ? (1.f / 4096.f) : 1.f; + for (int j = 0; j < 4; j++) { + c_node.matrix.push_back(scale * info.matrix[i][j]); + } + } + + prim.material = mat; + prim.indices = make_index_buffer_accessor( + model, draw_to_start.at(draw_idx), draw_to_count.at(draw_idx), wind_index_buffer_view); + prim.attributes["POSITION"] = position_buffer_accessor; + prim.attributes["TEXCOORD_0"] = texture_buffer_accessor; + for (int i = 0; i < kMaxColor; i++) { + prim.attributes[fmt::format("COLOR_{}", i)] = colors[i]; + } + prim.mode = TINYGLTF_MODE_TRIANGLES; + } + } + } } void add_shrub(const tfrag3::Level& level,