private void SaveAlpha(BinaryWriter writer, int basePosition, ref Mcnk header) { header.Mcal = (int) writer.BaseStream.Position - basePosition; writer.Write(0x4D43414C); var sizePos = writer.BaseStream.Position; writer.Write(0); if(mLayers.Length == 0) { header.SizeAlpha = 8; return; } var curPos = 0; mLayers[0].Flags &= ~0x300u; mLayers[0].OfsMcal = 0; for(var i = 1; i < mLayers.Length; ++i) { bool compressed; var data = GetSavedAlphaForLayer(i, out compressed); mLayers[i].OfsMcal = curPos; if (compressed) mLayers[i].Flags |= 0x300; else { mLayers[i].Flags |= 0x100; mLayers[i].Flags &= ~0x200u; } writer.Write(data); curPos += data.Length; } var endPos = writer.BaseStream.Position; writer.BaseStream.Position = sizePos; writer.Write((int) (endPos - sizePos - 4)); writer.BaseStream.Position = endPos; header.SizeAlpha = curPos + 8; }
private void SaveUnusedChunks(BinaryWriter writer, int basePosition, ref Mcnk header) { int unusedSize; SaveUnusedChunk(writer, 0x4D435246, basePosition, out header.Mcrf, out unusedSize); SaveUnusedChunk(writer, 0x4D435348, basePosition, out header.Mcsh, out unusedSize); SaveUnusedChunk(writer, 0x4D435345, basePosition, out header.Mcse, out unusedSize); SaveUnusedChunk(writer, 0x4D434C51, basePosition, out header.Mclq, out unusedSize); SaveUnusedChunk(writer, 0x4D434C56, basePosition, out header.Mclv, out unusedSize); //header.NumSoundEmitters /= 0x1C; }
private void SaveLayers(BinaryWriter writer, int basePosition, ref Mcnk header) { header.NumLayers = mLayers.Length; if(header.NumLayers == 0) { header.Mcly = 0; return; } header.Mcly = (int) writer.BaseStream.Position - basePosition; writer.Write(0x4D434C59); writer.Write(mLayers.Length * SizeCache<Mcly>.Size); writer.WriteArray(mLayers); }
private void SaveMccv(BinaryWriter writer, int basePosition, ref Mcnk header) { if (HasMccv == false) { header.Mccv = 0; header.Flags &= ~0x40u; return; } header.Flags |= 0x40; var colors = mShadingFloats.Select(v => { uint b = (byte)Math.Max(Math.Min((v.Z / 2.0f) * 255.0f, 255), 0); uint g = (byte)Math.Max(Math.Min((v.Y / 2.0f) * 255.0f, 255), 0); uint r = (byte)Math.Max(Math.Min((v.X / 2.0f) * 255.0f, 255), 0); return 0x7F000000 | (b << 16) | (g << 8) | r; }).ToArray(); header.Mccv = (int)writer.BaseStream.Position - basePosition; writer.Write(0x4D434356); writer.Write(145 * 4); writer.WriteArray(colors.ToArray()); }
private void SaveNormals(BinaryWriter writer, int basePosition, ref Mcnk header) { header.Mcnr = (int)writer.BaseStream.Position - basePosition; var normals = Vertices.SelectMany(v => new[] { (sbyte)(v.Normal.X * -127.0f), (sbyte)(v.Normal.Y * -127.0f), (sbyte)(v.Normal.Z * 127.0f) }); writer.Write(0x4D434E52); writer.Write(145 * 3); writer.WriteArray(normals.ToArray()); writer.Write(mNormalExtra); }
private void SaveHeights(BinaryWriter writer, int basePosition, ref Mcnk header) { header.Mcvt = (int) writer.BaseStream.Position - basePosition; var minPos = Vertices.Min(v => v.Position.Z); header.Position.Z = minPos; var heights = Vertices.Select(v => v.Position.Z - minPos); writer.Write(0x4D435654); writer.Write(145 * 4); writer.WriteArray(heights.ToArray()); }
public bool AsyncLoad(BinaryReader reader, ChunkInfo chunkInfo) { // chunkInfo.Offset points to right after the MCNK signature, the offsets in the header are relative to the signature tho var basePosition = chunkInfo.Offset - 4; reader.BaseStream.Position = chunkInfo.Offset; reader.ReadInt32(); mHeader = reader.Read<Mcnk>(); reader.BaseStream.Position = basePosition + mHeader.Mcvt; var signature = reader.ReadUInt32(); reader.ReadInt32(); if (signature != 0x4D435654) { Log.Error("Chunk is missing valid MCVT sub chunk"); return false; } LoadMcvt(reader); reader.BaseStream.Position = basePosition + mHeader.Mcnr; signature = reader.ReadUInt32(); reader.ReadInt32(); if (signature != 0x4D434E52) { Log.Error("Chunk is missing valid MCNR sub chunk"); return false; } LoadMcnr(reader); if(mHeader.Mcrf > 0) { reader.BaseStream.Position = basePosition + mHeader.Mcrf; signature = reader.ReadUInt32(); var chunkSize = reader.ReadInt32(); if (signature == 0x4D435246) LoadReferences(reader, chunkSize); } var hasMccv = false; if (mHeader.Mccv != 0) { reader.BaseStream.Position = basePosition + mHeader.Mccv; signature = reader.ReadUInt32(); reader.ReadInt32(); if (signature == 0x4D434356) { LoadMccv(reader); hasMccv = true; HasMccv = true; } } reader.BaseStream.Position = basePosition + mHeader.Mcly; signature = reader.ReadUInt32(); var size = reader.ReadInt32(); if (signature != 0x4D434C59) return false; LoadLayers(reader, size); if (mHeader.SizeAlpha > 8) { reader.BaseStream.Position = basePosition + mHeader.Mcal; signature = reader.ReadUInt32(); if (signature == 0x4D43414C) { reader.ReadInt32(); mAlphaCompressed = reader.ReadBytes(mHeader.SizeAlpha - 8); } } InitLayerData(); if(mHeader.SizeShadow > 8 && mHeader.Mcsh > 0) { reader.BaseStream.Position = basePosition + mHeader.Mcsh + 8; var curPtr = 0; for (var i = 0; i < 64; ++i) { for (var j = 0; j < 8; ++j) { byte mask = reader.ReadByte(); for (var k = 0; k < 8; ++k) { AlphaValues[curPtr] &= 0xFFFFFF00; AlphaValues[curPtr++] |= ((mask & (1 << k)) == 0) ? (byte)0xFF : (byte)0xCC; } } } } if(mHeader.Mclv > 0) { reader.BaseStream.Position = basePosition + mHeader.Mclv + 8; var colors = reader.ReadArray<uint>(145); for (var i = 0; i < 145; ++i) Vertices[i].AdditiveColor = colors[i]; } LoadHoles(); if (hasMccv == false) { for (var i = 0; i < 145; ++i) Vertices[i].Color = 0x7F7F7F7F; } if (mHeader.Mcrf > 0) LoadUnusedChunk(0x4D435246, basePosition + mHeader.Mcrf, (mHeader.NumDoodadRefs + mHeader.NumMapObjRefs) * 4, reader); if (mHeader.SizeShadow > 0) LoadUnusedChunk(0x4D435348, basePosition + mHeader.Mcsh, mHeader.SizeShadow, reader); if (mHeader.NumSoundEmitters > 0) LoadUnusedChunk(0x4D435345, basePosition + mHeader.Mcse, mHeader.NumSoundEmitters * 0x1C, reader); if (mHeader.SizeLiquid > 8) LoadUnusedChunk(0x4D434C51, basePosition + mHeader.Mclq, mHeader.SizeLiquid - 8, reader); if (mHeader.Mclv > 0) LoadUnusedChunk(0x4D434C56, basePosition + mHeader.Mclv, 0, reader); WorldFrame.Instance.MapManager.OnLoadProgress(); return true; }