public void ReadMH2O(MemoryStream ADTstream, int MH2Osize) { StreamTools s = new StreamTools(); long chunkStartPosition = ADTstream.Position; // header - SMLiquidChunk for (int a = 0; a < 256; a++) { int offset_instances = s.ReadLong(ADTstream); // points to SMLiquidInstance[layer_count] int layer_count = s.ReadLong(ADTstream); // 0 if the chunk has no liquids. If > 1, the offsets will point to arrays. int offset_attributes = s.ReadLong(ADTstream); // points to mh2o_chunk_attributes, can be ommitted for all-0 if (offset_instances >= 0) { // instances @24bytes ADTstream.Seek(chunkStartPosition + offset_instances, SeekOrigin.Begin); int liquid_type = s.ReadShort(ADTstream); //DBC - foreign_keyⁱ<uint16_t, &LiquidTypeRec::m_ID> liquid_type; int liquid_object_or_lvf = s.ReadShort(ADTstream); //DBC - foreign_keyⁱ<uint16_t, &LiquidObjectRec::m_ID> liquid_object_or_lvf; // if > 41, an id into DB/LiquidObject. If below, LiquidVertexFormat, used in ADT/v18#instance_vertex_data Note hardcoded LO ids below. // if >= 42, look up via DB/LiquidType and DB/LiquidMaterial, otherwise use liquid_object_or_lvf as LVF // also see below for offset_vertex_data: if that's 0 and lt ≠ 2 → lvf = 2 float min_height_level = s.ReadFloat(ADTstream); // used as height if no heightmap given and culling ᵘ float max_height_level = s.ReadFloat(ADTstream); // ≥ WoD ignores value and assumes to both be 0.0 for LVF = 2! ᵘ int x_offset = ADTstream.ReadByte(); // The X offset of the liquid square (0-7) int y_offset = ADTstream.ReadByte(); // The Y offset of the liquid square (0-7) int width = ADTstream.ReadByte(); // The width of the liquid square (1-8) int height = ADTstream.ReadByte(); // The height of the liquid square (1-8) // The above four members are only used if liquid_object_or_lvf <= 41. Otherwise they are assumed 0, 0, 8, 8. (18179) int offset_exists_bitmap = s.ReadLong(ADTstream); // not all tiles in the instances need to be filled. always 8*8 bits. // offset can be 0 for all-exist. also see (and extend) Talk:ADT/v18#SMLiquidInstance int offset_vertex_data = s.ReadLong(ADTstream); // actual data format defined by LiquidMaterialRec::m_LVF via LiquidTypeRec::m_materialID // if offset = 0 and liquidType ≠ 2, then let LVF = 2, i.e. some ocean shit } //attributes if (offset_attributes >= 0) { ADTstream.Seek(chunkStartPosition + offset_attributes, SeekOrigin.Begin); ulong fishable = s.ReadUint64(ADTstream); // seems to be usable as visibility information. ulong deep = s.ReadUint64(ADTstream); } } ADTstream.Seek(chunkStartPosition + MH2Osize, SeekOrigin.Begin); // set stream location to right after MH2O }
public void ReadMCNK(MemoryStream ADTstream, int MCNKchunkNumber, int MCNKsize) { StreamTools s = new StreamTools(); Flags f = new Flags(); ADTRootData.MeshChunkData chunkData = new ADTRootData.MeshChunkData(); long MCNKchnkPos = ADTstream.Position; // <Header> - 128 bytes chunkData.flags = f.ReadMCNKflags(ADTstream); chunkData.IndexX = s.ReadLong(ADTstream); chunkData.IndexY = s.ReadLong(ADTstream); chunkData.nLayers = s.ReadLong(ADTstream); // maximum 4 int nDoodadRefs = s.ReadLong(ADTstream); chunkData.holes_high_res = s.ReadUint64(ADTstream); // only used with flags.high_res_holes int ofsLayer = s.ReadLong(ADTstream); int ofsRefs = s.ReadLong(ADTstream); int ofsAlpha = s.ReadLong(ADTstream); int sizeAlpha = s.ReadLong(ADTstream); int ofsShadow = s.ReadLong(ADTstream); // only with flags.has_mcsh int sizeShadow = s.ReadLong(ADTstream); int areaid = s.ReadLong(ADTstream); // in alpha: both zone id and sub zone id, as uint16s. int nMapObjRefs = s.ReadLong(ADTstream); chunkData.holes_low_res = s.ReadShort(ADTstream); int unknown_but_used = s.ReadShort(ADTstream); // 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] = (byte)ADTstream.ReadByte(); } // unsigned integers, naming the layer. ulong noEffectDoodad = s.ReadUint64(ADTstream); // WoD: may be an explicit MCDD chunk int ofsSndEmitters = s.ReadLong(ADTstream); int nSndEmitters = s.ReadLong(ADTstream); // will be set to 0 in the client if ofsSndEmitters doesn't point to MCSE! int ofsLiquid = s.ReadLong(ADTstream); int sizeLiquid = s.ReadLong(ADTstream); // 8 when not used; only read if >8. // in alpha, remainder is padding but unused. chunkData.MeshPosition = new Vector3(s.ReadFloat(ADTstream), s.ReadFloat(ADTstream), s.ReadFloat(ADTstream)); int ofsMCCV = s.ReadLong(ADTstream); // only with flags.has_mccv, had uint32_t textureId; in ObscuR's structure. int ofsMCLV = s.ReadLong(ADTstream); // introduced in Cataclysm int unused = s.ReadLong(ADTstream); // currently unused // </header> if (!chunkData.flags.has_mccv) { FillMCCV(chunkData); // fill vertex shading with 127... } long streamPosition = ADTstream.Position; while (streamPosition < MCNKchnkPos + MCNKsize) { ADTstream.Position = streamPosition; int chunkID = s.ReadLong(ADTstream); int chunkSize = s.ReadLong(ADTstream); streamPosition = ADTstream.Position + chunkSize; switch (chunkID) { case (int)ChunkID.ADT.MCVT: ReadMCVT(ADTstream, chunkData); // vertex heights break; case (int)ChunkID.ADT.MCLV: ReadMCLV(ADTstream, chunkData); // chunk lighting break; case (int)ChunkID.ADT.MCCV: ReadMCCV(ADTstream, chunkData); // vertex shading break; case (int)ChunkID.ADT.MCNR: ReadMCNR(ADTstream, chunkData); // normals break; case (int)ChunkID.ADT.MCSE: ReadMCSE(ADTstream, chunkData, chunkSize); // sound emitters break; case (int)ChunkID.ADT.MCBB: ReadMCBB(ADTstream, chunkData, chunkSize); break; case (int)ChunkID.ADT.MCDD: ReadMCDD(ADTstream, chunkData, chunkSize); break; default: SkipUnknownChunk(ADTstream, chunkID, chunkSize); break; } } ADTRootData.meshBlockData.meshChunksData.Add(chunkData); }