Kelsidavis-WoWee/include/pipeline/adt_loader.hpp

213 lines
7.5 KiB
C++
Raw Normal View History

#pragma once
#include <vector>
#include <string>
#include <cstdint>
#include <array>
namespace wowee {
namespace pipeline {
/**
* ADT chunk coordinates
*/
struct ADTCoord {
int32_t x;
int32_t y;
};
/**
* Heightmap for a map chunk (9x9 + 8x8 grid)
*/
struct HeightMap {
std::array<float, 145> heights; // 9x9 outer + 8x8 inner vertices
bool loaded = false;
float getHeight(int x, int y) const;
bool isLoaded() const { return loaded; }
};
/**
* Texture layer for a map chunk
*/
struct TextureLayer {
uint32_t textureId; // Index into MTEX array
uint32_t flags; // Layer flags
uint32_t offsetMCAL; // Offset to alpha map in MCAL chunk
uint32_t effectId; // Effect ID (optional)
bool useAlpha() const { return (flags & 0x100) != 0; }
bool compressedAlpha() const { return (flags & 0x200) != 0; }
};
/**
* Map chunk (256x256 units, 1/16 of ADT)
*/
struct MapChunk {
uint32_t flags;
uint32_t indexX;
uint32_t indexY;
uint16_t holes; // 4x4 bitmask for terrain holes (cave entrances, etc.)
float position[3]; // World position (X, Y, Z)
HeightMap heightMap;
std::vector<TextureLayer> layers;
std::vector<uint8_t> alphaMap; // Alpha blend maps for layers
// Normals (compressed)
std::array<int8_t, 145 * 3> normals; // X, Y, Z per vertex
bool hasHeightMap() const { return heightMap.isLoaded(); }
bool hasLayers() const { return !layers.empty(); }
// Check if a quad has a hole (y and x are quad indices 0-7)
bool isHole(int y, int x) const {
int column = y / 2;
int row = x / 2;
int bit = 1 << (column * 4 + row);
return (bit & holes) != 0;
}
};
/**
* Complete ADT terrain tile (16x16 map chunks)
*/
struct ADTTerrain {
bool loaded = false;
uint32_t version = 0;
ADTCoord coord; // ADT coordinates (e.g., 32, 49 for Azeroth)
// 16x16 map chunks (256 total)
std::array<MapChunk, 256> chunks;
// Texture filenames
std::vector<std::string> textures;
// Doodad definitions (M2 models)
std::vector<std::string> doodadNames;
std::vector<uint32_t> doodadIds;
// WMO definitions (buildings)
std::vector<std::string> wmoNames;
std::vector<uint32_t> wmoIds;
// Doodad placement data (from MDDF chunk)
struct DoodadPlacement {
uint32_t nameId; // Index into doodadNames
uint32_t uniqueId;
float position[3]; // X, Y, Z
float rotation[3]; // Rotation in degrees
uint16_t scale; // 1024 = 1.0
uint16_t flags;
};
std::vector<DoodadPlacement> doodadPlacements;
// WMO placement data (from MODF chunk)
struct WMOPlacement {
uint32_t nameId; // Index into wmoNames
uint32_t uniqueId;
float position[3]; // X, Y, Z
float rotation[3]; // Rotation in degrees
float extentLower[3]; // Bounding box
float extentUpper[3];
uint16_t flags;
uint16_t doodadSet;
};
std::vector<WMOPlacement> wmoPlacements;
// Water/liquid data (from MH2O chunk)
struct WaterLayer {
uint16_t liquidType; // Type of liquid (0=water, 1=ocean, 2=magma, 3=slime)
uint16_t flags;
float minHeight;
float maxHeight;
uint8_t x; // X offset within chunk (0-7)
uint8_t y; // Y offset within chunk (0-7)
uint8_t width; // Width in vertices (1-9)
uint8_t height; // Height in vertices (1-9)
std::vector<float> heights; // Height values (width * height)
std::vector<uint8_t> mask; // Render mask (which tiles to render)
};
struct ChunkWater {
std::vector<WaterLayer> layers;
bool hasWater() const { return !layers.empty(); }
};
std::array<ChunkWater, 256> waterData; // Water for each chunk
MapChunk& getChunk(int x, int y) { return chunks[y * 16 + x]; }
const MapChunk& getChunk(int x, int y) const { return chunks[y * 16 + x]; }
bool isLoaded() const { return loaded; }
size_t getTextureCount() const { return textures.size(); }
};
/**
* ADT terrain loader
*
* Loads WoW 3.3.5a ADT (Azeroth Data Tile) terrain files
* Format specification: https://wowdev.wiki/ADT
*/
class ADTLoader {
public:
/**
* Load ADT terrain from byte data
* @param adtData Raw ADT file data
* @return Loaded terrain (check isLoaded())
*/
static ADTTerrain load(const std::vector<uint8_t>& adtData);
private:
// Chunk identifiers (as they appear in file when read as little-endian uint32)
static constexpr uint32_t MVER = 0x4D564552; // Version (ASCII "MVER")
static constexpr uint32_t MHDR = 0x4D484452; // Header (ASCII "MHDR")
static constexpr uint32_t MCIN = 0x4D43494E; // Chunk info (ASCII "MCIN")
static constexpr uint32_t MTEX = 0x4D544558; // Textures (ASCII "MTEX")
static constexpr uint32_t MMDX = 0x4D4D4458; // Doodad names (ASCII "MMDX")
static constexpr uint32_t MMID = 0x4D4D4944; // Doodad IDs (ASCII "MMID")
static constexpr uint32_t MWMO = 0x4D574D4F; // WMO names (ASCII "MWMO")
static constexpr uint32_t MWID = 0x4D574944; // WMO IDs (ASCII "MWID")
static constexpr uint32_t MDDF = 0x4D444446; // Doodad placement (ASCII "MDDF")
static constexpr uint32_t MODF = 0x4D4F4446; // WMO placement (ASCII "MODF")
static constexpr uint32_t MH2O = 0x4D48324F; // Water/liquid (ASCII "MH2O")
static constexpr uint32_t MCNK = 0x4D434E4B; // Map chunk (ASCII "MCNK")
// Sub-chunks within MCNK
static constexpr uint32_t MCVT = 0x4D435654; // Height values (ASCII "MCVT")
static constexpr uint32_t MCNR = 0x4D434E52; // Normals (ASCII "MCNR")
static constexpr uint32_t MCLY = 0x4D434C59; // Layers (ASCII "MCLY")
static constexpr uint32_t MCRF = 0x4D435246; // References (ASCII "MCRF")
static constexpr uint32_t MCSH = 0x4D435348; // Shadow map (ASCII "MCSH")
static constexpr uint32_t MCAL = 0x4D43414C; // Alpha maps (ASCII "MCAL")
static constexpr uint32_t MCLQ = 0x4D434C51; // Liquid (deprecated) (ASCII "MCLQ")
struct ChunkHeader {
uint32_t magic;
uint32_t size;
};
static bool readChunkHeader(const uint8_t* data, size_t offset, size_t dataSize, ChunkHeader& header);
static uint32_t readUInt32(const uint8_t* data, size_t offset);
static uint16_t readUInt16(const uint8_t* data, size_t offset);
static float readFloat(const uint8_t* data, size_t offset);
static void parseMVER(const uint8_t* data, size_t size, ADTTerrain& terrain);
static void parseMTEX(const uint8_t* data, size_t size, ADTTerrain& terrain);
static void parseMMDX(const uint8_t* data, size_t size, ADTTerrain& terrain);
static void parseMWMO(const uint8_t* data, size_t size, ADTTerrain& terrain);
static void parseMDDF(const uint8_t* data, size_t size, ADTTerrain& terrain);
static void parseMODF(const uint8_t* data, size_t size, ADTTerrain& terrain);
static void parseMCNK(const uint8_t* data, size_t size, int chunkIndex, ADTTerrain& terrain);
static void parseMCVT(const uint8_t* data, size_t size, MapChunk& chunk);
static void parseMCNR(const uint8_t* data, size_t size, MapChunk& chunk);
static void parseMCLY(const uint8_t* data, size_t size, MapChunk& chunk);
static void parseMCAL(const uint8_t* data, size_t size, MapChunk& chunk);
static void parseMH2O(const uint8_t* data, size_t size, ADTTerrain& terrain);
};
} // namespace pipeline
} // namespace wowee