mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-06 00:53:52 +00:00
Upgrades WOM from geometry-only (WOM1) to fully animated (WOM2): - WOM2 magic (0x324D4F57) for animated models, WOM1 for static - Vertex extended: +boneWeights[4] +boneIndices[4] (40 bytes vs 32) - Bone data: keyBoneId, parentBone, pivot, flags per bone - Animation data: per-sequence per-bone keyframes with translation, rotation (quaternion), scale at millisecond timestamps - fromM2() now preserves all skeletal data: bone hierarchy, weights, and per-sequence keyframes from M2 animation tracks - Backward compatible: WOM1 files load without bone data (32-byte vertices read and padded with default bone weights) - FORMAT_SPEC.md updated with WOM2 binary layout
74 lines
2 KiB
C++
74 lines
2 KiB
C++
#pragma once
|
|
|
|
#include <glm/glm.hpp>
|
|
#include <glm/gtc/quaternion.hpp>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <cstdint>
|
|
|
|
namespace wowee {
|
|
namespace pipeline {
|
|
|
|
// Wowee Open Model format (.wom) — novel format, no Blizzard IP
|
|
// WOM1: static geometry | WOM2: + bones + animations
|
|
struct WoweeModel {
|
|
struct Vertex {
|
|
glm::vec3 position;
|
|
glm::vec3 normal;
|
|
glm::vec2 texCoord;
|
|
uint8_t boneWeights[4] = {255, 0, 0, 0};
|
|
uint8_t boneIndices[4] = {0, 0, 0, 0};
|
|
};
|
|
|
|
struct Bone {
|
|
int32_t keyBoneId = -1;
|
|
int16_t parentBone = -1;
|
|
glm::vec3 pivot{0};
|
|
uint32_t flags = 0;
|
|
};
|
|
|
|
struct AnimKeyframe {
|
|
uint32_t timeMs;
|
|
glm::vec3 translation;
|
|
glm::quat rotation;
|
|
glm::vec3 scale;
|
|
};
|
|
|
|
struct Animation {
|
|
uint32_t id = 0;
|
|
uint32_t durationMs = 0;
|
|
float movingSpeed = 0;
|
|
std::vector<std::vector<AnimKeyframe>> boneKeyframes; // [boneIdx][keyframe]
|
|
};
|
|
|
|
std::string name;
|
|
std::vector<Vertex> vertices;
|
|
std::vector<uint32_t> indices;
|
|
std::vector<std::string> texturePaths;
|
|
std::vector<Bone> bones;
|
|
std::vector<Animation> animations;
|
|
float boundRadius = 1.0f;
|
|
glm::vec3 boundMin{0}, boundMax{0};
|
|
uint32_t version = 1; // 1=WOM1(static), 2=WOM2(animated)
|
|
|
|
bool isValid() const { return !vertices.empty() && !indices.empty(); }
|
|
bool hasAnimation() const { return !bones.empty() && !animations.empty(); }
|
|
};
|
|
|
|
class WoweeModelLoader {
|
|
public:
|
|
// Load from .wom file (binary) + .wom.json (metadata)
|
|
static WoweeModel load(const std::string& basePath);
|
|
|
|
// Save to .wom + .wom.json
|
|
static bool save(const WoweeModel& model, const std::string& basePath);
|
|
|
|
// Convert an M2 model to WoweeModel (static geometry only, no animation)
|
|
static WoweeModel fromM2(const std::string& m2Path, class AssetManager* am);
|
|
|
|
// Check if a .wom exists
|
|
static bool exists(const std::string& basePath);
|
|
};
|
|
|
|
} // namespace pipeline
|
|
} // namespace wowee
|