From e6b73f105822e2084e526f3fca84fa0774967bc4 Mon Sep 17 00:00:00 2001 From: Hat Kid <6624576+Hat-Kid@users.noreply.github.com> Date: Sun, 15 Oct 2023 16:36:14 +0200 Subject: [PATCH] custom levels: support for packing textures (#3089) --- custom_levels/test-zone/test-zone.jsonc | 30 ++++++++--- goalc/build_level/build_level.cpp | 66 ++++++++++++++++++------- 2 files changed, 72 insertions(+), 24 deletions(-) diff --git a/custom_levels/test-zone/test-zone.jsonc b/custom_levels/test-zone/test-zone.jsonc index ed0a568943..1f3420d4c9 100644 --- a/custom_levels/test-zone/test-zone.jsonc +++ b/custom_levels/test-zone/test-zone.jsonc @@ -38,6 +38,22 @@ // Note: You will still have to add them to your level's .gd file. "art_groups": ["plat-ag"], + // Any textures you want to include in your custom level. This is mainly useful for things such as the zoomer HUD, + // which is not in the common level files and has no art group associated with it. + // To get a list of all the textures, you can extract all of the game's textures + // by setting "save_texture_pngs" to true in the decompiler config. + "textures": [ + // all textures required for the zoomer HUD + // "zoomerhud", + // "zoomerhud-dial", + // "zoomerhud-main-02", + // "zoomerhud-main-03", + // "zoomerhud-pieslice", + // "zoomerhud-heatbg-01", + // "zoomerhud-main-03arrow", + // "zoomerhud-main-03knob" + ], + // Ambients you want to use in your custom level. Ambients can be used for various things like changing the music variation (flava), // adding ambient sounds, level name hints, etc. "ambients": [ @@ -58,10 +74,10 @@ "trans": [-21.6238, 20.0496, 17.1191], // translation "etype": "fuel-cell", // actor type "game_task": 0, // associated game task (for powercells, etc) - "quat" : [0, 0, 0, 1], // quaternion + "quat": [0, 0, 0, 1], // quaternion "bsphere": [-21.6238, 19.3496, 17.1191, 10], // bounding sphere "lump": { - "name":"test-fuel-cell" + "name": "test-fuel-cell" } }, @@ -69,11 +85,11 @@ "trans": [-15.2818, 15.2461, 17.1360], // translation "etype": "crate", // actor type "game_task": 0, // associated game task (for powercells, etc) - "quat" : [0, 0, 0, 1], // quaternion + "quat": [0, 0, 0, 1], // quaternion "bsphere": [-15.2818, 15.2461, 17.1360, 10], // bounding sphere "lump": { - "name":"test-crate", - "crate-type":"'steel", + "name": "test-crate", + "crate-type": "'steel", "eco-info": ["int32", 5, 10] } }, @@ -82,10 +98,10 @@ "trans": [-5.4630, 17.4553, 1.6169], // translation "etype": "eco-yellow", // actor type "game_task": 0, // associated game task (for powercells, etc) - "quat" : [0, 0, 0, 1], // quaternion + "quat": [0, 0, 0, 1], // quaternion "bsphere": [-5.4630, 17.4553, 1.6169, 10], // bounding sphere "lump": { - "name":"test-eco" + "name": "test-eco" } }, { diff --git a/goalc/build_level/build_level.cpp b/goalc/build_level/build_level.cpp index f5f7d69daa..417be470d8 100644 --- a/goalc/build_level/build_level.cpp +++ b/goalc/build_level/build_level.cpp @@ -144,7 +144,8 @@ bool run_build_level(const std::string& input_file, // Add textures and models // TODO remove hardcoded config settings - if (level_json.contains("art_groups") && !level_json.at("art_groups").empty()) { + if ((level_json.contains("art_groups") && !level_json.at("art_groups").empty()) || + (level_json.contains("textures") && !level_json.at("textures").empty())) { fs::path iso_folder = ""; lg::info("Looking for ISO path..."); // TODO - add to file_util @@ -171,7 +172,7 @@ bool run_build_level(const std::string& input_file, config = decompiler::read_config_file( file_util::get_jak_project_dir() / "decompiler/config/jak1/jak1_config.jsonc", version_info.decomp_config_version, - R"({"decompile_code": false, "find_functions": false, "levels_extract": true, "allowed_objects": []})"); + R"({"decompile_code": false, "find_functions": false, "levels_extract": true, "allowed_objects": [], "save_texture_pngs": false})"); } catch (const std::exception& e) { lg::error("Failed to parse config: {}", e.what()); return false; @@ -200,22 +201,53 @@ bool run_build_level(const std::string& input_file, std::vector processed_art_groups; // find all art groups used by the custom level in other dgos - for (auto& dgo : config.dgo_names) { - // remove "DGO/" prefix - const auto& dgo_name = dgo.substr(4); - const auto& files = db.obj_files_by_dgo.at(dgo_name); - auto art_groups = find_art_groups( - processed_art_groups, level_json.at("art_groups").get>(), files); - if (art_groups.empty()) { - continue; + if (level_json.contains("art_groups") && !level_json.at("art_groups").empty()) { + for (auto& dgo : config.dgo_names) { + // remove "DGO/" prefix + const auto& dgo_name = dgo.substr(4); + const auto& files = db.obj_files_by_dgo.at(dgo_name); + auto art_groups = + find_art_groups(processed_art_groups, + level_json.at("art_groups").get>(), files); + auto tex_remap = decompiler::extract_tex_remap(db, dgo_name); + for (const auto& ag : art_groups) { + if (ag.name.length() > 3 && !ag.name.compare(ag.name.length() - 3, 3, "-ag")) { + const auto& ag_file = db.lookup_record(ag); + lg::print("custom level: extracting art group {}\n", ag_file.name_in_dgo); + decompiler::extract_merc(ag_file, tex_db, db.dts, tex_remap, pc_level, false, + db.version()); + } + } } - auto tex_remap = decompiler::extract_tex_remap(db, dgo_name); - for (const auto& ag : art_groups) { - if (ag.name.length() > 3 && !ag.name.compare(ag.name.length() - 3, 3, "-ag")) { - const auto& ag_file = db.lookup_record(ag); - lg::print("custom level: extracting art group {}\n", ag_file.name_in_dgo); - decompiler::extract_merc(ag_file, tex_db, db.dts, tex_remap, pc_level, false, - db.version()); + } + + // add textures + if (level_json.contains("textures") && !level_json.at("textures").empty()) { + std::vector processed_textures; + std::vector wanted_texs = + level_json.at("textures").get>(); + // first check the texture is not already in the level + for (auto& level_tex : pc_level.textures) { + if (std::find(wanted_texs.begin(), wanted_texs.end(), level_tex.debug_name) != + wanted_texs.end()) { + processed_textures.push_back(level_tex.debug_name); + } + } + + // then add + for (auto& [id, tex] : tex_db.textures) { + for (auto& tex0 : wanted_texs) { + if (std::find(processed_textures.begin(), processed_textures.end(), tex.name) != + processed_textures.end()) { + continue; + } + if (tex.name == tex0) { + lg::info("custom level: adding texture {} from tpage {} ({})", tex.name, tex.page, + tex_db.tpage_names.at(tex.page)); + pc_level.textures.push_back( + make_texture(id, tex, tex_db.tpage_names.at(tex.page), true)); + processed_textures.push_back(tex.name); + } } } }