mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-23 15:50:20 +00:00
187 lines
6.2 KiB
C++
187 lines
6.2 KiB
C++
#pragma once
|
|
|
|
#include <vector>
|
|
#include <string>
|
|
#include <glm/glm.hpp>
|
|
#include <glm/gtc/quaternion.hpp>
|
|
|
|
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<uint32_t> timestamps; // Milliseconds
|
|
std::vector<glm::vec3> vec3Values; // For translation/scale tracks
|
|
std::vector<glm::quat> quatValues; // For rotation tracks
|
|
};
|
|
std::vector<SequenceKeys> 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)
|
|
};
|
|
|
|
// 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<M2Vertex> vertices;
|
|
std::vector<uint16_t> indices;
|
|
|
|
// Skeletal animation
|
|
std::vector<M2Bone> bones;
|
|
std::vector<M2Sequence> sequences;
|
|
|
|
// Rendering
|
|
std::vector<M2Batch> batches;
|
|
std::vector<M2Texture> textures;
|
|
std::vector<uint16_t> textureLookup; // Batch texture index lookup
|
|
|
|
// Attachment points (for weapon/effect anchoring)
|
|
std::vector<M2Attachment> attachments;
|
|
std::vector<uint16_t> 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<uint8_t>& 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<uint8_t>& 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<uint8_t>& m2Data,
|
|
const std::vector<uint8_t>& animData,
|
|
uint32_t sequenceIndex,
|
|
M2Model& model);
|
|
};
|
|
|
|
} // namespace pipeline
|
|
} // namespace wowee
|