#pragma once #include #include #include #include namespace wowee { namespace pipeline { /** * M2 Model Format (WoW Character/Creature Models) * * M2 files contain: * - Skeletal animated meshes * - Multiple texture units and materials * - Animation sequences * - Bone hierarchy * - Particle emitters, ribbon emitters, etc. * * Reference: https://wowdev.wiki/M2 */ // Animation sequence data struct M2Sequence { uint32_t id; // Animation ID uint32_t variationIndex; // Sub-animation index uint32_t duration; // Length in milliseconds float movingSpeed; // Speed during animation uint32_t flags; // Animation flags int16_t frequency; // Probability weight uint32_t replayMin; // Minimum replay delay uint32_t replayMax; // Maximum replay delay uint32_t blendTime; // Blend time in ms glm::vec3 boundMin; // Bounding box glm::vec3 boundMax; float boundRadius; // Bounding sphere radius int16_t nextAnimation; // Next animation in chain uint16_t aliasNext; // Alias for next animation }; // Animation track with per-sequence keyframe data struct M2AnimationTrack { uint16_t interpolationType = 0; // 0=none, 1=linear, 2=hermite, 3=bezier int16_t globalSequence = -1; // -1 if not a global sequence struct SequenceKeys { std::vector timestamps; // Milliseconds std::vector vec3Values; // For translation/scale tracks std::vector quatValues; // For rotation tracks }; std::vector sequences; // One per animation sequence bool hasData() const { return !sequences.empty(); } }; // Bone data for skeletal animation struct M2Bone { int32_t keyBoneId; // Bone ID (-1 = not key bone) uint32_t flags; // Bone flags int16_t parentBone; // Parent bone index (-1 = root) uint16_t submeshId; // Submesh ID glm::vec3 pivot; // Pivot point M2AnimationTrack translation; // Position keyframes per sequence M2AnimationTrack rotation; // Rotation keyframes per sequence M2AnimationTrack scale; // Scale keyframes per sequence }; // Vertex with skinning data struct M2Vertex { glm::vec3 position; uint8_t boneWeights[4]; // Bone weights (0-255) uint8_t boneIndices[4]; // Bone indices glm::vec3 normal; glm::vec2 texCoords[2]; // Two UV sets }; // Texture unit struct M2Texture { uint32_t type; // Texture type uint32_t flags; // Texture flags std::string filename; // Texture filename (from FileData or embedded) }; // Render batch (submesh) struct M2Batch { uint8_t flags; int8_t priorityPlane; uint16_t shader; // Shader ID uint16_t skinSectionIndex; // Submesh index uint16_t colorIndex; // Color animation index uint16_t materialIndex; // Material index uint16_t materialLayer; // Material layer uint16_t textureCount; // Number of textures uint16_t textureIndex; // First texture lookup index uint16_t textureUnit; // Texture unit uint16_t transparencyIndex; // Transparency animation index uint16_t textureAnimIndex; // Texture animation index // Render data uint32_t indexStart; // First index uint32_t indexCount; // Number of indices uint32_t vertexStart; // First vertex uint32_t vertexCount; // Number of vertices // Geoset info (from submesh) uint16_t submeshId = 0; // Submesh/geoset ID (determines body part group) uint16_t submeshLevel = 0; // Submesh level (0=base, 1+=LOD/alternate mesh) }; // Texture transform (UV animation) data struct M2TextureTransform { M2AnimationTrack translation; // UV translation keyframes M2AnimationTrack rotation; // UV rotation keyframes (quat) M2AnimationTrack scale; // UV scale keyframes }; // Attachment point (bone-anchored position for weapons, effects, etc.) struct M2Attachment { uint32_t id; // 0=Head, 1=RightHand, 2=LeftHand, etc. uint16_t bone; // Bone index glm::vec3 position; // Offset from bone pivot }; // Complete M2 model structure struct M2Model { // Model metadata std::string name; uint32_t version; glm::vec3 boundMin; // Model bounding box glm::vec3 boundMax; float boundRadius; // Bounding sphere // Geometry data std::vector vertices; std::vector indices; // Skeletal animation std::vector bones; std::vector sequences; std::vector globalSequenceDurations; // Per-global-sequence loop durations (ms) // Rendering std::vector batches; std::vector textures; std::vector textureLookup; // Batch texture index lookup // Texture transforms (UV animation) std::vector textureTransforms; std::vector textureTransformLookup; // Attachment points (for weapon/effect anchoring) std::vector attachments; std::vector attachmentLookup; // attachment ID → index // Flags uint32_t globalFlags; bool isValid() const { return !vertices.empty() && !indices.empty(); } }; class M2Loader { public: /** * Load M2 model from raw file data * * @param m2Data Raw M2 file bytes * @return Parsed M2 model */ static M2Model load(const std::vector& m2Data); /** * Load M2 skin file (contains submesh/batch data) * * @param skinData Raw M2 skin file bytes * @param model Model to populate with skin data * @return True if successful */ static bool loadSkin(const std::vector& skinData, M2Model& model); /** * Load external .anim file data into model bone tracks * * @param m2Data Original M2 file bytes (contains track headers) * @param animData Raw .anim file bytes * @param sequenceIndex Which sequence index this .anim file provides data for * @param model Model to patch with animation data */ static void loadAnimFile(const std::vector& m2Data, const std::vector& animData, uint32_t sequenceIndex, M2Model& model); }; } // namespace pipeline } // namespace wowee