#pragma once // gr2_bridge — libgr2 POD views -> Godot scene objects. // // Coordinate handling (the one place it lives; see docs/GODOT-POC-PLAN.md §02): // - gr2 Mat4 is row-major, row-vector math, translation in elements 12..14. // - A plain 4x4 transpose maps it to a Godot Transform3D (column-vector, // translation in .origin). gr2_to_godot() does exactly that. // - Z-up(cm) -> Y-up(m) and optional handedness flip are NOT applied here; // they go on the Metin2Model node transform (make_conv()). #include #include #include #include #include #include namespace godot { class Skeleton3D; class Skin; class ArrayMesh; } // namespace godot namespace mtgodot { // 4x4 transpose: gr2 row-major/row-vector -> Godot Transform3D. godot::Transform3D gr2_to_godot(const gr2::Mat4 &m); // gr2 affine compose (row-vector: result applies A then B), same as libgr2's // internal mul4x3. R = A · B with the 4th row treated as translation. gr2::Mat4 mul4x3(const gr2::Mat4 &A, const gr2::Mat4 &B); // Z-up cm -> Y-up m (+ optional Z flip for LH->RH content). godot::Transform3D make_conv(float unit_scale, bool flip_z); // Build a Skeleton3D (rest pose from bone local transforms; initial_placement // folded into root bones). Returns nullptr if the skeleton has no bones. godot::Skeleton3D *build_skeleton(const gr2::Skeleton &sk); // One render part = one Godot surface. A gr2 mesh with N>1 tri_groups splits into // N parts (each its own material); a mesh with 0/1 groups is one whole-mesh part. struct RenderPart { int mesh = -1; // gr2::FileInfo::meshes index int group = -1; // gr2::Mesh::tri_groups index, or -1 = whole mesh int mat_index = -1; // tri_groups[group].material_index (mesh-local), or -1 uint32_t idx_first = 0; // start into mesh.indices (= tri_first * 3) uint32_t idx_count = 0; // length into mesh.indices (= tri_count * 3) }; std::vector build_parts(const gr2::FileInfo &fi); // Skin whose bind list is parallel to the skeleton bones: // bind i -> bone i, pose = gr2_to_godot(bone[i].inverse_world) godot::Ref build_skin(const gr2::Skeleton &sk); // One ArrayMesh with a surface per RenderPart (see build_parts). // ARRAY_BONES values are skeleton bone indices (mesh slot -> bone via // mesh.bone_bindings). Rigid meshes are bound rigidly to bone_bindings[0]. // Fills out_bounds with the untransformed vertex AABB. godot::Ref build_mesh(const gr2::FileInfo &fi, const std::vector &parts, bool flip_winding, godot::AABB &out_bounds); } // namespace mtgodot