mirror of
https://github.com/open-goal/jak-project
synced 2026-07-07 06:05:15 -04:00
custom models: option to copy mod/eye draws from original model (#3800)
Two new flags were added to the Blender plugin to allow reusing the mod and/or eye draws of the original model that is being replaced. Works pretty well for eyes, but the blerc draws can cause some Z-fighting with the non-moving parts of the model. Also a small refactor to the merc replacement code to de-duplicate some code by moving stuff to `gltf_util.cpp`.
This commit is contained in:
@@ -756,4 +756,89 @@ tfrag3::PackedTimeOfDay pack_time_of_day(const std::vector<math::Vector<u8, 4>>&
|
||||
return colors;
|
||||
}
|
||||
|
||||
void process_normal_merc_draw(const tinygltf::Model& model,
|
||||
MercExtractData& out,
|
||||
u32 tex_offset,
|
||||
tfrag3::MercEffect& eff,
|
||||
int mat_idx,
|
||||
const tfrag3::MercDraw& d_) {
|
||||
const auto& mat = model.materials[mat_idx];
|
||||
eff.all_draws.push_back(d_);
|
||||
auto& draw = eff.all_draws.back();
|
||||
draw.mode = gltf_util::make_default_draw_mode();
|
||||
|
||||
if (mat_idx == -1) {
|
||||
lg::warn("Draw had a material index of -1, using default texture.");
|
||||
draw.tree_tex_id = 0;
|
||||
return;
|
||||
}
|
||||
int tex_idx = mat.pbrMetallicRoughness.baseColorTexture.index;
|
||||
if (tex_idx == -1) {
|
||||
lg::warn("Material {} has no texture, using default texture.", mat.name);
|
||||
draw.tree_tex_id = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& tex = model.textures[tex_idx];
|
||||
ASSERT(tex.sampler >= 0);
|
||||
ASSERT(tex.source >= 0);
|
||||
gltf_util::setup_draw_mode_from_sampler(model.samplers.at(tex.sampler), &draw.mode);
|
||||
gltf_util::setup_alpha_from_material(mat, &draw.mode);
|
||||
|
||||
const auto& img = model.images[tex.source];
|
||||
draw.tree_tex_id = tex_offset + texture_pool_add_texture(&out.tex_pool, img);
|
||||
};
|
||||
|
||||
void process_envmap_merc_draw(const tinygltf::Model& model,
|
||||
MercExtractData& out,
|
||||
u32 tex_offset,
|
||||
tfrag3::MercEffect& eff,
|
||||
int mat_idx,
|
||||
const tfrag3::MercDraw& d_) {
|
||||
const auto& mat = model.materials[mat_idx];
|
||||
eff.all_draws.push_back(d_);
|
||||
auto& draw = eff.all_draws.back();
|
||||
draw.mode = gltf_util::make_default_draw_mode();
|
||||
|
||||
if (mat_idx == -1) {
|
||||
lg::warn("Envmap draw had a material index of -1, using default texture.");
|
||||
draw.tree_tex_id = texture_pool_debug_checker(&out.tex_pool);
|
||||
return;
|
||||
}
|
||||
int base_tex_idx = mat.pbrMetallicRoughness.baseColorTexture.index;
|
||||
if (base_tex_idx == -1) {
|
||||
lg::warn("Envmap material {} has no texture, using default texture.", mat.name);
|
||||
draw.tree_tex_id = texture_pool_debug_checker(&out.tex_pool);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& base_tex = model.textures[base_tex_idx];
|
||||
ASSERT(base_tex.sampler >= 0);
|
||||
ASSERT(base_tex.source >= 0);
|
||||
gltf_util::setup_draw_mode_from_sampler(model.samplers.at(base_tex.sampler), &draw.mode);
|
||||
gltf_util::setup_alpha_from_material(mat, &draw.mode);
|
||||
const auto& roughness_tex =
|
||||
model.textures.at(mat.pbrMetallicRoughness.metallicRoughnessTexture.index);
|
||||
ASSERT(roughness_tex.sampler >= 0);
|
||||
ASSERT(roughness_tex.source >= 0);
|
||||
|
||||
draw.tree_tex_id =
|
||||
tex_offset + gltf_util::texture_pool_add_envmap_control_texture(
|
||||
&out.tex_pool, model, base_tex.source, roughness_tex.source,
|
||||
!draw.mode.get_clamp_s_enable(), !draw.mode.get_clamp_t_enable());
|
||||
|
||||
// now, setup envmap draw:
|
||||
auto envmap_settings = gltf_util::envmap_settings_from_gltf(mat);
|
||||
const auto& envmap_tex = model.textures[envmap_settings.texture_idx];
|
||||
ASSERT(envmap_tex.sampler >= 0);
|
||||
ASSERT(envmap_tex.source >= 0);
|
||||
auto env_mode = gltf_util::make_default_draw_mode();
|
||||
gltf_util::setup_draw_mode_from_sampler(model.samplers.at(envmap_tex.sampler), &env_mode);
|
||||
eff.envmap_texture = tex_offset + gltf_util::texture_pool_add_texture(
|
||||
&out.tex_pool, model.images[envmap_tex.source]);
|
||||
env_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_0_DST_DST);
|
||||
env_mode.enable_ab();
|
||||
eff.envmap_mode = env_mode;
|
||||
};
|
||||
|
||||
} // namespace gltf_util
|
||||
@@ -180,4 +180,35 @@ math::Matrix4f matrix_from_trs(const math::Vector3f& trans,
|
||||
|
||||
tfrag3::PackedTimeOfDay pack_time_of_day(const std::vector<math::Vector<u8, 4>>& color_palette);
|
||||
|
||||
struct MercExtractData {
|
||||
TexturePool tex_pool;
|
||||
std::vector<u32> new_indices;
|
||||
std::vector<tfrag3::PreloadedVertex> new_vertices;
|
||||
std::vector<math::Vector<u8, 4>> new_colors;
|
||||
std::vector<math::Vector3f> normals;
|
||||
std::vector<JointsAndWeights> joints_and_weights;
|
||||
tfrag3::MercModel new_model;
|
||||
};
|
||||
|
||||
// Data produced by loading a replacement model
|
||||
struct MercSwapData {
|
||||
std::vector<u32> new_indices;
|
||||
std::vector<tfrag3::MercVertex> new_vertices;
|
||||
std::vector<tfrag3::Texture> new_textures;
|
||||
tfrag3::MercModel new_model;
|
||||
};
|
||||
|
||||
void process_normal_merc_draw(const tinygltf::Model& model,
|
||||
MercExtractData& out,
|
||||
u32 tex_offset,
|
||||
tfrag3::MercEffect& eff,
|
||||
int mat_idx,
|
||||
const tfrag3::MercDraw& d_);
|
||||
void process_envmap_merc_draw(const tinygltf::Model& model,
|
||||
MercExtractData& out,
|
||||
u32 tex_offset,
|
||||
tfrag3::MercEffect& eff,
|
||||
int mat_idx,
|
||||
const tfrag3::MercDraw& d_);
|
||||
|
||||
} // namespace gltf_util
|
||||
@@ -91,6 +91,8 @@ def draw_func_ob(self, context):
|
||||
ob = context.object
|
||||
layout.prop(ob, "set_invisible")
|
||||
layout.prop(ob, "enable_custom_weights")
|
||||
layout.prop(ob, "copy_eye_draws")
|
||||
layout.prop(ob, "copy_mod_draws")
|
||||
layout.prop(ob, "set_collision")
|
||||
if (ob.set_collision):
|
||||
layout.prop(ob, "ignore")
|
||||
@@ -118,6 +120,8 @@ def register():
|
||||
bpy.types.Object.set_invisible = bpy.props.BoolProperty(name="Invisible")
|
||||
bpy.types.Object.set_collision = bpy.props.BoolProperty(name="Apply Collision Properties")
|
||||
bpy.types.Object.enable_custom_weights = bpy.props.BoolProperty(name="Use Custom Bone Weights")
|
||||
bpy.types.Object.copy_eye_draws = bpy.props.BoolProperty(name="Copy Eye Draws")
|
||||
bpy.types.Object.copy_mod_draws = bpy.props.BoolProperty(name="Copy Mod Draws")
|
||||
bpy.types.Object.ignore = bpy.props.BoolProperty(name="ignore")
|
||||
bpy.types.Object.noedge = bpy.props.BoolProperty(name="No-Edge")
|
||||
bpy.types.Object.noentity = bpy.props.BoolProperty(name="No-Entity")
|
||||
|
||||
@@ -2603,9 +2603,6 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
|
||||
ASSERT(x->parent_form == m_src);
|
||||
}
|
||||
|
||||
if (auto test0 = m_src->to_string(env) == "(* 0.00024414062 (-> arg0 y))") {
|
||||
printf("");
|
||||
}
|
||||
if (m_src->is_single_element()) {
|
||||
auto src_as_se = dynamic_cast<SimpleExpressionElement*>(m_src->back());
|
||||
if (src_as_se) {
|
||||
|
||||
@@ -113,6 +113,16 @@ void extract_art_groups_from_level(const ObjectFileDB& db,
|
||||
if (db.obj_files_by_dgo.count(dgo_name)) {
|
||||
const auto& files = db.obj_files_by_dgo.at(dgo_name);
|
||||
MercSwapInfo swapped_info;
|
||||
// build list of models to replace
|
||||
auto merc_replacements_path = file_util::get_jak_project_dir() / "custom_assets" /
|
||||
game_version_names[db.version()] / "merc_replacements";
|
||||
if (file_util::file_exists(merc_replacements_path.string())) {
|
||||
auto custom_models =
|
||||
file_util::find_files_in_dir(merc_replacements_path, std::regex(".*\\.glb"));
|
||||
for (auto& mdl : custom_models) {
|
||||
swapped_info.add_to_swap_list(mdl.stem().string());
|
||||
}
|
||||
}
|
||||
for (const auto& file : files) {
|
||||
if (file.name.length() > 3 && !file.name.compare(file.name.length() - 3, 3, "-ag")) {
|
||||
const auto& ag_file = db.lookup_record(file);
|
||||
|
||||
@@ -12,9 +12,14 @@ namespace decompiler {
|
||||
|
||||
// info about what models have been replaced/added per level
|
||||
struct MercSwapInfo {
|
||||
std::vector<std::string> swap_list;
|
||||
std::map<std::string, std::vector<std::string>> per_level_merc_swaps;
|
||||
std::map<std::string, std::vector<std::string>> per_level_custom_mdls;
|
||||
|
||||
bool should_swap(const std::string& model) {
|
||||
return std::find(swap_list.begin(), swap_list.end(), model) != swap_list.end();
|
||||
}
|
||||
|
||||
bool already_swapped(const std::string& model, const std::string& level) {
|
||||
auto mdls_it = per_level_merc_swaps.find(level);
|
||||
if (mdls_it != per_level_merc_swaps.end()) {
|
||||
@@ -35,6 +40,8 @@ struct MercSwapInfo {
|
||||
return false;
|
||||
}
|
||||
|
||||
void add_to_swap_list(const std::string& model) { swap_list.push_back(model); }
|
||||
|
||||
void add_to_swapped_list(const std::string& model, const std::string& level) {
|
||||
per_level_merc_swaps[level].push_back(model);
|
||||
}
|
||||
|
||||
@@ -1624,7 +1624,7 @@ void replace_model(tfrag3::Level& lvl, tfrag3::MercModel& model, const fs::path&
|
||||
}
|
||||
}
|
||||
|
||||
auto swap_info = load_replacement_merc_model(model.name, lvl.merc_data.indices.size(),
|
||||
auto swap_info = load_replacement_merc_model(model, lvl.merc_data.indices.size(),
|
||||
lvl.merc_data.vertices.size(), lvl.textures.size(),
|
||||
mdl_path.string(), old_verts, false);
|
||||
model = swap_info.new_model;
|
||||
@@ -1647,8 +1647,8 @@ void add_custom_model_to_level(tfrag3::Level& lvl,
|
||||
auto lvl_name = lvl.level_name == "" ? "common" : lvl.level_name;
|
||||
lg::info("Adding custom model {} to {}", name, lvl_name);
|
||||
auto merc_data =
|
||||
load_replacement_merc_model(name, lvl.merc_data.indices.size(), lvl.merc_data.vertices.size(),
|
||||
lvl.textures.size(), mdl_path.string(), {}, true);
|
||||
load_custom_merc_model(name, lvl.merc_data.indices.size(), lvl.merc_data.vertices.size(),
|
||||
lvl.textures.size(), mdl_path.string(), {}, true);
|
||||
for (auto& idx : merc_data.new_indices) {
|
||||
lvl.merc_data.indices.push_back(idx);
|
||||
}
|
||||
@@ -1798,23 +1798,25 @@ void extract_merc(const ObjectFileData& ag_data,
|
||||
|
||||
// do model replacement if present
|
||||
for (auto& ctrl : ctrls) {
|
||||
auto merc_replacements_path = file_util::get_jak_project_dir() / "custom_assets" /
|
||||
game_version_names[version] / "merc_replacements";
|
||||
if (!swapped_info.already_swapped(ctrl.name, out.level_name)) {
|
||||
if (file_util::file_exists(merc_replacements_path.string())) {
|
||||
std::string file_name(ctrl.name + ".glb");
|
||||
auto mdl_path = merc_replacements_path / file_name;
|
||||
if (file_util::file_exists(mdl_path.string())) {
|
||||
auto it = std::find_if(out.merc_data.models.begin(), out.merc_data.models.end(),
|
||||
[&](const auto& m) { return m.name == ctrl.name; });
|
||||
if (it != out.merc_data.models.end()) {
|
||||
auto& model = *it;
|
||||
replace_model(out, model, mdl_path);
|
||||
swapped_info.add_to_swapped_list(ctrl.name, out.level_name);
|
||||
if (swapped_info.should_swap(ctrl.name)) {
|
||||
auto merc_replacements_path = file_util::get_jak_project_dir() / "custom_assets" /
|
||||
game_version_names[version] / "merc_replacements";
|
||||
if (!swapped_info.already_swapped(ctrl.name, out.level_name)) {
|
||||
if (file_util::file_exists(merc_replacements_path.string())) {
|
||||
std::string file_name(ctrl.name + ".glb");
|
||||
auto mdl_path = merc_replacements_path / file_name;
|
||||
if (file_util::file_exists(mdl_path.string())) {
|
||||
auto it = std::find_if(out.merc_data.models.begin(), out.merc_data.models.end(),
|
||||
[&](const auto& m) { return m.name == ctrl.name; });
|
||||
if (it != out.merc_data.models.end()) {
|
||||
auto& model = *it;
|
||||
replace_model(out, model, mdl_path);
|
||||
swapped_info.add_to_swapped_list(ctrl.name, out.level_name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lg::info("{} in level {} was already swapped, skipping", ctrl.name, out.level_name);
|
||||
}
|
||||
} else {
|
||||
lg::info("{} in level {} was already swapped, skipping", ctrl.name, out.level_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,149 @@ using namespace gltf_util;
|
||||
|
||||
namespace decompiler {
|
||||
|
||||
void extract(tfrag3::MercModel& mdl,
|
||||
MercExtractData& out,
|
||||
const tinygltf::Model& model,
|
||||
const std::vector<NodeWithTransform>& all_nodes,
|
||||
u32 index_offset,
|
||||
u32 vertex_offset,
|
||||
u32 tex_offset,
|
||||
bool& has_custom_weights) {
|
||||
ASSERT(out.new_vertices.empty());
|
||||
|
||||
std::map<int, tfrag3::MercDraw> draw_by_material;
|
||||
int mesh_count = 0;
|
||||
int prim_count = 0;
|
||||
int joints = 3;
|
||||
auto skin_idx = find_single_skin(model, all_nodes);
|
||||
if (skin_idx) {
|
||||
joints += get_joint_count(model, *skin_idx);
|
||||
}
|
||||
bool copy_eye_draws = false;
|
||||
bool copy_mod_draws = false;
|
||||
|
||||
for (const auto& n : all_nodes) {
|
||||
const auto& node = model.nodes[n.node_idx];
|
||||
if (node.extras.Has("set_invisible") && node.extras.Get("set_invisible").Get<int>()) {
|
||||
continue;
|
||||
}
|
||||
if (node.mesh >= 0) {
|
||||
const auto& mesh = model.meshes[node.mesh];
|
||||
mesh_count++;
|
||||
has_custom_weights = node.extras.Has("enable_custom_weights") &&
|
||||
node.extras.Get("enable_custom_weights").Get<int>();
|
||||
copy_eye_draws =
|
||||
node.extras.Has("copy_eye_draws") && node.extras.Get("copy_eye_draws").Get<int>();
|
||||
copy_mod_draws =
|
||||
node.extras.Has("copy_mod_draws") && node.extras.Get("copy_mod_draws").Get<int>();
|
||||
for (const auto& prim : mesh.primitives) {
|
||||
prim_count++;
|
||||
// extract index buffer
|
||||
std::vector<u32> prim_indices = gltf_util::gltf_index_buffer(
|
||||
model, prim.indices, out.new_vertices.size() + vertex_offset);
|
||||
ASSERT_MSG(prim.mode == TINYGLTF_MODE_TRIANGLES, "Unsupported triangle mode");
|
||||
// extract vertices
|
||||
auto verts =
|
||||
gltf_util::gltf_vertices(model, prim.attributes, n.w_T_node, true, true, mesh.name);
|
||||
out.new_vertices.insert(out.new_vertices.end(), verts.vtx.begin(), verts.vtx.end());
|
||||
out.new_colors.insert(out.new_colors.end(), verts.vtx_colors.begin(),
|
||||
verts.vtx_colors.end());
|
||||
out.normals.insert(out.normals.end(), verts.normals.begin(), verts.normals.end());
|
||||
ASSERT(out.new_colors.size() == out.new_vertices.size());
|
||||
|
||||
if (prim.attributes.count("JOINTS_0") && prim.attributes.count("WEIGHTS_0")) {
|
||||
auto joints_and_weights = gltf_util::extract_and_flatten_joints_and_weights(model, prim);
|
||||
ASSERT(joints_and_weights.size() == verts.vtx.size());
|
||||
out.joints_and_weights.insert(out.joints_and_weights.end(), joints_and_weights.begin(),
|
||||
joints_and_weights.end());
|
||||
} else {
|
||||
// add fake data for vertices without this data
|
||||
gltf_util::JointsAndWeights dummy;
|
||||
dummy.joints[0] = 3;
|
||||
dummy.weights[0] = 1.f;
|
||||
for (size_t i = 0; i < out.new_vertices.size(); i++) {
|
||||
out.joints_and_weights.push_back(dummy);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: just putting it all in one material
|
||||
auto& draw = draw_by_material[prim.material];
|
||||
draw.mode = gltf_util::make_default_draw_mode(); // todo rm
|
||||
draw.tree_tex_id = 0; // todo rm
|
||||
draw.num_triangles += prim_indices.size() / 3;
|
||||
draw.no_strip = true;
|
||||
draw.index_count = prim_indices.size();
|
||||
draw.first_index = index_offset + out.new_indices.size();
|
||||
|
||||
out.new_indices.insert(out.new_indices.end(), prim_indices.begin(), prim_indices.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tfrag3::MercEffect e;
|
||||
tfrag3::MercEffect envmap_eff;
|
||||
envmap_eff.has_envmap = false;
|
||||
out.new_model.name = mdl.name;
|
||||
// if we have a skeleton, use that joint count, otherwise use a high default value since the model
|
||||
// we replace can have more
|
||||
out.new_model.max_bones = joints != 3 ? joints : 100;
|
||||
out.new_model.max_draws = 0;
|
||||
|
||||
for (const auto& [mat_idx, d_] : draw_by_material) {
|
||||
const auto& mat = model.materials[mat_idx];
|
||||
if (mat_idx < 0 || !gltf_util::material_has_envmap(model.materials[mat_idx]) ||
|
||||
!gltf_util::envmap_is_valid(model.materials[mat_idx])) {
|
||||
gltf_util::process_normal_merc_draw(model, out, tex_offset, e, mat_idx, d_);
|
||||
} else {
|
||||
envmap_eff.has_envmap = true;
|
||||
gltf_util::process_envmap_merc_draw(model, out, tex_offset, envmap_eff, mat_idx, d_);
|
||||
}
|
||||
}
|
||||
|
||||
// in case a model only has envmap draws, we don't push the normal merc effect
|
||||
if (!e.all_draws.empty()) {
|
||||
out.new_model.effects.push_back(e);
|
||||
}
|
||||
if (envmap_eff.has_envmap) {
|
||||
out.new_model.effects.push_back(envmap_eff);
|
||||
}
|
||||
|
||||
// copy any effects from the old model that used mod or eye draws
|
||||
if (copy_eye_draws || copy_mod_draws) {
|
||||
for (auto& old_eff : mdl.effects) {
|
||||
tfrag3::MercEffect eff;
|
||||
bool has_eye_draw = false;
|
||||
if (copy_eye_draws) {
|
||||
for (auto& draw : old_eff.all_draws) {
|
||||
if (draw.eye_id != 0xff) {
|
||||
has_eye_draw = true;
|
||||
eff.all_draws.push_back(draw);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (copy_mod_draws && old_eff.has_mod_draw) {
|
||||
eff.has_mod_draw = true;
|
||||
eff.mod = old_eff.mod;
|
||||
eff.mod.fix_draw.clear();
|
||||
}
|
||||
if ((copy_eye_draws || copy_mod_draws) && (eff.has_mod_draw || has_eye_draw)) {
|
||||
lg::info("adding old effect for {} (mod draw {}, eye draw {})", mdl.name,
|
||||
old_eff.has_mod_draw, has_eye_draw);
|
||||
out.new_model.effects.push_back(eff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& effect : out.new_model.effects) {
|
||||
out.new_model.max_draws += effect.all_draws.size();
|
||||
}
|
||||
|
||||
lg::info("total of {} unique materials ({} normal, {} envmap)", out.new_model.max_draws,
|
||||
e.all_draws.size(), envmap_eff.all_draws.size());
|
||||
lg::info("Merged {} meshes and {} prims into {} vertices", mesh_count, prim_count,
|
||||
out.new_vertices.size());
|
||||
}
|
||||
|
||||
void extract(const std::string& name,
|
||||
MercExtractData& out,
|
||||
const tinygltf::Model& model,
|
||||
@@ -86,88 +229,14 @@ void extract(const std::string& name,
|
||||
out.new_model.max_bones = joints != 3 ? joints : 100;
|
||||
out.new_model.max_draws = 0;
|
||||
|
||||
auto process_normal_draw = [&](tfrag3::MercEffect& eff, int mat_idx, const tfrag3::MercDraw& d_) {
|
||||
const auto& mat = model.materials[mat_idx];
|
||||
eff.all_draws.push_back(d_);
|
||||
auto& draw = eff.all_draws.back();
|
||||
draw.mode = gltf_util::make_default_draw_mode();
|
||||
|
||||
if (mat_idx == -1) {
|
||||
lg::warn("Draw had a material index of -1, using default texture.");
|
||||
draw.tree_tex_id = 0;
|
||||
return;
|
||||
}
|
||||
int tex_idx = mat.pbrMetallicRoughness.baseColorTexture.index;
|
||||
if (tex_idx == -1) {
|
||||
lg::warn("Material {} has no texture, using default texture.", mat.name);
|
||||
draw.tree_tex_id = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& tex = model.textures[tex_idx];
|
||||
ASSERT(tex.sampler >= 0);
|
||||
ASSERT(tex.source >= 0);
|
||||
gltf_util::setup_draw_mode_from_sampler(model.samplers.at(tex.sampler), &draw.mode);
|
||||
gltf_util::setup_alpha_from_material(mat, &draw.mode);
|
||||
|
||||
const auto& img = model.images[tex.source];
|
||||
draw.tree_tex_id = tex_offset + texture_pool_add_texture(&out.tex_pool, img);
|
||||
};
|
||||
|
||||
auto process_envmap_draw = [&](tfrag3::MercEffect& eff, int mat_idx, const tfrag3::MercDraw& d_) {
|
||||
const auto& mat = model.materials[mat_idx];
|
||||
eff.all_draws.push_back(d_);
|
||||
auto& draw = eff.all_draws.back();
|
||||
draw.mode = gltf_util::make_default_draw_mode();
|
||||
|
||||
if (mat_idx == -1) {
|
||||
lg::warn("Envmap draw had a material index of -1, using default texture.");
|
||||
draw.tree_tex_id = texture_pool_debug_checker(&out.tex_pool);
|
||||
return;
|
||||
}
|
||||
int base_tex_idx = mat.pbrMetallicRoughness.baseColorTexture.index;
|
||||
if (base_tex_idx == -1) {
|
||||
lg::warn("Envmap material {} has no texture, using default texture.", mat.name);
|
||||
draw.tree_tex_id = texture_pool_debug_checker(&out.tex_pool);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& base_tex = model.textures[base_tex_idx];
|
||||
ASSERT(base_tex.sampler >= 0);
|
||||
ASSERT(base_tex.source >= 0);
|
||||
gltf_util::setup_draw_mode_from_sampler(model.samplers.at(base_tex.sampler), &draw.mode);
|
||||
gltf_util::setup_alpha_from_material(mat, &draw.mode);
|
||||
const auto& roughness_tex =
|
||||
model.textures.at(mat.pbrMetallicRoughness.metallicRoughnessTexture.index);
|
||||
ASSERT(roughness_tex.sampler >= 0);
|
||||
ASSERT(roughness_tex.source >= 0);
|
||||
|
||||
draw.tree_tex_id =
|
||||
tex_offset + gltf_util::texture_pool_add_envmap_control_texture(
|
||||
&out.tex_pool, model, base_tex.source, roughness_tex.source,
|
||||
!draw.mode.get_clamp_s_enable(), !draw.mode.get_clamp_t_enable());
|
||||
|
||||
// now, setup envmap draw:
|
||||
auto envmap_settings = gltf_util::envmap_settings_from_gltf(mat);
|
||||
const auto& envmap_tex = model.textures[envmap_settings.texture_idx];
|
||||
ASSERT(envmap_tex.sampler >= 0);
|
||||
ASSERT(envmap_tex.source >= 0);
|
||||
auto env_mode = gltf_util::make_default_draw_mode();
|
||||
gltf_util::setup_draw_mode_from_sampler(model.samplers.at(envmap_tex.sampler), &env_mode);
|
||||
eff.envmap_texture = tex_offset + gltf_util::texture_pool_add_texture(
|
||||
&out.tex_pool, model.images[envmap_tex.source]);
|
||||
env_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_0_DST_DST);
|
||||
env_mode.enable_ab();
|
||||
eff.envmap_mode = env_mode;
|
||||
};
|
||||
|
||||
for (const auto& [mat_idx, d_] : draw_by_material) {
|
||||
const auto& mat = model.materials[mat_idx];
|
||||
if (!material_has_envmap(mat) || !envmap_is_valid(mat)) {
|
||||
process_normal_draw(e, mat_idx, d_);
|
||||
if (mat_idx < 0 || !gltf_util::material_has_envmap(model.materials[mat_idx]) ||
|
||||
!gltf_util::envmap_is_valid(model.materials[mat_idx])) {
|
||||
gltf_util::process_normal_merc_draw(model, out, tex_offset, e, mat_idx, d_);
|
||||
} else {
|
||||
envmap_eff.has_envmap = true;
|
||||
process_envmap_draw(envmap_eff, mat_idx, d_);
|
||||
gltf_util::process_envmap_merc_draw(model, out, tex_offset, envmap_eff, mat_idx, d_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,7 +354,7 @@ void merc_convert_custom(MercSwapData& out, const MercExtractData& in) {
|
||||
}
|
||||
}
|
||||
|
||||
MercSwapData load_replacement_merc_model(const std::string& name,
|
||||
MercSwapData load_replacement_merc_model(tfrag3::MercModel& mdl,
|
||||
u32 current_idx_count,
|
||||
u32 current_vtx_count,
|
||||
u32 current_tex_count,
|
||||
@@ -303,6 +372,37 @@ MercSwapData load_replacement_merc_model(const std::string& name,
|
||||
ASSERT_MSG(res, "Failed to load GLTF file!");
|
||||
auto all_nodes = flatten_nodes_from_all_scenes(model);
|
||||
|
||||
MercExtractData extract_data;
|
||||
auto has_custom_weights = false;
|
||||
extract(mdl, extract_data, model, all_nodes, current_idx_count, current_vtx_count,
|
||||
current_tex_count, has_custom_weights);
|
||||
if (custom_mdl) {
|
||||
merc_convert_custom(result, extract_data);
|
||||
} else {
|
||||
merc_convert_replacement(result, extract_data, old_verts, has_custom_weights);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
MercSwapData load_custom_merc_model(const std::string& name,
|
||||
u32 current_idx_count,
|
||||
u32 current_vtx_count,
|
||||
u32 current_tex_count,
|
||||
const std::string& path,
|
||||
const std::vector<tfrag3::MercVertex>& old_verts,
|
||||
bool custom_mdl) {
|
||||
MercSwapData result;
|
||||
lg::info("Reading gltf mesh: {}", path);
|
||||
tinygltf::TinyGLTF loader;
|
||||
tinygltf::Model model;
|
||||
std::string err, warn;
|
||||
bool res = loader.LoadBinaryFromFile(&model, &err, &warn, path);
|
||||
ASSERT_MSG(warn.empty(), warn.c_str());
|
||||
ASSERT_MSG(err.empty(), err.c_str());
|
||||
ASSERT_MSG(res, "Failed to load GLTF file!");
|
||||
auto all_nodes = flatten_nodes_from_all_scenes(model);
|
||||
|
||||
MercExtractData extract_data;
|
||||
auto has_custom_weights = false;
|
||||
extract(name, extract_data, model, all_nodes, current_idx_count, current_vtx_count,
|
||||
|
||||
@@ -4,29 +4,21 @@
|
||||
#include "common/util/gltf_util.h"
|
||||
|
||||
namespace decompiler {
|
||||
struct MercExtractData {
|
||||
gltf_util::TexturePool tex_pool;
|
||||
std::vector<u32> new_indices;
|
||||
std::vector<tfrag3::PreloadedVertex> new_vertices;
|
||||
std::vector<math::Vector<u8, 4>> new_colors;
|
||||
std::vector<math::Vector3f> normals;
|
||||
std::vector<gltf_util::JointsAndWeights> joints_and_weights;
|
||||
tfrag3::MercModel new_model;
|
||||
};
|
||||
|
||||
// Data produced by loading a replacement model
|
||||
struct MercSwapData {
|
||||
std::vector<u32> new_indices;
|
||||
std::vector<tfrag3::MercVertex> new_vertices;
|
||||
std::vector<tfrag3::Texture> new_textures;
|
||||
tfrag3::MercModel new_model;
|
||||
};
|
||||
gltf_util::MercSwapData load_replacement_merc_model(
|
||||
tfrag3::MercModel& mdl,
|
||||
u32 current_idx_count,
|
||||
u32 current_vtx_count,
|
||||
u32 current_tex_count,
|
||||
const std::string& path,
|
||||
const std::vector<tfrag3::MercVertex>& old_verts,
|
||||
bool custom_mdl);
|
||||
|
||||
MercSwapData load_replacement_merc_model(const std::string& name,
|
||||
u32 current_idx_count,
|
||||
u32 current_vtx_count,
|
||||
u32 current_tex_count,
|
||||
const std::string& path,
|
||||
const std::vector<tfrag3::MercVertex>& old_verts,
|
||||
bool custom_mdl);
|
||||
gltf_util::MercSwapData load_custom_merc_model(const std::string& name,
|
||||
u32 current_idx_count,
|
||||
u32 current_vtx_count,
|
||||
u32 current_tex_count,
|
||||
const std::string& path,
|
||||
const std::vector<tfrag3::MercVertex>& old_verts,
|
||||
bool custom_mdl);
|
||||
} // namespace decompiler
|
||||
@@ -538,8 +538,6 @@ void Merc2::handle_pc_model(const DmaTransfer& setup,
|
||||
auto* flags = (const PcMercFlags*)input_data;
|
||||
int num_effects = flags->effect_count; // mostly just a sanity check
|
||||
ASSERT(num_effects < kMaxEffect);
|
||||
// hack for custom models to disable blerc/mod draws
|
||||
bool is_custom_model = model->effects.at(0).all_draws.at(0).no_strip;
|
||||
u64 current_ignore_alpha_bits = flags->ignore_alpha_mask; // shader settings
|
||||
u64 current_effect_enable_bits = flags->enable_mask; // mask for game to disable an effect
|
||||
bool model_uses_mod = flags->bitflags & 1; // if we should update vertices from game.
|
||||
@@ -566,11 +564,18 @@ void Merc2::handle_pc_model(const DmaTransfer& setup,
|
||||
|
||||
// Next is pointers to merc data, needed so we can update vertices
|
||||
|
||||
// custom models are likely to have a different number of effects than what GOAL reports, update
|
||||
// the count here (after reading DMA) so we don't potentially go out of bounds when we do
|
||||
// blerc/mod draws
|
||||
if (model->effects.at(0).all_draws.at(0).no_strip) {
|
||||
num_effects = model->effects.size();
|
||||
}
|
||||
|
||||
// will hold opengl buffers for the updated vertices
|
||||
ModBuffers mod_opengl_buffers[kMaxEffect];
|
||||
if (model_uses_pc_blerc && !is_custom_model) {
|
||||
if (model_uses_pc_blerc) {
|
||||
model_mod_blerc_draws(num_effects, model, lev, mod_opengl_buffers, blerc_weights, stats);
|
||||
} else if (model_uses_mod && !is_custom_model) { // only if we've enabled, this path is slow.
|
||||
} else if (model_uses_mod) { // only if we've enabled, this path is slow.
|
||||
model_mod_draws(num_effects, model, lev, input_data, setup, mod_opengl_buffers, stats);
|
||||
}
|
||||
|
||||
@@ -650,8 +655,7 @@ void Merc2::handle_pc_model(const DmaTransfer& setup,
|
||||
auto& effect = model->effects[ei];
|
||||
|
||||
bool should_envmap = effect.has_envmap && !model_disables_envmap;
|
||||
bool should_mod =
|
||||
!is_custom_model && ((model_uses_pc_blerc || model_uses_mod) && effect.has_mod_draw);
|
||||
bool should_mod = (model_uses_pc_blerc || model_uses_mod) && effect.has_mod_draw;
|
||||
|
||||
if (should_mod) {
|
||||
// draw as two parts, fixed and mod
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "goalc/build_level/common/gltf_mesh_extract.h"
|
||||
|
||||
void extract(const std::string& name,
|
||||
MercExtractData& out,
|
||||
gltf_util::MercExtractData& out,
|
||||
const tinygltf::Model& model,
|
||||
const std::vector<gltf_util::NodeWithTransform>& all_nodes,
|
||||
u32 index_offset,
|
||||
@@ -96,89 +96,14 @@ void extract(const std::string& name,
|
||||
out.new_model.max_bones = joints;
|
||||
out.new_model.max_draws = 0;
|
||||
|
||||
auto process_normal_draw = [&](tfrag3::MercEffect& eff, int mat_idx, const tfrag3::MercDraw& d_) {
|
||||
eff.all_draws.push_back(d_);
|
||||
auto& draw = eff.all_draws.back();
|
||||
draw.mode = gltf_util::make_default_draw_mode();
|
||||
|
||||
if (mat_idx == -1) {
|
||||
lg::warn("Draw had a material index of -1, using default texture.");
|
||||
draw.tree_tex_id = 0;
|
||||
return;
|
||||
}
|
||||
const auto& mat = model.materials[mat_idx];
|
||||
|
||||
int tex_idx = mat.pbrMetallicRoughness.baseColorTexture.index;
|
||||
if (tex_idx == -1) {
|
||||
lg::warn("Material {} has no texture, using default texture.", mat.name);
|
||||
draw.tree_tex_id = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& tex = model.textures[tex_idx];
|
||||
ASSERT(tex.sampler >= 0);
|
||||
ASSERT(tex.source >= 0);
|
||||
gltf_util::setup_draw_mode_from_sampler(model.samplers.at(tex.sampler), &draw.mode);
|
||||
gltf_util::setup_alpha_from_material(mat, &draw.mode);
|
||||
|
||||
const auto& img = model.images[tex.source];
|
||||
draw.tree_tex_id = tex_offset + texture_pool_add_texture(&out.tex_pool, img);
|
||||
};
|
||||
|
||||
auto process_envmap_draw = [&](tfrag3::MercEffect& eff, int mat_idx, const tfrag3::MercDraw& d_) {
|
||||
const auto& mat = model.materials[mat_idx];
|
||||
eff.all_draws.push_back(d_);
|
||||
auto& draw = eff.all_draws.back();
|
||||
draw.mode = gltf_util::make_default_draw_mode();
|
||||
|
||||
if (mat_idx == -1) {
|
||||
lg::warn("Envmap draw had a material index of -1, using default texture.");
|
||||
draw.tree_tex_id = texture_pool_debug_checker(&out.tex_pool);
|
||||
return;
|
||||
}
|
||||
int base_tex_idx = mat.pbrMetallicRoughness.baseColorTexture.index;
|
||||
if (base_tex_idx == -1) {
|
||||
lg::warn("Envmap material {} has no texture, using default texture.", mat.name);
|
||||
draw.tree_tex_id = texture_pool_debug_checker(&out.tex_pool);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& base_tex = model.textures[base_tex_idx];
|
||||
ASSERT(base_tex.sampler >= 0);
|
||||
ASSERT(base_tex.source >= 0);
|
||||
gltf_util::setup_draw_mode_from_sampler(model.samplers.at(base_tex.sampler), &draw.mode);
|
||||
gltf_util::setup_alpha_from_material(mat, &draw.mode);
|
||||
const auto& roughness_tex =
|
||||
model.textures.at(mat.pbrMetallicRoughness.metallicRoughnessTexture.index);
|
||||
ASSERT(roughness_tex.sampler >= 0);
|
||||
ASSERT(roughness_tex.source >= 0);
|
||||
|
||||
draw.tree_tex_id =
|
||||
tex_offset + gltf_util::texture_pool_add_envmap_control_texture(
|
||||
&out.tex_pool, model, base_tex.source, roughness_tex.source,
|
||||
!draw.mode.get_clamp_s_enable(), !draw.mode.get_clamp_t_enable());
|
||||
|
||||
// now, setup envmap draw:
|
||||
auto envmap_settings = gltf_util::envmap_settings_from_gltf(mat);
|
||||
const auto& envmap_tex = model.textures[envmap_settings.texture_idx];
|
||||
ASSERT(envmap_tex.sampler >= 0);
|
||||
ASSERT(envmap_tex.source >= 0);
|
||||
auto env_mode = gltf_util::make_default_draw_mode();
|
||||
gltf_util::setup_draw_mode_from_sampler(model.samplers.at(envmap_tex.sampler), &env_mode);
|
||||
eff.envmap_texture = tex_offset + gltf_util::texture_pool_add_texture(
|
||||
&out.tex_pool, model.images[envmap_tex.source]);
|
||||
env_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_0_DST_DST);
|
||||
env_mode.enable_ab();
|
||||
eff.envmap_mode = env_mode;
|
||||
};
|
||||
|
||||
for (const auto& [mat_idx, d_] : draw_by_material) {
|
||||
const auto& mat = model.materials[mat_idx];
|
||||
if (mat_idx < 0 || !gltf_util::material_has_envmap(model.materials[mat_idx]) ||
|
||||
!gltf_util::envmap_is_valid(model.materials[mat_idx])) {
|
||||
process_normal_draw(e, mat_idx, d_);
|
||||
gltf_util::process_normal_merc_draw(model, out, tex_offset, e, mat_idx, d_);
|
||||
} else {
|
||||
envmap_eff.has_envmap = true;
|
||||
process_envmap_draw(envmap_eff, mat_idx, d_);
|
||||
gltf_util::process_envmap_merc_draw(model, out, tex_offset, envmap_eff, mat_idx, d_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,7 +125,7 @@ void extract(const std::string& name,
|
||||
out.new_vertices.size());
|
||||
}
|
||||
|
||||
void merc_convert(MercSwapData& out, const MercExtractData& in) {
|
||||
void merc_convert(gltf_util::MercSwapData& out, const gltf_util::MercExtractData& in) {
|
||||
// easy
|
||||
out.new_model = in.new_model;
|
||||
out.new_indices = in.new_indices;
|
||||
@@ -231,12 +156,12 @@ void merc_convert(MercSwapData& out, const MercExtractData& in) {
|
||||
}
|
||||
}
|
||||
|
||||
MercSwapData load_merc_model(u32 current_idx_count,
|
||||
u32 current_vtx_count,
|
||||
u32 current_tex_count,
|
||||
const std::string& path,
|
||||
const std::string& name) {
|
||||
MercSwapData result;
|
||||
gltf_util::MercSwapData load_merc_model(u32 current_idx_count,
|
||||
u32 current_vtx_count,
|
||||
u32 current_tex_count,
|
||||
const std::string& path,
|
||||
const std::string& name) {
|
||||
gltf_util::MercSwapData result;
|
||||
lg::info("Reading gltf mesh: {}", path);
|
||||
tinygltf::TinyGLTF loader;
|
||||
tinygltf::Model model;
|
||||
@@ -247,7 +172,7 @@ MercSwapData load_merc_model(u32 current_idx_count,
|
||||
ASSERT_MSG(res, "Failed to load GLTF file!");
|
||||
auto all_nodes = gltf_util::flatten_nodes_from_all_scenes(model);
|
||||
|
||||
MercExtractData extract_data;
|
||||
gltf_util::MercExtractData extract_data;
|
||||
extract(name, extract_data, model, all_nodes, current_idx_count, current_vtx_count,
|
||||
current_tex_count);
|
||||
merc_convert(result, extract_data);
|
||||
|
||||
@@ -4,37 +4,19 @@
|
||||
|
||||
#include "goalc/build_actor/jak1/build_actor.h"
|
||||
|
||||
struct MercExtractData {
|
||||
gltf_util::TexturePool tex_pool;
|
||||
std::vector<u32> new_indices;
|
||||
std::vector<tfrag3::PreloadedVertex> new_vertices;
|
||||
std::vector<math::Vector<u8, 4>> new_colors;
|
||||
std::vector<math::Vector3f> normals;
|
||||
std::vector<gltf_util::JointsAndWeights> joints_and_weights;
|
||||
tfrag3::MercModel new_model;
|
||||
};
|
||||
|
||||
// Data produced by loading a replacement model
|
||||
struct MercSwapData {
|
||||
std::vector<u32> new_indices;
|
||||
std::vector<tfrag3::MercVertex> new_vertices;
|
||||
std::vector<tfrag3::Texture> new_textures;
|
||||
tfrag3::MercModel new_model;
|
||||
};
|
||||
|
||||
void extract(const std::string& name,
|
||||
MercExtractData& out,
|
||||
gltf_util::MercExtractData& out,
|
||||
const tinygltf::Model& model,
|
||||
const std::vector<gltf_util::NodeWithTransform>& all_nodes,
|
||||
u32 index_offset,
|
||||
u32 vertex_offset,
|
||||
u32 tex_offset);
|
||||
void merc_convert(MercSwapData& out, const MercExtractData& in);
|
||||
MercSwapData load_merc_model(u32 current_idx_count,
|
||||
u32 current_vtx_count,
|
||||
u32 current_tex_count,
|
||||
const std::string& path,
|
||||
const std::string& name);
|
||||
void merc_convert(gltf_util::MercSwapData& out, const gltf_util::MercExtractData& in);
|
||||
gltf_util::MercSwapData load_merc_model(u32 current_idx_count,
|
||||
u32 current_vtx_count,
|
||||
u32 current_tex_count,
|
||||
const std::string& path,
|
||||
const std::string& name);
|
||||
std::vector<jak1::CollideMesh> gen_collide_mesh_from_model(
|
||||
const tinygltf::Model& model,
|
||||
const std::vector<gltf_util::NodeWithTransform>& all_nodes,
|
||||
|
||||
Reference in New Issue
Block a user