diff --git a/extension/src/metin2_model.cpp b/extension/src/metin2_model.cpp index d55936bd..949f3f1d 100644 --- a/extension/src/metin2_model.cpp +++ b/extension/src/metin2_model.cpp @@ -43,6 +43,8 @@ void Metin2Model::_bind_methods() { ClassDB::bind_method(D_METHOD("get_flip_winding"), &Metin2Model::get_flip_winding); ClassDB::bind_method(D_METHOD("set_material_mode", "m"), &Metin2Model::set_material_mode); ClassDB::bind_method(D_METHOD("get_material_mode"), &Metin2Model::get_material_mode); + ClassDB::bind_method(D_METHOD("set_use_gr2_materials", "v"), &Metin2Model::set_use_gr2_materials); + ClassDB::bind_method(D_METHOD("get_use_gr2_materials"), &Metin2Model::get_use_gr2_materials); ClassDB::bind_method(D_METHOD("set_surface_texture", "surface", "path"), &Metin2Model::set_surface_texture); ClassDB::bind_method(D_METHOD("reload"), &Metin2Model::reload); ClassDB::bind_method(D_METHOD("get_info"), &Metin2Model::get_info); @@ -58,6 +60,8 @@ void Metin2Model::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_winding"), "set_flip_winding", "get_flip_winding"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "material_mode", PROPERTY_HINT_ENUM, "metin2,standard"), "set_material_mode", "get_material_mode"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_gr2_materials"), + "set_use_gr2_materials", "get_use_gr2_materials"); } void Metin2Model::set_material_mode(const String &m) { @@ -67,6 +71,13 @@ void Metin2Model::set_material_mode(const String &m) { } } +void Metin2Model::set_use_gr2_materials(bool v) { + use_gr2_materials = v; + if (is_inside_tree()) { + _apply_materials(); + } +} + void Metin2Model::set_surface_texture(int surface, const String &path) { if (surface < 0) { return; @@ -178,12 +189,24 @@ void Metin2Model::reload() { mi->set_custom_aabb(bounds.grow(0.01)); } + materials = gr2::dump_materials(**file); + _apply_materials(); int vtot = 0; for (const auto &m : fi.meshes) { vtot += (int)m.vertices.size(); } + { + int with_tex = 0; + for (const auto &mm : materials) { + if (!mm.diffuse_texture.empty()) { + ++with_tex; + } + } + UtilityFunctions::print(vformat("[Metin2Model] gr2 materials: %d (%d with diffuse name)", + (int)materials.size(), with_tex)); + } last_info = vformat("gr2 v%d | bones=%d meshes=%d surfaces=%d verts=%d | bounds=%s", (int)(*file)->format_version(), sk ? (int)sk->bones.size() : 0, @@ -327,14 +350,56 @@ void Metin2Model::_apply_materials() { } } + // Surface s corresponds to the s-th gr2 mesh that has geometry (same skip + // rule as build_mesh). Recover that mapping to reach tri_groups/material_index. + const gr2::FileInfo &fi = (*file)->file_info(); + std::vector surf_to_mesh; + for (int mi_ = 0; mi_ < (int)fi.meshes.size(); ++mi_) { + if (!fi.meshes[mi_].vertices.empty() && !fi.meshes[mi_].indices.empty()) { + surf_to_mesh.push_back(mi_); + } + } + Ref mesh = mi->get_mesh(); int textured = 0; for (int s = 0; s < mesh->get_surface_count(); ++s) { const String sname = mesh->surface_get_name(s); Ref tex; + auto mat_texture_name = [&]() -> String { + if (s >= (int)surf_to_mesh.size()) { + return String(); + } + const gr2::Mesh &gm = fi.meshes[surf_to_mesh[s]]; + int matidx = gm.tri_groups.empty() ? -1 : gm.tri_groups[0].material_index; + if (matidx < 0 || matidx >= (int)materials.size() || + materials[matidx].diffuse_texture.empty()) { + return String(); + } + return String(materials[matidx].diffuse_texture.c_str()) + .replace("\\", "/") + .get_file() + .get_basename() + .to_lower(); + }; + if (s < surface_tex_override.size() && !String(surface_tex_override[s]).is_empty()) { tex = _load_dds(surface_tex_override[s]); - } else { + } + // gr2 material name -> texture, only when opted in (unverified vs oracle; + // see GODOT-POC-PLAN.md §M2.5 T2.5.6). + if (tex.is_null() && use_gr2_materials) { + String want = mat_texture_name(); + if (!want.is_empty()) { + for (int i = 0; i < dds_files.size(); ++i) { + if (dds_files[i].get_basename().to_lower() == want) { + tex = _load_dds(dir.path_join(dds_files[i])); + break; + } + } + } + } + // filename-convention resolution (default path) + if (tex.is_null()) { tex = _resolve_texture(dir, stem, sname, dds_files); } if (tex.is_valid()) { diff --git a/extension/src/metin2_model.h b/extension/src/metin2_model.h index 026be84f..83f303e2 100644 --- a/extension/src/metin2_model.h +++ b/extension/src/metin2_model.h @@ -11,6 +11,7 @@ #include #include +#include namespace godot { class Skeleton3D; @@ -54,6 +55,9 @@ public: void set_material_mode(const godot::String &m); godot::String get_material_mode() const { return material_mode; } + void set_use_gr2_materials(bool v); + bool get_use_gr2_materials() const { return use_gr2_materials; } + // Explicit per-surface texture path override (index -> absolute .dds path). void set_surface_texture(int surface, const godot::String &path); @@ -81,9 +85,11 @@ private: bool flip_winding = false; godot::String material_mode = "metin2"; // "metin2" (ShaderMaterial) | "standard" + bool use_gr2_materials = false; // drive textures from gr2 material names (unverified) godot::PackedStringArray surface_tex_override; std::shared_ptr> file; // shared_ptr so accessor stays valid + std::vector materials; godot::Skeleton3D *skel = nullptr; godot::MeshInstance3D *mi = nullptr; godot::String last_info; diff --git a/test/golden/m25-assassin.png b/test/golden/m25-assassin.png index a7145f0e..1642a321 100644 Binary files a/test/golden/m25-assassin.png and b/test/golden/m25-assassin.png differ diff --git a/test/golden/m25-shaman.png b/test/golden/m25-shaman.png index cea431dc..5186a13f 100644 Binary files a/test/golden/m25-shaman.png and b/test/golden/m25-shaman.png differ diff --git a/test/golden/m25-warrior-shader.png b/test/golden/m25-warrior-shader.png index 133234cf..2197300f 100644 Binary files a/test/golden/m25-warrior-shader.png and b/test/golden/m25-warrior-shader.png differ diff --git a/test/golden/m2c-t2.0.png b/test/golden/m2c-t2.0.png deleted file mode 100644 index 2311d5ef..00000000 Binary files a/test/golden/m2c-t2.0.png and /dev/null differ diff --git a/test/golden/m2c-t23.0.png b/test/golden/m2c-t23.0.png deleted file mode 100644 index ed4bd4ad..00000000 Binary files a/test/golden/m2c-t23.0.png and /dev/null differ