Files
mtgodot-poc/libgr2/src/internal.h
T
shenleiandClaude Opus 5.5 668f48d6ec port 2V2-d.2: Granny runtime on libgr2, main character model animates
Implement the Granny SDK 2.11 API the client uses on top of libgr2
(platform/EterGrnLib/GrannyRuntime.cpp, shim granny.h declared from the
SDK header): file sections, type-definition vertex conversion, material
textures by Usage, mesh/bone bindings, deformer, control clock/loop/ease
and weighted SRT sampling. Port EterGrnLib (LODController, Material, Mesh,
Model, ModelInstance*, Motion, Thing, ThingInstance, Util) plus EterLib
GrpObjectInstance/GrpCollisionObject/CollisionData verbatim and drop their
platform skeletons and pending stand-ins; register the gr2 resource
factory; vertex/index buffers are CPU-side until the 2V2-e render adapter.

app.UpdateGame/RenderGame now run 40250's bodies, reaching the
CPythonApplication members through their singletons (the platform has no
app object); CPythonGraphic joins GameSingletons in member order, and
GetMousePosition reads the host cursor.

port.login_flow asserts the main instance's PART_MAIN model has meshes,
its diffuse image loaded and the WAIT motion moves the bones between
frames; offline and live pass, port_gate macos PASS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 19:43:27 +09:00

145 lines
6.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// libgr2 内部。SDK struct 镜像从 granny_file_format.h / granny_data_type_definition.h 抄。
#pragma once
#include "gr2/gr2.h"
#include <cstdint>
#include <string>
#include <unordered_map>
#include <vector>
namespace gr2 {
namespace detail {
// ── granny_file_format.h 镜像 ──────────────────────────────────────────
#pragma pack(push, 1)
struct GrnFileMagic { // grn_file_magic_value
uint32_t magic[4];
uint32_t header_size;
uint32_t header_format;
uint32_t reserved[2];
};
struct GrnReference { uint32_t section; uint32_t offset; };
struct GrnPointerFixup { uint32_t from_offset; GrnReference to; }; // 12B
struct GrnSection { // grn_section —— 44B
uint32_t compression;
uint32_t data_offset, data_size;
uint32_t expanded_data_size;
uint32_t internal_alignment;
uint32_t first16bit, first8bit;
uint32_t pointer_fixup_off, pointer_fixup_count;
uint32_t mixed_fixup_off, mixed_fixup_count;
};
#pragma pack(pop)
struct Section {
std::vector<uint8_t> data; // 展开后
SectionInfo info;
};
// section 内的位置。不物化指针(文件是 32 位指针,本进程 64 位),
// 全程用 (section, offset) + fixup 表按需解引用。
struct Ref {
int32_t section = -1;
uint32_t offset = 0;
bool valid() const { return section >= 0; }
};
// ── granny_data_type_definition.h:member_type 枚举(序数不可变)────────
enum MemberType {
MT_End = 0, MT_Inline, MT_Reference, MT_RefToArray, MT_ArrayOfRefs,
MT_VariantRef, MT_Removed, MT_RefToVariantArray, MT_String, MT_Transform,
MT_Real32, MT_Int8, MT_UInt8, MT_BinormInt8, MT_NormUInt8,
MT_Int16, MT_UInt16, MT_BinormInt16, MT_NormUInt16,
MT_Int32, MT_UInt32, MT_Real16, MT_EmptyRef, MT_OnePastLast
};
// data_type_definition 在文件里的字节数(32 位指针):
// Type(4) Name(ptr4) ReferenceType(ptr4) ArrayWidth(4) Extra[3](12) Ignored(ptr4)
constexpr uint32_t kTypeDefEntrySize = 32;
struct TypeMember {
std::string name;
int32_t type = MT_End;
int32_t array_width = 0; // 0 => 1
Ref ref_type; // Inline/Reference/... 的元素类型
uint32_t offset = 0; // 在对象实例里的字节偏移(打包,无对齐 pad)
uint32_t size = 0; // 本 member 的总字节数
};
} // namespace detail
struct File::Impl {
std::vector<detail::Section> sections; // 展开后数据 + info
std::vector<detail::GrnSection> raw; // 原始 section 头(fixup 用)
using Ref = detail::Ref;
using TypeMember = detail::TypeMember;
using GrnSection = detail::GrnSection;
// (section<<32 | from_offset) -> 目标 Ref
std::unordered_map<uint64_t, Ref> fixups;
Ref root_obj; // grn_file_header.RootObject
Ref root_type; // grn_file_header.RootObjectTypeDefinition
bool typetree_ready = false;
// 类型解析缓存:typedef 的 Ref -> 成员列表
std::unordered_map<uint64_t, std::vector<TypeMember>> type_cache;
// ── T2 / T1 ──
bool decompress_section(const GrnSection&, const uint8_t* src, detail::Section& out, LoadError*);
void build_fixups(const uint8_t* file, size_t file_len); // T1
// ── T3 ──
const uint8_t* at(Ref r, size_t need = 0) const; // section 内指针 + 边界检查
Ref follow(Ref slot) const; // 解一个"指针槽"
const std::vector<TypeMember>& parse_type(Ref type_ref); // 走 data_type_definition 数组
uint32_t object_size(Ref type_ref);
uint32_t member_unit_size(const TypeMember&);
const TypeMember* find_member(const std::vector<TypeMember>& ms, const char* name) const;
// 便捷读取
uint32_t rd_u32(Ref r) const;
int32_t rd_i32(Ref r) const { return (int32_t)rd_u32(r); }
float rd_f32(Ref r) const;
std::string rd_str(Ref slot) const; // 解引用一个 String 槽
// 成员访问(obj = 对象实例的 Ref,m = 其类型的某个成员)
Ref member_slot(Ref obj, const TypeMember& m) const { return {obj.section, obj.offset + m.offset}; }
Ref read_reference(Ref obj, const TypeMember& m) const { return follow(member_slot(obj, m)); }
// ArrayOfReferences: {int32 count; ptr → [count] 个指针槽 → 各自的对象}
std::vector<Ref> read_array_of_refs(Ref obj, const TypeMember& m) const;
// ReferenceToArray: {int32 count; ptr → [count] 个连续对象(elem_type)}
bool read_ref_to_array(Ref obj, const TypeMember& m, Ref& base, uint32_t& count, uint32_t& stride);
// ── T4/T5/T6/T7a ──
bool build_fileinfo(FileInfo& out, LoadError*);
bool extract_skeleton(Ref skel_obj, Ref skel_type, Skeleton& out);
bool extract_mesh(Ref mesh_obj, Ref mesh_type, const std::vector<Skeleton>& skels, Mesh& out);
// granny_material 链:直接 .Texture.FromFileName,或递归 .Maps[].Material。返回 dds 文件名(原样)。
std::string material_texture_name(Ref mat_obj, Ref mat_type, int depth);
bool extract_animation(Ref anim_obj, Ref anim_type, const Skeleton* skel, Animation& out);
// 曲线子类型分类(T7a)。curve_obj 指向 inline 曲线对象本体,curve_type 是它的类型。
std::string classify_curve_obj(Ref curve_obj, Ref curve_type);
void read_old_curve(Ref curve_obj, Ref curve_type, Curve& out); // T7b
double skeleton_self_check(int skeleton) const;
// granny_transform (68B) → 行主序 4x4(BuildCompositeTransform4x4 语义)
void transform_to_composite(Ref tf, Mat4& out, uint32_t& flags) const;
void read_transform(Ref tf, Transform& out) const; // 68B → SRT 分量
// granny_material 图:按对象 Ref 去重,缺的追加到 mats_out(子材质 / 只经 mesh 可达的材质)。
// 返回 FileInfo::materials 索引;无效 / 递归太深 = -1。
int32_t intern_material(Ref mat_obj, Ref mat_type, int depth = 0);
std::vector<Material>* mats_out = nullptr;
std::vector<Ref> mat_refs; // 与 *mats_out 平行
// ExtendedData(VariantRef = {type ptr; object ptr})里取名为 name 的 Int32。
bool extended_i32(Ref variant_slot, const char* name, int32_t& out);
std::vector<Skeleton> skels_cache; // self-check 复用
std::vector<Ref> skel_refs; // 与 skels_cache 平行:各 skeleton 对象的 Ref(model 关联用)
mutable FileInfo* info_cache = nullptr; // 指向 File::info_
};
} // namespace gr2