From 9d680a0abab36b2573f075e95e26d023e1df3311 Mon Sep 17 00:00:00 2001 From: Matt Dallmeyer Date: Fri, 5 Jan 2024 00:36:09 -0800 Subject: [PATCH] Support extracting collision to obj for jak2/3 formats (#3292) ![image](https://github.com/open-goal/jak-project/assets/2515356/b4d43254-4fc4-4f66-92d1-0d61e471b90e) ![image](https://github.com/open-goal/jak-project/assets/2515356/d2fa9fb8-5f51-43c5-8e0e-b51b64499b72) --- .../level_extractor/extract_collide_frags.cpp | 48 +++++++++++++++++-- .../level_extractor/extract_collide_frags.h | 8 +++- decompiler/level_extractor/extract_level.cpp | 12 +++-- 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/decompiler/level_extractor/extract_collide_frags.cpp b/decompiler/level_extractor/extract_collide_frags.cpp index f86393f9c..23eb19e78 100644 --- a/decompiler/level_extractor/extract_collide_frags.cpp +++ b/decompiler/level_extractor/extract_collide_frags.cpp @@ -1,5 +1,6 @@ #include "extract_collide_frags.h" +#include "common/log/log.h" #include "common/util/FileUtil.h" namespace decompiler { @@ -230,6 +231,7 @@ void set_vertices_for_tri(tfrag3::CollisionMesh::Vertex* out, const math::Vector void extract_collide_frags(const level_tools::DrawableTreeCollideFragment* tree, const std::vector& ties, + const Config& config, const std::string& debug_name, tfrag3::Level& out, bool dump_level) { @@ -260,8 +262,8 @@ void extract_collide_frags(const level_tools::DrawableTreeCollideFragment* tree, if (dump_level) { auto debug_out = debug_dump_to_obj(all_frags); - auto file_path = - file_util::get_file_path({"debug_out", fmt::format("collide-{}.obj", debug_name)}); + auto file_path = file_util::get_file_path( + {fmt::format("debug_out/{}", config.game_name), fmt::format("collide-{}.obj", debug_name)}); file_util::create_dir_if_needed_for_file(file_path); file_util::write_text_file(file_path, debug_out); } @@ -408,10 +410,40 @@ void handle_collide_fragment(const TypedRef& collide_fragment, } } +std::string debug_dump_to_obj(const std::vector& verts_in) { + std::vector verts; + std::vector> faces; + + for (auto& v : verts_in) { + verts.emplace_back(v.x / 4096.0, v.y / 4096.0, v.z / 4096.0, 1.0); + + u32 v_len = verts.size(); + if (v_len % 3 == 0) { + // add face from last 3 vertices + faces.emplace_back(v_len - 2, v_len - 1, v_len); + } + } + + std::string result; + for (auto& vert : verts) { + result += fmt::format("v {} {} {}\n", vert.x(), vert.y(), vert.z()); + } + + for (auto& face : faces) { + result += fmt::format("f {}/{} {}/{} {}/{}\n", face.x(), face.x(), face.y(), face.y(), face.z(), + face.z()); + } + + return result; +} + void extract_collide_frags(const level_tools::CollideHash& chash, const std::vector& ties, + const Config& config, + const std::string& debug_name, const decompiler::DecompilerTypeSystem& dts, - tfrag3::Level& out) { + tfrag3::Level& out, + bool dump_level) { // We need to find all collide-hash-fragments, but we can't just scan through the entire file. // for collide-hash-fragments, we need to figure out which TIEs they belong to, to apply the // instance transformation matrix. @@ -474,5 +506,15 @@ void extract_collide_frags(const level_tools::CollideHash& chash, } } } + + if (dump_level) { + // out.collision.vertices every 3 vertices make a face, so it duplicates vertices in many cases + // for now debug_dump_to_obj isn't smart and doesn't hash these to save space or anything + auto debug_out = debug_dump_to_obj(out.collision.vertices); + auto file_path = file_util::get_file_path( + {fmt::format("debug_out/{}", config.game_name), fmt::format("collide-{}.obj", debug_name)}); + file_util::create_dir_if_needed_for_file(file_path); + file_util::write_text_file(file_path, debug_out); + } } } // namespace decompiler diff --git a/decompiler/level_extractor/extract_collide_frags.h b/decompiler/level_extractor/extract_collide_frags.h index 0b9d239b2..7abd90ef1 100644 --- a/decompiler/level_extractor/extract_collide_frags.h +++ b/decompiler/level_extractor/extract_collide_frags.h @@ -8,13 +8,17 @@ namespace decompiler { void extract_collide_frags(const level_tools::DrawableTreeCollideFragment* tree, const std::vector& ties, + const Config& config, const std::string& debug_name, tfrag3::Level& out, bool dump_level); void extract_collide_frags(const level_tools::CollideHash& chash, const std::vector& ties, + const Config& config, + const std::string& debug_name, const decompiler::DecompilerTypeSystem& dts, - tfrag3::Level& out); + tfrag3::Level& out, + bool dump_level); -} // namespace decompiler \ No newline at end of file +} // namespace decompiler diff --git a/decompiler/level_extractor/extract_level.cpp b/decompiler/level_extractor/extract_level.cpp index aa9eda114..0104849c6 100644 --- a/decompiler/level_extractor/extract_level.cpp +++ b/decompiler/level_extractor/extract_level.cpp @@ -159,9 +159,10 @@ std::vector extract_tex_remap(const ObjectFileDB& db, level_tools::BspHeader extract_bsp_from_level(const ObjectFileDB& db, const TextureDB& tex_db, const std::string& dgo_name, - const DecompileHacks& hacks, + const Config& config, bool extract_collision, tfrag3::Level& level_data) { + auto hacks = config.hacks; auto bsp_rec = get_bsp_file(db.obj_files_by_dgo.at(dgo_name), dgo_name); if (!bsp_rec) { lg::warn("Skipping extract for {} because the BSP file was not found", dgo_name); @@ -236,8 +237,8 @@ level_tools::BspHeader extract_bsp_from_level(const ObjectFileDB& db, ASSERT(as_collide_frags); ASSERT(!got_collide); got_collide = true; - extract_collide_frags(as_collide_frags, all_ties, fmt::format("{}-{}-collide", dgo_name, i++), - level_data, false); + extract_collide_frags(as_collide_frags, all_ties, config, + fmt::format("{}-{}-collide", dgo_name, i++), level_data, false); } else { lg::print(" unsupported tree {}\n", draw_tree->my_type()); } @@ -245,7 +246,8 @@ level_tools::BspHeader extract_bsp_from_level(const ObjectFileDB& db, if (bsp_header.collide_hash.num_items) { ASSERT(!got_collide); - extract_collide_frags(bsp_header.collide_hash, all_ties, db.dts, level_data); + extract_collide_frags(bsp_header.collide_hash, all_ties, config, + fmt::format("{}-{}-collide", dgo_name, i++), db.dts, level_data, false); } level_data.level_name = level_name; @@ -348,7 +350,7 @@ void extract_from_level(const ObjectFileDB& db, // the bsp header file data auto bsp_header = - extract_bsp_from_level(db, tex_db, dgo_name, config.hacks, extract_collision, level_data); + extract_bsp_from_level(db, tex_db, dgo_name, config, extract_collision, level_data); extract_art_groups_from_level(db, tex_db, bsp_header.texture_remap_table, dgo_name, level_data, art_group_data);