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>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
5266b00c6e
commit
668f48d6ec
+29
-18
@@ -57,32 +57,43 @@ void m3_mul(const float a[9], const float b[9], float r[9]) {
|
||||
} // namespace
|
||||
|
||||
// granny_transform (68B: u32 Flags; f32 Position[3]; f32 Orientation[4]; f32 ScaleShear[3][3])
|
||||
// → 行主序 4x4,上 3x3 = transpose(U3),平移在 elem 12..14。BuildCompositeTransform4x4 语义。
|
||||
void File::Impl::transform_to_composite(Ref tf, Mat4& out, uint32_t& flags) const {
|
||||
void File::Impl::read_transform(Ref tf, Transform& out) const {
|
||||
out = Transform{};
|
||||
const uint8_t* p = at(tf, 68);
|
||||
out = Mat4{};
|
||||
out[0] = out[5] = out[10] = out[15] = 1.0f;
|
||||
flags = 0;
|
||||
if (!p) return;
|
||||
std::memcpy(&out.flags, p, 4);
|
||||
std::memcpy(out.position, p + 4, 12);
|
||||
std::memcpy(out.orientation, p + 16, 16);
|
||||
std::memcpy(out.scale_shear, p + 32, 36);
|
||||
}
|
||||
|
||||
auto f32 = [&](size_t off) { float v; std::memcpy(&v, p + off, 4); return v; };
|
||||
flags = rd_u32(tf);
|
||||
float pos[3] = { f32(4), f32(8), f32(12) };
|
||||
float ori[4] = { f32(16), f32(20), f32(24), f32(28) };
|
||||
float ss[9];
|
||||
for (int i = 0; i < 9; ++i) ss[i] = f32(32 + size_t(i) * 4);
|
||||
|
||||
// → 行主序 4x4,上 3x3 = transpose(U3),平移在 elem 12..14。BuildCompositeTransform4x4 语义。
|
||||
Mat4 compose(const Transform& t) {
|
||||
float q3[9];
|
||||
quat_to_m3(ori, q3);
|
||||
quat_to_m3(t.orientation, q3);
|
||||
float u3[9];
|
||||
if (flags & 0x4 /* HasScaleShear */) m3_mul(q3, ss, u3);
|
||||
if (t.flags & 0x4 /* HasScaleShear */) m3_mul(q3, t.scale_shear, u3);
|
||||
else std::memcpy(u3, q3, sizeof u3);
|
||||
|
||||
Mat4 out{};
|
||||
// C 的上 3x3 = transpose(U3)
|
||||
out[0] = u3[0]; out[1] = u3[3]; out[2] = u3[6]; out[3] = 0;
|
||||
out[4] = u3[1]; out[5] = u3[4]; out[6] = u3[7]; out[7] = 0;
|
||||
out[8] = u3[2]; out[9] = u3[5]; out[10] = u3[8]; out[11] = 0;
|
||||
out[12] = pos[0]; out[13] = pos[1]; out[14] = pos[2]; out[15] = 1;
|
||||
out[12] = t.position[0]; out[13] = t.position[1]; out[14] = t.position[2]; out[15] = 1;
|
||||
return out;
|
||||
}
|
||||
|
||||
void File::Impl::transform_to_composite(Ref tf, Mat4& out, uint32_t& flags) const {
|
||||
Transform t;
|
||||
read_transform(tf, t);
|
||||
if (!at(tf, 68)) {
|
||||
out = Mat4{1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
|
||||
flags = 0;
|
||||
return;
|
||||
}
|
||||
out = compose(t);
|
||||
flags = t.flags;
|
||||
}
|
||||
|
||||
// skeleton: {String Name; RefToArray Bones(bone[]); int32 LODType; VariantRef ExtendedData}
|
||||
@@ -118,9 +129,9 @@ bool File::Impl::extract_skeleton(Ref skel_obj, Ref skel_type, Skeleton& out) {
|
||||
Bone& bo = out.bones[i];
|
||||
if (mName) bo.name = rd_str(member_slot(b, *mName));
|
||||
if (mParent) bo.parent = rd_i32(member_slot(b, *mParent));
|
||||
uint32_t flags = 0;
|
||||
transform_to_composite(member_slot(b, *mLocal), bo.local_transform, flags);
|
||||
bo.lt_flags = flags;
|
||||
read_transform(member_slot(b, *mLocal), bo.local);
|
||||
bo.local_transform = compose(bo.local);
|
||||
bo.lt_flags = bo.local.flags;
|
||||
const uint8_t* iw = at(member_slot(b, *mInvW), 64);
|
||||
if (iw) for (int k = 0; k < 16; ++k) std::memcpy(&bo.inverse_world[k], iw + k * 4, 4);
|
||||
else bo.inverse_world = Mat4{};
|
||||
|
||||
Reference in New Issue
Block a user