// Chunk Data // public void ReadMCNKObj(BinaryReader reader, int MCNKchunkNumber, uint MCNKsize) { if (reader.BaseStream.Length == reader.BaseStream.Position) { return; } long MCNKchnkPos = reader.BaseStream.Position; long streamPosition = reader.BaseStream.Position; while (streamPosition < MCNKchnkPos + MCNKsize) { reader.BaseStream.Position = streamPosition; ADTChunkId chunkID = (ADTChunkId)reader.ReadInt32(); uint chunkSize = reader.ReadUInt32(); streamPosition = reader.BaseStream.Position + chunkSize; switch (chunkID) { case ADTChunkId.MCRD: ReadMCRD(reader, MCNKchunkNumber, chunkSize); // MCNK.nDoodadRefs into the file's MDDF break; case ADTChunkId.MCRW: ReadMCRW(reader, MCNKchunkNumber, chunkSize); // MCNK.nMapObjRefs into the file's MODF break; default: SkipUnknownChunk(reader, chunkID, chunkSize); break; } } }
// Move the stream forward upon finding unknown chunks // public static void SkipUnknownChunk(Stream stream, ADTChunkId chunkID, uint chunkSize) { // if (Enum.IsDefined(typeof(ADTChunkId), chunkID)) // Debug.Log($"Missing chunk ID : {chunkID}"); stream.Seek(chunkSize, SeekOrigin.Current); }
// Move the stream forward upon finding unknown chunks // public static void SkipUnknownChunk(BinaryReader reader, ADTChunkId chunkID, uint chunkSize) { if (Enum.IsDefined(typeof(ADTChunkId), chunkID)) { Debug.Log($"Missing chunk ID : {chunkID}"); } reader.BaseStream.Seek(chunkSize, SeekOrigin.Current); }
// Terrain Texture Parser // private static void ParseADT_Tex(uint TexFileDataId, CASCHandler Handler, uint WdtFileDataId) { ADTTex t = new ADTTex(); int MCNKchunkNumber = 0; long StreamPos = 0; using (var stream = Handler.OpenFile(TexFileDataId)) using (var reader = new BinaryReader(stream)) { while (StreamPos < stream.Length) { stream.Position = StreamPos; ADTChunkId chunkID = (ADTChunkId)reader.ReadInt32(); uint chunkSize = reader.ReadUInt32(); StreamPos = stream.Position + chunkSize; switch (chunkID) { case ADTChunkId.MVER: t.ReadMVER(reader); // ADT file version break; case ADTChunkId.MAMP: t.ReadMAMP(reader); // Single value - texture size = 64 break; case ADTChunkId.MCNK: { t.ReadMCNKtex(reader, WdtFileDataId, MCNKchunkNumber, chunkSize); // Texture Data - 256chunks MCNKchunkNumber++; } break; case ADTChunkId.MTXP: t.ReadMTXP(reader, chunkSize); break; case ADTChunkId.MHID: t.ReadMHID(reader, chunkSize, Handler); break; case ADTChunkId.MDID: t.ReadMDID(reader, chunkSize, Handler); break; default: SkipUnknownChunk(stream, chunkID, chunkSize); break; } } } }
// Terrain Mesh Parser // private static void ParseADT_Main(uint RootAdtFileDataId, CASCHandler Handler) // MS version { ADTRoot r = new ADTRoot(); int MCNKchunkNumber = 0; long StreamPos = 0; using (var stream = Handler.OpenFile(RootAdtFileDataId)) using (var reader = new BinaryReader(stream)) { while (StreamPos < stream.Length) { stream.Position = StreamPos; ADTChunkId chunkID = (ADTChunkId)reader.ReadInt32(); uint chunkSize = reader.ReadUInt32(); StreamPos = stream.Position + chunkSize; switch (chunkID) { case ADTChunkId.MVER: r.ReadMVER(reader); // ADT file version break; case ADTChunkId.MHDR: r.ReadMHDR(reader); // Offsets for specific chunks 0000 if chunks don't exist. break; // case ADTChunkId.MH2O: // r.ReadMH2O(reader, chunkSize); // Water Data // break; case ADTChunkId.MCNK: { r.ReadMCNK(reader, MCNKchunkNumber, chunkSize); // Terrain Data - 256chunks MCNKchunkNumber++; } break; case ADTChunkId.MFBO: r.ReadMFBO(reader); // FlightBounds plane & Death plane break; default: SkipUnknownChunk(stream, chunkID, chunkSize); break; } } } }
// Terrain Models Parser // public static void ParseADT_Obj(uint OBJFileDataId, CASCHandler Handler) { ADTObj o = new ADTObj(); int MCNKchunkNumber = 0; long StreamPos = 0; using (var stream = Handler.OpenFile(OBJFileDataId)) using (BinaryReader reader = new BinaryReader(stream)) { while (stream.Position < stream.Length) { stream.Position = StreamPos; ADTChunkId chunkID = (ADTChunkId)reader.ReadInt32(); uint chunkSize = reader.ReadUInt32(); StreamPos = stream.Position + chunkSize; switch (chunkID) { case ADTChunkId.MVER: o.ReadMVER(reader); // ADT file version break; case ADTChunkId.MDDF: o.ReadMDDF(reader, chunkSize); // Placement information for doodads (M2 models). break; case ADTChunkId.MODF: o.ReadMODF(reader, chunkSize); // Placement information for WMOs. break; case ADTChunkId.MCNK: { o.ReadMCNKObj(reader, MCNKchunkNumber, chunkSize); // 256chunks MCNKchunkNumber++; } break; default: SkipUnknownChunk(stream, chunkID, chunkSize); break; } } } }
public void ReadMCNKtex(BinaryReader reader, uint WdtFileDataId, int MCNKchunkNumber, uint MCNKsize) { if (reader.BaseStream.Length == reader.BaseStream.Position) { return; } ADTTexData.TextureChunkData chunkData = new ADTTexData.TextureChunkData(); long MCNKchnkPos = reader.BaseStream.Position; long streamPosition = reader.BaseStream.Position; while (streamPosition < MCNKchnkPos + MCNKsize) { reader.BaseStream.Position = streamPosition; ADTChunkId chunkID = (ADTChunkId)reader.ReadInt32(); uint chunkSize = reader.ReadUInt32(); streamPosition = reader.BaseStream.Position + chunkSize; switch (chunkID) { case ADTChunkId.MCLY: ReadMCLY(reader, chunkData, chunkSize); // texture layers break; case ADTChunkId.MCSH: ReadMCSH(reader, chunkData); // static shadow maps break; case ADTChunkId.MCAL: ReadMCAL(reader, WdtFileDataId, chunkData); // alpha layers break; case ADTChunkId.MCMT: ReadMCMT(reader); break; default: SkipUnknownChunk(reader, chunkID, chunkSize); break; } } ADTTexData.textureBlockData.textureChunksData.Add(chunkData); }
public void ReadMCNK(BinaryReader reader, int MCNKchunkNumber, uint MCNKsize) { Flags f = new Flags(); ADTRootData.MeshChunkData chunkData = new ADTRootData.MeshChunkData(); long MCNKchnkPos = reader.BaseStream.Position; // <Header> - 128 bytes chunkData.flags = f.ReadMCNKflags(reader); chunkData.IndexX = reader.ReadUInt32(); chunkData.IndexY = reader.ReadUInt32(); chunkData.nLayers = reader.ReadUInt32(); // maximum 4 uint nDoodadRefs = reader.ReadUInt32(); chunkData.holes_high_res = reader.ReadUInt64(); // only used with flags.high_res_holes uint ofsLayer = reader.ReadUInt32(); uint ofsRefs = reader.ReadUInt32(); uint ofsAlpha = reader.ReadUInt32(); uint sizeAlpha = reader.ReadUInt32(); uint ofsShadow = reader.ReadUInt32(); // only with flags.has_mcsh uint sizeShadow = reader.ReadUInt32(); uint areaid = reader.ReadUInt32(); // in alpha: both zone id and sub zone id, as uint16s. uint nMapObjRefs = reader.ReadUInt32(); chunkData.holes_low_res = reader.ReadUInt16(); ushort unknown_but_used = reader.ReadUInt16(); // in alpha: padding byte[] ReallyLowQualityTextureingMap = new byte[16]; // uint2_t[8][8] "predTex", It is used to determine which detail doodads to show. Values are an array of two bit for (int b = 0; b < 16; b++) { ReallyLowQualityTextureingMap[b] = reader.ReadByte(); } // unsigned integers, naming the layer. ulong noEffectDoodad = reader.ReadUInt64(); // WoD: may be an explicit MCDD chunk int ofsSndEmitters = reader.ReadInt32(); int nSndEmitters = reader.ReadInt32(); // will be set to 0 in the client if ofsSndEmitters doesn't point to MCSE! int ofsLiquid = reader.ReadInt32(); int sizeLiquid = reader.ReadInt32(); // 8 when not used; only read if >8. // in alpha, remainder is padding but unused. chunkData.MeshPosition = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); int ofsMCCV = reader.ReadInt32(); // only with flags.has_mccv, had uint32_t textureId; in ObscuR's structure. int ofsMCLV = reader.ReadInt32(); // introduced in Cataclysm int unused = reader.ReadInt32(); // currently unused // </header> if (!chunkData.flags.has_mccv) { FillMCCV(chunkData); // fill vertex shading with 127... } long streamPosition = reader.BaseStream.Position; while (streamPosition < MCNKchnkPos + MCNKsize) { reader.BaseStream.Position = streamPosition; ADTChunkId chunkId = (ADTChunkId)reader.ReadInt32(); uint chunkSize = reader.ReadUInt32(); streamPosition = reader.BaseStream.Position + chunkSize; switch (chunkId) { case ADTChunkId.MCVT: ReadMCVT(reader, chunkData); // vertex heights break; case ADTChunkId.MCLV: ReadMCLV(reader, chunkData); // chunk lighting break; case ADTChunkId.MCCV: ReadMCCV(reader, chunkData); // vertex shading break; case ADTChunkId.MCNR: ReadMCNR(reader, chunkData); // normals break; case ADTChunkId.MCSE: ReadMCSE(reader, chunkData, chunkSize); // sound emitters break; case ADTChunkId.MCBB: ReadMCBB(reader, chunkData, chunkSize); break; case ADTChunkId.MCDD: ReadMCDD(reader, chunkData, chunkSize); break; default: SkipUnknownChunk(reader, chunkId, chunkSize); break; } } ADTRootData.meshBlockData.meshChunksData.Add(chunkData); }