Kelsidavis-WoWee/include/pipeline/wmo_loader.hpp

223 lines
5.3 KiB
C++
Raw Normal View History

#pragma once
#include <vector>
#include <string>
#include <unordered_map>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
namespace wowee {
namespace pipeline {
/**
* WMO (World Model Object) Format
*
* WMO files contain buildings, dungeons, and large structures.
* Structure:
* - Root WMO file: Contains groups, materials, doodad sets
* - Group WMO files: Individual rooms/sections (_XXX.wmo)
*
* Reference: https://wowdev.wiki/WMO
*/
// WMO Material
struct WMOMaterial {
uint32_t flags;
uint32_t shader;
uint32_t blendMode;
uint32_t texture1; // Diffuse texture index
uint32_t color1;
uint32_t texture2; // Environment/detail texture
uint32_t color2;
uint32_t texture3;
uint32_t color3;
float runtime[4]; // Runtime data
};
// WMO Group Info
struct WMOGroupInfo {
uint32_t flags;
glm::vec3 boundingBoxMin;
glm::vec3 boundingBoxMax;
int32_t nameOffset; // Group name in MOGN chunk
};
// WMO Light
struct WMOLight {
uint32_t type; // 0=omni, 1=spot, 2=directional, 3=ambient
uint8_t useAttenuation;
uint8_t pad[3];
glm::vec4 color;
glm::vec3 position;
float intensity;
float attenuationStart;
float attenuationEnd;
float unknown[4];
};
// WMO Doodad Set (collection of M2 models placed in WMO)
struct WMODoodadSet {
char name[20];
uint32_t startIndex; // First doodad in MODD
uint32_t count; // Number of doodads
uint32_t padding;
};
// WMO Doodad Instance
struct WMODoodad {
uint32_t nameIndex; // Index into MODN (doodad names)
glm::vec3 position;
glm::quat rotation; // Quaternion rotation
float scale;
glm::vec4 color; // BGRA color
};
// WMO Fog
struct WMOFog {
uint32_t flags;
glm::vec3 position;
float smallRadius;
float largeRadius;
float endDist;
float startFactor;
glm::vec4 color1; // End fog color
float endDist2;
float startFactor2;
glm::vec4 color2; // Start fog color (blend with color1)
};
// WMO Portal
struct WMOPortal {
uint16_t startVertex;
uint16_t vertexCount;
uint16_t planeIndex;
uint16_t padding;
};
// WMO Portal Plane
struct WMOPortalPlane {
glm::vec3 normal;
float distance;
};
// WMO Group Vertex
struct WMOVertex {
glm::vec3 position;
glm::vec3 normal;
glm::vec2 texCoord;
glm::vec4 color; // Vertex color
};
// WMO Batch (render batch)
struct WMOBatch {
uint32_t startIndex; // First index (this is uint32 in file format)
uint16_t indexCount; // Number of indices
uint16_t startVertex;
uint16_t lastVertex;
uint8_t flags;
uint8_t materialId;
};
// WMO Group (individual room/section)
struct WMOGroup {
uint32_t flags;
glm::vec3 boundingBoxMin;
glm::vec3 boundingBoxMax;
uint16_t portalStart;
uint16_t portalCount;
uint16_t batchCountA;
uint16_t batchCountB;
uint32_t fogIndices[4]; // Fog references
uint32_t liquidType;
uint32_t groupId;
// Geometry
std::vector<WMOVertex> vertices;
std::vector<uint16_t> indices;
std::vector<WMOBatch> batches;
// Portals
std::vector<WMOPortal> portals;
std::vector<glm::vec3> portalVertices;
// BSP tree (for collision - optional)
std::vector<uint8_t> bspNodes;
std::string name;
std::string description;
};
// Complete WMO Model
struct WMOModel {
// Root WMO data
uint32_t version;
uint32_t nGroups;
uint32_t nPortals;
uint32_t nLights;
uint32_t nDoodadNames;
uint32_t nDoodadDefs;
uint32_t nDoodadSets;
glm::vec3 boundingBoxMin;
glm::vec3 boundingBoxMax;
// Materials and textures
std::vector<WMOMaterial> materials;
std::vector<std::string> textures;
std::unordered_map<uint32_t, uint32_t> textureOffsetToIndex; // MOTX offset -> texture array index
// Groups (rooms/sections)
std::vector<WMOGroupInfo> groupInfo;
std::vector<WMOGroup> groups;
// Portals (visibility culling)
std::vector<WMOPortal> portals;
std::vector<WMOPortalPlane> portalPlanes;
std::vector<glm::vec3> portalVertices;
// Lights
std::vector<WMOLight> lights;
// Doodads (M2 models placed in WMO)
// Keyed by byte offset into MODN chunk (nameIndex in MODD references these offsets)
std::unordered_map<uint32_t, std::string> doodadNames;
std::vector<WMODoodad> doodads;
std::vector<WMODoodadSet> doodadSets;
// Fog
std::vector<WMOFog> fogs;
// Group names
std::vector<std::string> groupNames;
bool isValid() const {
return nGroups > 0 && !groups.empty();
}
};
class WMOLoader {
public:
/**
* Load root WMO file
*
* @param wmoData Raw WMO file bytes
* @return Parsed WMO model (without group geometry)
*/
static WMOModel load(const std::vector<uint8_t>& wmoData);
/**
* Load WMO group file
*
* @param groupData Raw WMO group file bytes
* @param model Model to populate with group data
* @param groupIndex Group index to load
* @return True if successful
*/
static bool loadGroup(const std::vector<uint8_t>& groupData,
WMOModel& model,
uint32_t groupIndex);
};
} // namespace pipeline
} // namespace wowee