/// <summary> /// Read the doodad instances from the Object ADT. /// </summary> public static void ReadMDDF(BinaryReader reader, uint chunkSize, ADTModel model) { var mddfSize = chunkSize / 36; for (var i = 0; i < mddfSize; ++i) { var mddfEntry = new MDDF(); mddfEntry.FileDataId = reader.ReadUInt32(); mddfEntry.UniqueId = reader.ReadInt32(); var rawY = (reader.ReadSingle() - 17066) * -1 / WorldConstants.WorldScale; var rawZ = reader.ReadSingle() / WorldConstants.WorldScale; var rawX = (reader.ReadSingle() - 17066) * -1 / WorldConstants.WorldScale; mddfEntry.Position = new Vector3(rawX, rawZ, rawY); rawX = reader.ReadSingle(); rawZ = 180 - reader.ReadSingle(); rawY = reader.ReadSingle(); mddfEntry.Rotation = Quaternion.Euler(new Vector3(rawX, rawZ, rawY)); mddfEntry.Scale = reader.ReadUInt16() / 1024.0f; mddfEntry.Flags = (MDDFFlags)reader.ReadUInt16(); model.DoodadInstances.Add(mddfEntry.UniqueId, mddfEntry); } }
/// <summary> /// Read the Obj0.adt format. /// </summary> /// <param name="fileDataId"></param> /// <param name="model"></param> public static void ReadObjADT(uint fileDataId, ADTModel model) { var stream = CASC.OpenFile(fileDataId); if (stream == null) { return; } using (var reader = new BinaryReader(stream)) { while (reader.BaseStream.Position < reader.BaseStream.Length) { var chunkId = (Chunks)reader.ReadUInt32(); var chunkSize = reader.ReadUInt32(); switch (chunkId) { case Chunks.MDDF: // Doodad Instances ReadMDDF(reader, chunkSize, model); break; default: reader.Skip(chunkSize); // Debug.Log($"ADTOBJ: Skipping {chunkId} (0x{chunkId:X}) with size: {chunkSize}.."); break; } } } }
/// <summary> /// Read the Texture MCNK from the texture ADT. /// </summary> public static void ReadTexMCNK(BinaryReader reader, uint mcnkSize, ADTModel model) { var startPosition = reader.BaseStream.Position; var texMcnk = new TexMCNKChunk(); while (reader.BaseStream.Position < startPosition + mcnkSize) { var chunkId = (Chunks)reader.ReadUInt32(); var chunkSize = reader.ReadUInt32(); switch (chunkId) { case Chunks.MCLY: // Texture Layers. ReadMCLY(reader, chunkSize, texMcnk); break; case Chunks.MCAL: // Alpha Layers. ReadMCAL(reader, texMcnk, model.WdtFileDataId, chunkSize); break; default: reader.Skip(chunkSize); break; } } model.TexMCNKs.Add(texMcnk); }
/// <summary> /// Read the MTXP chunk. /// </summary> public static void ReadMTXP(BinaryReader reader, uint chunkSize, ADTModel model) { model.HasMTXP = true; for (var i = 0; i < chunkSize / 16; ++i) { var flags = reader.ReadUInt32(); var heightScale = reader.ReadSingle(); var heightOffset = reader.ReadSingle(); reader.ReadInt32(); // Padding } }
/// <summary> /// Read the Textures from the Tex0 adt. /// </summary> public static void ReadTextures(BinaryReader reader, uint chunkSize, ADTModel data) { var textureSize = chunkSize / 4; for (var i = 0; i < textureSize; ++i) { var texFileDataId = reader.ReadUInt32(); if (!data.TextureFileDataId.Contains(texFileDataId)) { var textureData = BLP.Open(texFileDataId); if (textureData == null) { continue; } data.TextureFileDataId.Add(texFileDataId); data.TextureDatas.Add(texFileDataId, textureData); } } }
/// <summary> /// Read the Tex0.adt format. /// </summary> public static void ReadTexADT(uint fileDataId, ADTModel model) { var stream = CASC.OpenFile(fileDataId); if (stream == null) { return; } using (var reader = new BinaryReader(stream)) { while (reader.BaseStream.Position < reader.BaseStream.Length) { var chunkId = (Chunks)reader.ReadUInt32(); var chunkSize = reader.ReadUInt32(); switch (chunkId) { case Chunks.MDID: case Chunks.MHID: ReadTextures(reader, chunkSize, model); break; case Chunks.MCNK: ReadTexMCNK(reader, chunkSize, model); break; case Chunks.MTXP: ReadMTXP(reader, chunkSize, model); break; default: reader.Skip(chunkSize); // Debug.Log($"ADTTEX: Skipping {chunkId} (0x{chunkId:X}) with size: {chunkSize}.."); break; } } } }
/// <summary> /// Read the MCNK chunk and fills the <see cref="ADTModel"/> and <see cref="MCNKChunk"/> /// </summary> public static void ReadMCNK(BinaryReader reader, ADTModel model, uint mcnkSize) { var startPosition = reader.BaseStream.Position; var mcnk = new MCNKChunk(); mcnk.Flags = reader.ReadUInt32(); mcnk.IndexX = reader.ReadUInt32(); mcnk.IndexY = reader.ReadUInt32(); mcnk.LayerCount = reader.ReadUInt32(); var doodadRefCount = reader.ReadUInt32(); mcnk.HolesHighRes = new byte[8]; for (var i = 0; i < 8; ++i) { mcnk.HolesHighRes[i] = reader.ReadByte(); } var layerOffset = reader.ReadUInt32(); var refOffset = reader.ReadUInt32(); var alphaOffset = reader.ReadUInt32(); var alphaSize = reader.ReadUInt32(); var shadowOffset = reader.ReadUInt32(); var shadowSize = reader.ReadUInt32(); var areaId = reader.ReadUInt32(); var mapObjectRefs = reader.ReadUInt32(); mcnk.HolesLowRes = reader.ReadUInt16(); var unknown1 = reader.ReadUInt16(); var lowQualityTexture = new uint[4]; for (var i = 0; i < 4; ++i) { lowQualityTexture[i] = reader.ReadUInt32(); } var predTex = reader.ReadUInt32(); var noEffectDoodad = reader.ReadUInt32(); var soundEmitterOffset = reader.ReadInt32(); var soundEmitterCount = reader.ReadInt32(); var liquidOffset = reader.ReadInt32(); var liquidSize = reader.ReadInt32(); mcnk.MeshPosition = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); var mccvOffset = reader.ReadInt32(); var mclvOffset = reader.ReadInt32(); reader.ReadInt32(); // Unused while (reader.BaseStream.Position < startPosition + mcnkSize) { var chunkId = (Chunks)reader.ReadUInt32(); var chunkSize = reader.ReadUInt32(); switch (chunkId) { case Chunks.MCVT: // Vertex Heights mcnk.Vertices = ReadMCVT(reader); break; case Chunks.MCNR: // Normals mcnk.Normals = ReadMCNR(reader); break; default: reader.Skip(chunkSize); // Debug.Log($"MCNK - Skipping {chunkId} (0x{chunkId:X}) with size: {chunkSize}.."); break; } } model.MCNKs.Add(mcnk); }