private MCAL[] ReadMCALSubChunk(BlizzHeader subchunk, BinaryReader subbin, TexMCNK mapchunk) { var mcal = new MCAL[mapchunk.layers.Length]; mcal[0].layer = new byte[64 * 64]; for(int i = 0; i < 64 * 64; i++) { mcal[0].layer[i] = 255; } uint read_offset = 0; for (int layer = 1; layer < mapchunk.layers.Length; ++layer) { // we assume that we have read as many bytes as this next layer's mcal offset. we then read depending on encoding if (mapchunk.layers[layer].offsetInMCAL != read_offset) { throw new Exception("mismatch: layer before required more / less bytes than expected"); } if (mapchunk.layers[layer].flags.HasFlag (mclyFlags.Flag_0x200)) { // first layer is always fully opaque -> you can let that out // array of 3 x array of 64*64 chars: unpacked alpha values mcal[layer].layer = new byte[64 * 64]; // sorry, I have no god damn idea about c# // *x = value at x. x = pointer to data. ++x = advance üpointer a byte uint in_offset = 0; uint out_offset = 0; while (out_offset < 4096) { byte info = subbin.ReadByte(); ++in_offset; uint mode = (uint)(info & 0x80) >> 7; // 0 = copy, 1 = fill uint count = (uint)(info & 0x7f); // do mode operation count times if (mode != 0) { byte val = subbin.ReadByte(); ++in_offset; while (count --> 0 && out_offset < 4096) { mcal[layer].layer[out_offset] = val; ++out_offset; } } else // mode == 1 { while (count --> 0 && out_offset < 4096) { var val = subbin.ReadByte(); ++in_offset; mcal[layer].layer[out_offset] = val; ++out_offset; } } } read_offset += in_offset; if (out_offset != 4096) throw new Exception("we somehow overshoot. this should not be the case, except for broken adts"); } else if (wdt.mphd.flags.HasFlag(WoWFormatLib.Structs.WDT.mphdFlags.Flag_0x4) || wdt.mphd.flags.HasFlag(WoWFormatLib.Structs.WDT.mphdFlags.Flag_0x80)) { mcal[layer].layer = subbin.ReadBytes(4096); read_offset += 4096; } else { mcal[layer].layer = new byte[64 * 64]; //uncompressed_2048 var mcal_data = subbin.ReadBytes(2048); read_offset += 2048; for (int i = 0; i < 2048; ++i) { // maybe nibbles swapped mcal[layer].layer[2 * i + 0] = (byte) (((mcal_data[i] & 0x0F) >> 0) * 17); mcal[layer].layer[2 * i + 1] = (byte) (((mcal_data[i] & 0xF0) >> 4) * 17); } } } if (read_offset != subchunk.Size) throw new Exception("Haven't finished reading chunk but should be"); return mcal; /* var mcal = new MCAL(); var mphdFlag = false; var mclyFlag = false; if (wdt.mphd.flags.HasFlag(WoWFormatLib.Structs.WDT.mphdFlags.Flag_0x4)){ mphdFlag = true; } if (mapchunk.layers[0].flags.HasFlag(mclyFlags.Flag_0x200)){ mclyFlag = true; } mcal.alpha = new byte[64][]; if(!mphdFlag && !mclyFlag) { for(int x = 0; x < 64; x++) { mcal.alpha[x] = new byte[64]; for(int y = 0; y < 64; y++) { mcal.alpha[x][y] = subbin.ReadByte(); } } } else { throw new Exception("Unsupported MCAL detected!"); } return mcal; */ }
public TexMCNK ReadTexMCNKChunk(BlizzHeader chunk, BinaryReader bin) { //256 of these chunks per file TexMCNK mapchunk = new TexMCNK(); MemoryStream stream = new MemoryStream(bin.ReadBytes((int)chunk.Size)); var subbin = new BinaryReader(stream); BlizzHeader subchunk; long subpos = 0; while (subpos < stream.Length) { subbin.BaseStream.Position = subpos; subchunk = new BlizzHeader(subbin.ReadChars(4), subbin.ReadUInt32()); subchunk.Flip(); subpos = stream.Position + subchunk.Size; switch (subchunk.ToString()) { case "MCLY": mapchunk.layers = ReadMCLYSubChunk(subchunk, subbin); break; case "MCAL": mapchunk.alphaLayer = ReadMCALSubChunk(subchunk, subbin, mapchunk); break; case "MCSH": case "MCMT": continue; default: throw new Exception(String.Format("Found unknown header at offset {1} \"{0}\" while we should've already read them all!", subchunk.ToString(), subpos.ToString())); } } return mapchunk; }