#ifndef MODEL_M2_DATA_HPP #define MODEL_M2_DATA_HPP #include "gx/Buffer.hpp" #include "math/Types.hpp" #include #include #include /* M2Array has been modified from the implementation present in 12340. The implementation present in 12340 looks like this: template struct M2Array { uint32_t count; union { T* data; uint32_t offset; } }; On a 32-bit system, sizeof(M2Array) == 8 bytes in memory: 4 bytes for the count, and 4 bytes for the union. This lines up with M2Array in the .m2 files: each M2Array is 8 bytes. In 12340 (and until 64-bit support was introduced), the M2Init functions simply adjust the M2Array when loading: m2Data->someM2Array.offset = (uint32_t)m2Data + m2Data->someM2Array.offset; This ensures T* data points to the appropriate (absolute) location in memory. Unfortunately, this approach fails on 64-bit systems. On a 64-bit system, M2Array would occupy 12 bytes in memory: 4 bytes for the count, and 8 bytes for the union. This would make the approach outlined above fail. As a result, on 64-bit systems, a different approach is used: M2Arrays are assumed (reasonably so) to only exist within the same structure that their on-disk offsets reference. Thus, M2Init adjusts the M2Array when loading: uintptr_t absoluteOffset = (uintptr_t)m2Data + m2Data->someM2Array.offset; uintptr_t relativeOffset = absoluteOffset - (uintptr_t)&m2Data->someM2Array; m2Data->someM2Array.offset = (uint32_t)relativeOffset; By storing the relative offset, access to the data is possible by adding the relative offset to the address of the M2Array: uintptr_t absoluteOffset = (uintptr_t)m2Data->someM2Array + m2Data->someM2Array.offset; T* data = (T*)absoluteOffset; */ template struct M2Array { uint32_t count; uint32_t offset; T& operator[](uint32_t i); T& operator[](uint32_t i) const; uint32_t Count(); uint32_t Count() const; T* Data(); }; template T& M2Array::operator[](uint32_t i) { T* data = reinterpret_cast(reinterpret_cast(this) + this->offset); return data[i]; } template T& M2Array::operator[](uint32_t i) const { T* data = reinterpret_cast(reinterpret_cast(this) + this->offset); return data[i]; } template uint32_t M2Array::Count() { return this->count; } template uint32_t M2Array::Count() const { return this->count; } template T* M2Array::Data() { T* data = reinterpret_cast(reinterpret_cast(this) + this->offset); return data; } template struct M2SequenceKeys { M2Array keys; }; struct M2SequenceTimes { M2Array times; }; struct M2TrackBase { uint16_t trackType; uint16_t loopIndex; M2Array sequenceTimes; }; template class M2Track : public M2TrackBase { public: M2Array> sequenceKeys; }; struct M2Attachment { uint32_t attachmentId; uint16_t boneIndex; C3Vector position; M2Track visibilityTrack; }; struct M2Batch { uint8_t flags; int8_t priorityPlane; uint16_t shader; uint16_t skinSectionIndex; uint16_t geosetIndex; uint16_t colorIndex; uint16_t materialIndex; uint16_t materialLayer; uint16_t textureCount; uint16_t textureComboIndex; uint16_t textureCoordComboIndex; uint16_t textureWeightComboIndex; uint16_t textureTransformComboIndex; }; struct M2Bounds { CAaBox extent; float radius; }; template struct M2SplineKey { T value; T inTan; T outTan; }; struct M2Camera { uint32_t cameraId; float fieldOfView; float farClip; float nearClip; M2Track> positionTrack; C3Vector positionPivot; M2Track> targetTrack; C3Vector targetPivot; M2Track> rollTrack; }; struct M2Color { M2Track colorTrack; M2Track alphaTrack; }; struct M2CompQuat { uint32_t auCompQ[2]; }; struct M2CompBone { uint32_t boneId; uint32_t flags; uint16_t parentIndex; uint16_t uDistToParent; union { struct { uint16_t uDistToFurthDesc; uint16_t uZRatioOfChain; } CompressData; uint32_t boneNameCRC; }; M2Track translationTrack; M2Track rotationTrack; M2Track scaleTrack; C3Vector pivot; }; struct M2Event { uint32_t eventId; uint32_t data; uint16_t boneIndex; C3Vector position; M2TrackBase eventTrack; }; struct M2Light { uint16_t lightType; uint16_t boneIndex; C3Vector position; M2Track ambientColorTrack; M2Track ambientIntensityTrack; M2Track diffuseColorTrack; M2Track diffuseIntensityTrack; M2Track attenuationStartTrack; M2Track attenuationEndTrack; M2Track visibilityTrack; }; struct M2Loop { uint32_t length; }; struct M2Material { uint16_t flags; uint16_t blendMode; }; template struct M2PartTrack { M2Array times; M2Array values; }; struct M2Particle { uint32_t particleId; uint32_t flags; C3Vector position; uint16_t boneIndex; uint16_t textureIndex; M2Array geometryMdl; M2Array recursionMdl; uint8_t blendMode; uint8_t emitterType; uint16_t colorIndex; uint16_t pad; int16_t priorityPlane; uint16_t rows; uint16_t cols; M2Track speedTrack; M2Track variationTrack; M2Track latitudeTrack; M2Track longitudeTrack; M2Track gravityTrack; M2Track lifeTrack; float lifeVariation; M2Track emissionRateTrack; float emissionRateVariation; M2Track widthTrack; M2Track lengthTrack; M2Track zsourceTrack; M2PartTrack colorTrack; M2PartTrack alphaTrack; M2PartTrack scaleTrack; C2Vector scaleVariation; M2PartTrack headCellTrack; M2PartTrack tailCellTrack; float tailLength; float twinkleFPS; float twinkleOnOff; CRange twinkleScale; float ivelScale; float drag; float initialSpin; float initialSpinVariation; float spin; float spinVariation; CAaBox tumble; C3Vector windVector; float windTime; float followSpeed1; float followScale1; float followSpeed2; float followScale2; M2Array spline; M2Track visibilityTrack; }; struct M2Ribbon { uint32_t ribbonId; uint16_t boneIndex; C3Vector position; M2Array textureIndices; M2Array materialIndices; M2Track colorTrack; M2Track alphaTrack; M2Track heightAboveTrack; M2Track heightBelowTrack; float edgesPerSecond; float edgeLifetime; float gravity; uint16_t textureRows; uint16_t textureCols; M2Track textureSlotTrack; M2Track visibilityTrack; int16_t priorityPlane; uint16_t pad; }; struct M2Sequence { uint16_t id; uint16_t variationIndex; uint32_t duration; float movespeed; uint32_t flags; uint32_t frequency; CiRange replay; uint32_t blendtime; M2Bounds bounds; uint16_t variationNext; uint16_t aliasNext; }; struct M2SkinSection { uint32_t skinSectionId; uint16_t vertexStart; uint16_t vertexCount; uint16_t indexStart; uint16_t indexCount; uint16_t boneCount; uint16_t boneComboIndex; uint16_t boneInfluences; uint16_t centerBoneIndex; C3Vector centerPosition; C3Vector sortCenterPosition; float sortRadius; }; struct M2Texture { uint32_t textureId; uint16_t flags; M2Array filename; }; struct M2TextureTransform { M2Track translationTrack; M2Track rotationTrack; M2Track scaleTrack; }; struct M2TextureWeight { M2Track weightTrack; }; struct M2Vertex { C3Vector position; ubyte4 weights; ubyte4 indices; C3Vector normal; C2Vector texcoord[2]; }; // .m2 files struct M2Data { uint32_t MD20; uint32_t version; M2Array name; uint32_t flags; M2Array loops; M2Array sequences; M2Array sequenceIdxHashById; M2Array bones; M2Array boneIndicesById; M2Array vertices; uint32_t numSkinProfiles; M2Array colors; M2Array textures; M2Array textureWeights; M2Array textureTransforms; M2Array textureIndicesById; M2Array materials; M2Array boneCombos; M2Array textureCombos; M2Array textureCoordCombos; M2Array textureWeightCombos; M2Array textureTransformCombos; M2Bounds bounds; M2Bounds collisionBounds; M2Array collisionIndices; M2Array collisionPositions; M2Array collisionFaceNormals; M2Array attachments; M2Array attachmentIndicesById; M2Array events; M2Array lights; M2Array cameras; M2Array cameraIndicesById; M2Array ribbons; M2Array particles; M2Array textureCombinerCombos; }; // .skin files struct M2SkinProfile { uint32_t magic; M2Array vertices; M2Array indices; M2Array bones; M2Array skinSections; M2Array batches; uint32_t boneCountMax; }; #endif