public long WriteTr3(BinaryWriterEx writer) { var meshOffset1 = writer.BaseStream.Position; writer.WriteBlock(Center); writer.Write(Radius); writer.Write(NumVertices); writer.WriteBlockArray(Vertices); writer.Write(NumNormals); if (NumNormals > 0) { writer.WriteBlockArray(Normals); } else if (NumNormals < 0) { writer.WriteBlockArray(Lights); } writer.Write(NumTexturedQuads); for (var k = 0; k < NumTexturedQuads; k++) { TexturedQuads[k].Write(writer); } // writer.WriteBlockArray(Meshes[i].TexturedRectangles); writer.Write(NumTexturedTriangles); for (var k = 0; k < NumTexturedTriangles; k++) { TexturedTriangles[k].Write(writer); } // writer.WriteBlockArray(Meshes[i].TexturedTriangles); writer.Write(NumColoredRectangles); //writer.WriteBlockArray(Meshes[i].ColoredRectangles); writer.Write(NumColoredTriangles); //writer.WriteBlockArray(Meshes[i].ColoredTriangles); var meshOffset2 = writer.BaseStream.Position; var meshSize = meshOffset2 - meshOffset1; if (meshSize % 4 != 0) { const ushort tempFiller = 0; writer.Write(tempFiller); meshSize += 2; } return(meshSize); }
public long WriteTr4AndTr5(BinaryWriterEx writer) { long meshOffset1 = writer.BaseStream.Position; writer.WriteBlock(Center); writer.Write(Radius); writer.Write(NumVertices); writer.WriteBlockArray(Vertices); writer.Write(NumNormals); if (NumNormals > 0) { writer.WriteBlockArray(Normals); } else if (NumNormals < 0) { writer.WriteBlockArray(Lights); } writer.Write(NumTexturedQuads); if (NumTexturedQuads != 0) { writer.WriteBlockArray(TexturedQuads); } writer.Write(NumTexturedTriangles); if (NumTexturedTriangles != 0) { writer.WriteBlockArray(TexturedTriangles); } var meshOffset2 = writer.BaseStream.Position; var meshSize = meshOffset2 - meshOffset1; if (meshSize % 4 != 0) { const ushort tempFiller = 0; writer.Write(tempFiller); meshSize += 2; } return(meshSize); }
public static bool DecryptLevel(string source, string target) { if (!File.Exists(source)) { return(false); } if (File.Exists(target)) { File.Delete(target); } File.Copy(source, target); bool result = false; var iStream = new FileStream(source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); var oStream = new FileStream(target, FileMode.Open, FileAccess.Write, FileShare.Read); var sr = new BinaryReaderEx(iStream); var sw = new BinaryWriterEx(oStream); try { sw.Seek(3, SeekOrigin.Begin); sw.Write((byte)0); sr.BaseStream.Seek(14, SeekOrigin.Begin); sw.BaseStream.Seek(14, SeekOrigin.Begin); uint size; byte[] header = new byte[_keyLength]; int chunk; for (chunk = 0; chunk < 4; ++chunk) { size = sr.ReadUInt32(); sr.ReadBlockArray(out header, _keyLength); sw.Seek(4, SeekOrigin.Current); sw.WriteBlockArray(Decrypt(header, (int)size >> (chunk + 5) & 0x0F, (int)size >> (chunk + 1) & 0x0F)); sw.BaseStream.Seek(size - _keyLength + sizeof(uint), SeekOrigin.Current); sr.BaseStream.Seek(size - _keyLength + sizeof(uint), SeekOrigin.Current); } result = true; } finally { sw.Close(); sr.Close(); oStream.Close(); iStream.Close(); } return(result); }
private void WriteLevelTr5Main() { // Now begin to compile the geometry block in a MemoryStream byte[] geometryDataBuffer; using (var geometryDataStream = new MemoryStream()) { var writer = new BinaryWriterEx(geometryDataStream); // Don't dispose ReportProgress(80, "Writing geometry data to memory buffer"); const int filler = 0; writer.Write(filler); var numRooms = (uint)_level.Rooms.Count(r => r != null); writer.Write(numRooms); foreach (var r in _level.Rooms.Where(r => r != null)) { _tempRooms[r].WriteTr5(writer); } // Write floordata var numFloorData = (uint)_floorData.Count; writer.Write(numFloorData); writer.WriteBlockArray(_floorData); // Write meshes var offset = writer.BaseStream.Position; const int numMeshData = 0; writer.Write(numMeshData); var totalMeshSize = 0; for (var i = 0; i < _meshes.Count; i++) { var meshSize = _meshes[i].WriteTr4AndTr5(writer); totalMeshSize += (int)meshSize; } var offset2 = writer.BaseStream.Position; // ReSharper disable once SuggestVarOrType_BuiltInTypes uint meshDataSize = (uint)((offset2 - offset - 4) / 2); // Save the size of the meshes writer.BaseStream.Seek(offset, SeekOrigin.Begin); writer.Write(meshDataSize); writer.BaseStream.Seek(offset2, SeekOrigin.Begin); // Write mesh pointers writer.Write((uint)_meshPointers.Count); writer.WriteBlockArray(_meshPointers); // Write animations' data writer.Write((uint)_animations.Count); foreach (var anim in _animations) { anim.Write(writer, _level); } writer.Write((uint)_stateChanges.Count); writer.WriteBlockArray(_stateChanges); writer.Write((uint)_animDispatches.Count); writer.WriteBlockArray(_animDispatches); writer.Write((uint)_animCommands.Count); writer.WriteBlockArray(_animCommands); writer.Write((uint)_meshTrees.Count); writer.WriteBlockArray(_meshTrees); writer.Write((uint)_frames.Count); writer.WriteBlockArray(_frames); writer.Write((uint)_moveables.Count); for (var k = 0; k < _moveables.Count; k++) { writer.WriteBlock(_moveables[k]); writer.Write((ushort)0xfeff); } writer.Write((uint)_staticMeshes.Count); writer.WriteBlockArray(_staticMeshes); // SPR block writer.WriteBlockArray(new byte[] { 0x53, 0x50, 0x52, 0x00 }); writer.Write((uint)_spriteTextures.Count); writer.WriteBlockArray(_spriteTextures); writer.Write((uint)_spriteSequences.Count); writer.WriteBlockArray(_spriteSequences); // Write camera, flyby and sound sources writer.Write((uint)_cameras.Count); writer.WriteBlockArray(_cameras); writer.Write((uint)_flyByCameras.Count); writer.WriteBlockArray(_flyByCameras); writer.Write((uint)_soundSources.Count); writer.WriteBlockArray(_soundSources); // Write pathfinding data writer.Write((uint)_boxes.Length); writer.WriteBlockArray(_boxes); writer.Write((uint)_overlaps.Length); writer.WriteBlockArray(_overlaps); for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone1_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone2_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone3_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone4_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].FlyZone_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone1_Alternate); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone2_Alternate); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone3_Alternate); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone4_Alternate); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].FlyZone_Alternate); } // Write animated textures _textureInfoManager.WriteAnimatedTextures(writer); // Write object textures writer.Write(checked ((byte)_textureInfoManager.UvRotateCount)); writer.Write(new byte[] { 0x54, 0x45, 0x58, 0x00 }); _textureInfoManager.WriteTextureInfos(writer, _level); // Write items and AI objects writer.Write((uint)_items.Count); writer.WriteBlockArray(_items); writer.Write((uint)_aiItems.Count); writer.WriteBlockArray(_aiItems); // Write sound meta data PrepareSoundsData(); WriteSoundMetadata(writer); // Finish it writer.Write((ushort)0xcdcd); writer.Write((ushort)0xcdcd); writer.Write((ushort)0xcdcd); geometryDataBuffer = geometryDataStream.ToArray(); } using (var fs = new FileStream(_dest, FileMode.Create, FileAccess.Write, FileShare.None)) { using (var writer = new BinaryWriterEx(fs)) { ReportProgress(90, "Writing final level"); writer.WriteBlockArray(new byte[] { 0x54, 0x52, 0x34, 0x00 }); ReportProgress(91, "Writing textures"); // The room texture tile count currently also currently contains the wad textures // But lets not bother with those fields too much since they only matter when bump maps are used and we don't use them. writer.Write((ushort)_textureInfoManager.NumRoomPages); writer.Write((ushort)_textureInfoManager.NumObjectsPages); // Bump map pages must be multiplied by 2 or tile index will be wrong writer.Write((ushort)(_textureInfoManager.NumBumpPages * 2)); // Compress data ReportProgress(95, "Compressing data"); byte[] texture32 = null; int texture32UncompressedSize = -1; byte[] texture16 = null; int texture16UncompressedSize = -1; byte[] textureMisc = null; int textureMiscUncompressedSize = -1; byte[] geometryData = geometryDataBuffer; int geometryDataUncompressedSize = geometryData.Length; using (Task Texture32task = Task.Factory.StartNew(() => { texture32 = ZLib.CompressData(_texture32Data); texture32UncompressedSize = _texture32Data.Length; })) using (Task Texture16task = Task.Factory.StartNew(() => { byte[] texture16Data = PackTextureMap32To16Bit(_texture32Data, _level.Settings); texture16 = ZLib.CompressData(texture16Data); texture16UncompressedSize = texture16Data.Length; })) using (Task textureMiscTask = Task.Factory.StartNew(() => { Stream textureMiscData = PrepareFontAndSkyTexture(); textureMisc = ZLib.CompressData(textureMiscData); textureMiscUncompressedSize = (int)textureMiscData.Length; })) Task.WaitAll(Texture32task, Texture16task, textureMiscTask); // Write data ReportProgress(97, "Writing compressed data to file."); writer.Write(texture32UncompressedSize); writer.Write(texture32.Length); writer.Write(texture32); writer.Write(texture16UncompressedSize); writer.Write(texture16.Length); writer.Write(texture16); writer.Write(textureMiscUncompressedSize); writer.Write(textureMisc.Length); writer.Write(textureMisc); writer.Write((ushort)_level.Settings.Tr5LaraType); writer.Write((ushort)_level.Settings.Tr5WeatherType); for (var i = 0; i < 28; i++) { writer.Write((byte)0); } // In TR5 geometry data is not compressed writer.Write(geometryDataUncompressedSize); writer.Write(geometryDataUncompressedSize); writer.Write(geometryData); ReportProgress(98, "Writing WAVE sounds"); WriteSoundData(writer); // Write extra data _volumeScripts = new List <VolumeScriptInstance>(); using (var ms = new MemoryStream()) { var chunkIO = new ChunkWriter(new byte[] { 0x54, 0x52, 0x35, 0x4D }, new BinaryWriterFast(ms)); int currRoom = 0; foreach (var r in _level.Rooms.Where(r => r != null)) { // Add further extra data conditions here, otherwise compiler will skip this room altogether if (r.Volumes.Count() > 0) { currRoom++; } else { currRoom++; continue; } using (var extraRoomDataChunk = chunkIO.WriteChunk(Tr5MainExtraRoomData)) { // First and only param after signature is internal room number chunkIO.Raw.Write(currRoom); using (var volumeListChunk = chunkIO.WriteChunk(Tr5MainChunkVolumeList)) { var trRoom = _tempRooms[r]; foreach (var vol in r.Volumes) { using (var volumeChunk = chunkIO.WriteChunk(Tr5MainChunkVolume)) { int scriptIndex = 0; if (_volumeScripts.Contains(vol.Scripts)) { scriptIndex = _volumeScripts.IndexOf(vol.Scripts); } else { _volumeScripts.Add(vol.Scripts); scriptIndex = _volumeScripts.Count - 1; } // FIXME is it needed? int add = 0; if (vol is BoxVolumeInstance) { add = (int)((vol as BoxVolumeInstance).Size.Y / 2.0f); } var X = (int)Math.Round(trRoom.Info.X + vol.Position.X); var Y = (int)-Math.Round(r.WorldPos.Y + vol.Position.Y + add); var Z = (int)Math.Round(trRoom.Info.Z + vol.Position.Z); if (vol is BoxVolumeInstance) { chunkIO.Raw.Write(0); } else if (vol is SphereVolumeInstance) { chunkIO.Raw.Write(1); } else if (vol is PrismVolumeInstance) { chunkIO.Raw.Write(2); } chunkIO.Raw.Write(X); chunkIO.Raw.Write(Y); chunkIO.Raw.Write(Z); chunkIO.Raw.Write((short)vol.Activators); chunkIO.Raw.Write(scriptIndex); if (vol is BoxVolumeInstance) { var bv = (BoxVolumeInstance)vol; var min = vol.Position - (bv.Size / 2.0f); var max = vol.Position + (bv.Size / 2.0f); var rotY = (ushort)Math.Max(0, Math.Min(ushort.MaxValue, Math.Round(bv.RotationY * (65536.0 / 360.0)))); var rotX = (ushort)Math.Max(0, Math.Min(ushort.MaxValue, Math.Round(bv.RotationX * (65536.0 / 360.0)))); chunkIO.Raw.Write(rotY); chunkIO.Raw.Write(rotX); chunkIO.Raw.Write((short)min.X); chunkIO.Raw.Write((short)min.Y); chunkIO.Raw.Write((short)min.Z); chunkIO.Raw.Write((short)max.X); chunkIO.Raw.Write((short)max.Y); chunkIO.Raw.Write((short)max.Z); } else if (vol is SphereVolumeInstance) { chunkIO.Raw.Write((vol as SphereVolumeInstance).Size); } else if (vol is PrismVolumeInstance) { var pv = (PrismVolumeInstance)vol; chunkIO.Raw.Write(pv.RotationY); chunkIO.Raw.Write(pv.Size); } } } } } } /* * using (var extraDataChunk = chunkIO.WriteChunk(Tr5MainExtraData)) * { * using (var volScriptListChunk = chunkIO.WriteChunk(Tr5MainChunkVolumeScriptList)) * { * for (int i = 0; i < _volumeScripts.Count; i++) * { * var script = _volumeScripts[i]; * using (var volScriptChunk = chunkIO.WriteChunk(Tr5MainChunkVolumeScript)) * { * chunkIO.Raw.WriteStringUTF8(script.Name); * * string onEnter = string.Empty; * string onInside = string.Empty; * string onLeave = string.Empty; * * if (script.OnEnter.Trim().Length > 0) * onEnter = "volscripts[" + i + "].OnEnter = function(activator) \n" + * _indent + script.OnEnter.Replace("\n", "\n" + _indent) + "\n" + "end;"; * * if (script.OnInside.Trim().Length > 0) * onInside = "volscripts[" + i + "].OnInside = function(activator) \n" + * _indent + script.OnInside.Replace("\n", "\n" + _indent) + "\n" + "end;"; * * if (script.OnLeave.Trim().Length > 0) * onLeave = "volscripts[" + i + "].OnLeave = function(activator) \n" + * _indent + script.OnLeave.Replace("\n", "\n" + _indent) + "\n" + "end;"; * * string functionCode = * onEnter + (string.IsNullOrEmpty(onEnter) ? string.Empty : "\n\n") + * onInside + (string.IsNullOrEmpty(onInside) ? string.Empty : "\n\n") + * onLeave + (string.IsNullOrEmpty(onLeave) ? string.Empty : "\n\n") ; * * chunkIO.Raw.WriteStringUTF8(functionCode); * } * } * } * * using (var chunkLuaIds = chunkIO.WriteChunk(Tr5MainChunkLuaIds)) * { * for (int i = 0; i < _luaIdToItems.Count; i++) * { * chunkIO.WriteChunk(Tr5MainChunkLuaId, () => * { * chunkIO.Raw.Write(_luaIdToItems.ElementAt(i).Key); * chunkIO.Raw.Write(_luaIdToItems.ElementAt(i).Value); * }); * } * } * } */ chunkIO.Raw.Flush(); writer.Write((int)(ms.Length + 4)); writer.Write((int)(ms.Length + 4)); writer.Write(ms.ToArray(), 0, (int)ms.Length); writer.Write((int)0); } ReportProgress(99, "Done"); } } }
private void WriteLevelTr3() { // Now begin to compile the geometry block in a MemoryStream using (var writer = new BinaryWriterEx(new FileStream(_dest, FileMode.Create, FileAccess.Write, FileShare.None))) { ReportProgress(80, "Writing geometry data to memory buffer"); // Write version writer.WriteBlockArray(new byte[] { 0x38, 0x00, 0x18, 0xFF }); /*using (var readerPalette = new BinaryReader(new FileStream("Editor\\Misc\\Palette.Tr3.bin", FileMode.Open, FileAccess.Write, FileShare.None))) * { * var palette = readerPalette.ReadBytes(1792); * // Write palette * writer.Write(palette); * }*/ // TODO: for now I write fake palette, they should be needed only for 8 bit textures for (var i = 0; i < 768; i++) { writer.Write((byte)0x00); } for (var i = 0; i < 1024; i++) { writer.Write((byte)0x00); } // Write textures int numTextureTiles = _texture32Data.GetLength(0) / (256 * 256 * 4); writer.Write(numTextureTiles); // TODO 8 bit textures (altough who uses 8 bit textures in 2018?) var fakeTextures = new byte[256 * 256 * numTextureTiles]; writer.Write(fakeTextures); // 16 bit textures byte[] texture16Data = PackTextureMap32To16Bit(_texture32Data, _level.Settings); writer.Write(texture16Data); const int filler = 0; writer.Write(filler); var numRooms = (ushort)_level.Rooms.Count(r => r != null); writer.Write(numRooms); long offset; long offset2; foreach (var r in _level.Rooms.Where(r => r != null)) { _tempRooms[r].WriteTr3(writer); } // Write floordata var numFloorData = (uint)_floorData.Count; writer.Write(numFloorData); writer.WriteBlockArray(_floorData); // Write meshes offset = writer.BaseStream.Position; const int numMeshData = 0; writer.Write(numMeshData); var totalMeshSize = 0; for (var i = 0; i < _meshes.Count; i++) { var meshSize = _meshes[i].WriteTr3(writer); totalMeshSize += (int)meshSize; } offset2 = writer.BaseStream.Position; uint meshDataSize = (uint)((offset2 - offset - 4) / 2); // Save the size of the meshes writer.BaseStream.Seek(offset, SeekOrigin.Begin); writer.Write(meshDataSize); writer.BaseStream.Seek(offset2, SeekOrigin.Begin); // Write mesh pointers writer.Write((uint)_meshPointers.Count); writer.WriteBlockArray(_meshPointers); // Write animations' data writer.Write((uint)_animations.Count); foreach (var anim in _animations) { anim.Write(writer, _level); } writer.Write((uint)_stateChanges.Count); writer.WriteBlockArray(_stateChanges); writer.Write((uint)_animDispatches.Count); writer.WriteBlockArray(_animDispatches); writer.Write((uint)_animCommands.Count); writer.WriteBlockArray(_animCommands); writer.Write((uint)_meshTrees.Count); writer.WriteBlockArray(_meshTrees); writer.Write((uint)_frames.Count); writer.WriteBlockArray(_frames); writer.Write((uint)_moveables.Count); writer.WriteBlockArray(_moveables); writer.Write((uint)_staticMeshes.Count); writer.WriteBlockArray(_staticMeshes); // Sprites writer.Write((uint)_spriteTextures.Count); writer.WriteBlockArray(_spriteTextures); writer.Write((uint)_spriteSequences.Count); writer.WriteBlockArray(_spriteSequences); // Write camera, sound sources writer.Write((uint)_cameras.Count); writer.WriteBlockArray(_cameras); writer.Write((uint)_soundSources.Count); writer.WriteBlockArray(_soundSources); // Write pathfinding data writer.Write((uint)_boxes.Length); writer.WriteBlockArray(_boxes); writer.Write((uint)_overlaps.Length); writer.WriteBlockArray(_overlaps); for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone1_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone2_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone3_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone4_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].FlyZone_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone1_Alternate); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone2_Alternate); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone3_Alternate); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone4_Alternate); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].FlyZone_Alternate); } // Write animated textures _textureInfoManager.WriteAnimatedTextures(writer); // Write object textures _textureInfoManager.WriteTextureInfos(writer, _level); // Write items and AI objects writer.Write((uint)_items.Count); writer.WriteBlockArray(_items); // TODO Figure out light map var lightmap = new byte[8192]; writer.Write(lightmap); const ushort numDemo = 0; const ushort numCinematicFrames = 0; writer.Write(numDemo); writer.Write(numCinematicFrames); // Write sound meta data PrepareSoundsData(); WriteSoundMetadata(writer); writer.Flush(); } }
public TestLevel(string fileName, string outFileName = "") { this.fileName = fileName; FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); BinaryReaderEx reader = new BinaryReaderEx(fileStream); byte[] buffer; reader.ReadBlock(out Version); reader.ReadBlock(out NumRoomTextureTiles); reader.ReadBlock(out NumObjectTextureTiles); reader.ReadBlock(out NumBumpTextureTiles); reader.ReadBlock(out Texture32UncompressedSize); reader.ReadBlock(out Texture32CompressedSize); Texture32 = new byte[Texture32CompressedSize]; reader.ReadBlockArray(out Texture32, Texture32CompressedSize); Texture32 = ZLib.DecompressData(Texture32); ImageC img = ImageC.FromByteArray(Texture32, 256, (int)Texture32UncompressedSize / 262144 * 256); //img.Save("H:\\karnak.png"); BinaryWriterEx wrttext = new BinaryWriterEx(new FileStream("textures.raw", FileMode.Create, FileAccess.Write, FileShare.None)); wrttext.WriteBlockArray(Texture32); wrttext.Flush(); wrttext.Close(); reader.ReadBlock(out Texture16UncompressedSize); reader.ReadBlock(out Texture16CompressedSize); Texture16 = new byte[Texture16CompressedSize]; reader.ReadBlockArray(out Texture16, Texture16CompressedSize); Texture16 = ZLib.DecompressData(Texture16); reader.ReadBlock(out MiscTextureUncompressedSize); reader.ReadBlock(out MiscTextureCompressedSize); MiscTexture = new byte[MiscTextureCompressedSize]; reader.ReadBlockArray(out MiscTexture, MiscTextureCompressedSize); MiscTexture = ZLib.DecompressData(MiscTexture); reader.ReadBlock(out LevelUncompressedSize); reader.ReadBlock(out LevelCompressedSize); buffer = new byte[LevelCompressedSize]; reader.ReadBlockArray(out buffer, LevelCompressedSize); buffer = ZLib.DecompressData(buffer); var stream = new MemoryStream(); stream.Write(buffer, 0, (int)LevelUncompressedSize); stream.Seek(0, SeekOrigin.Begin); BinaryWriterEx wrt = new BinaryWriterEx(new FileStream("coastal.bin", FileMode.Create, FileAccess.Write, FileShare.None)); wrt.Write(buffer, 0, (int)LevelUncompressedSize); wrt.Flush(); wrt.Close(); BinaryWriterEx wrs = new BinaryWriterEx(new FileStream("samples." + outFileName + ".bin", FileMode.Create, FileAccess.Write, FileShare.None)); byte[] samples = reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position)); wrs.Write(samples); wrs.Flush(); wrs.Close(); reader.Close(); reader = new BinaryReaderEx(stream); reader.ReadBlock(out Unused); reader.ReadBlock(out NumRooms); int max = 0; StreamWriter wp = new StreamWriter(new FileStream("portals" + outFileName + ".txt", FileMode.Create, FileAccess.Write, FileShare.None)); Rooms = new tr_room[NumRooms]; for (int i = 0; i < NumRooms; i++) { wp.WriteLine("====================================================================="); wp.WriteLine("ROOM #" + i); wp.WriteLine("====================================================================="); reader.ReadBlock(out Rooms[i].Info); reader.ReadBlock(out Rooms[i].NumDataWords); reader.ReadBlock(out Rooms[i].NumVertices); // Rooms[i].Vertices = new tr_room_vertex[Rooms[i].NumVertices]; reader.ReadBlockArray(out Rooms[i].Vertices, Rooms[i].NumVertices); if (Rooms[i].NumVertices > max) { max = Rooms[i].NumVertices; } reader.ReadBlock(out Rooms[i].NumRectangles); Rooms[i].Rectangles = new tr_face4[Rooms[i].NumRectangles]; for (int j = 0; j < Rooms[i].NumRectangles; j++) { // Rooms[i].Rectangles[j].Vertices = new ushort[4]; reader.ReadBlockArray(out Rooms[i].Rectangles[j].Vertices, 4); reader.ReadBlock(out Rooms[i].Rectangles[j].Texture); } reader.ReadBlock(out Rooms[i].NumTriangles); Rooms[i].Triangles = new tr_face3[Rooms[i].NumTriangles]; for (int j = 0; j < Rooms[i].NumTriangles; j++) { // Rooms[i].Triangles[j].Vertices = new ushort[3]; reader.ReadBlockArray(out Rooms[i].Triangles[j].Vertices, 3); reader.ReadBlock(out Rooms[i].Triangles[j].Texture); } reader.ReadBlock(out Rooms[i].NumSprites); reader.ReadBlock(out Rooms[i].NumPortals); //Rooms[i].Portals = new tr_room_portal[Rooms[i].NumPortals]; reader.ReadBlockArray(out Rooms[i].Portals, Rooms[i].NumPortals); for (int nn = 0; nn < Rooms[i].Portals.Length; nn++) { tr_room_portal pt = Rooms[i].Portals[nn]; wp.WriteLine(nn + ": "); wp.WriteLine("Room: " + pt.AdjoiningRoom); for (int vv = 0; vv < 4; vv++) { wp.Write("V" + vv + " = " + pt.Vertices[vv].X + ", " + pt.Vertices[vv].Y + ", " + pt.Vertices[vv].Z); wp.WriteLine(""); } wp.WriteLine(""); } reader.ReadBlock(out Rooms[i].NumZSectors); reader.ReadBlock(out Rooms[i].NumXSectors); //Rooms[i].Sectors = new tr_room_sector[Rooms[i].NumZSectors * Rooms[i].NumXSectors]; reader.ReadBlockArray(out Rooms[i].Sectors, (uint)Rooms[i].NumZSectors * Rooms[i].NumXSectors); reader.ReadBlock(out Rooms[i].AmbientIntensity1); reader.ReadBlock(out Rooms[i].AmbientIntensity2); reader.ReadBlock(out Rooms[i].NumLights); reader.ReadBlockArray(out Rooms[i].Lights, Rooms[i].NumLights); reader.ReadBlock(out Rooms[i].NumStaticMeshes); reader.ReadBlockArray(out Rooms[i].StaticMeshes, Rooms[i].NumStaticMeshes); reader.ReadBlock(out Rooms[i].AlternateRoom); reader.ReadBlock(out Rooms[i].Flags); reader.ReadBlock(out Rooms[i].Param1); reader.ReadBlock(out Rooms[i].Unknown1); reader.ReadBlock(out Rooms[i].Unknown2); } wp.Flush(); wp.Close(); //return; reader.ReadBlock(out NumFloorData); reader.ReadBlockArray(out FloorData, NumFloorData); reader.ReadBlock(out NumMeshData); /*for (int i = 0; i < NumFloorData; i++) * Console.WriteLine(FloorData[i].ToString("X2"));*/ int numBytes = 0; int totalBytes = 0; int l = 0; short temp = 0; Meshes = new tr_mesh[2048]; while (totalBytes < NumMeshData * 2) { long offset1 = reader.BaseStream.Position; reader.ReadBlock(out Meshes[l].Center); reader.ReadBlock(out Meshes[l].Radius); numBytes += 10; reader.ReadBlock(out Meshes[l].NumVertices); reader.ReadBlockArray(out Meshes[l].Vertices, Meshes[l].NumVertices); numBytes += 2 + 6 * Meshes[l].NumVertices; reader.ReadBlock(out Meshes[l].NumNormals); if (Meshes[l].NumNormals > 0) { reader.ReadBlockArray(out Meshes[l].Normals, Meshes[l].NumNormals); numBytes += 2 + 6 * Meshes[l].NumNormals; } else { reader.ReadBlockArray(out Meshes[l].Lights, -Meshes[l].NumNormals); numBytes += 2 - 2 * Meshes[l].NumNormals; } reader.ReadBlock(out Meshes[l].NumTexturedRectangles); reader.ReadBlockArray(out Meshes[l].TexturedRectangles, Meshes[l].NumTexturedRectangles); numBytes += 2 + 12 * Meshes[l].NumTexturedRectangles; reader.ReadBlock(out Meshes[l].NumTexturedTriangles); reader.ReadBlockArray(out Meshes[l].TexturedTriangles, Meshes[l].NumTexturedTriangles); numBytes += 2 + 10 * Meshes[l].NumTexturedTriangles; long offset2 = reader.BaseStream.Position; int diff = (int)(offset2 - offset1); if (diff % 4 != 0) { reader.ReadBlock(out temp); diff += 2; } Meshes[l].MeshSize = numBytes; Meshes[l].MeshPointer = totalBytes; if (l == 209) { BinaryWriterEx tmpwriter = new BinaryWriterEx(new FileStream("cleopal.msh", FileMode.Create, FileAccess.Write, FileShare.None)); tmpwriter.WriteBlock(Meshes[l].Center); tmpwriter.WriteBlock(Meshes[l].Radius); tmpwriter.WriteBlock(Meshes[l].NumVertices); tmpwriter.WriteBlockArray(Meshes[l].Vertices); tmpwriter.WriteBlock(Meshes[l].NumNormals); if (Meshes[l].NumNormals > 0) { tmpwriter.WriteBlockArray(Meshes[l].Normals); } else { tmpwriter.WriteBlockArray(Meshes[l].Lights); } tmpwriter.WriteBlock(Meshes[l].NumTexturedRectangles); tmpwriter.WriteBlockArray(Meshes[l].TexturedRectangles); tmpwriter.WriteBlock(Meshes[l].NumTexturedTriangles); tmpwriter.WriteBlockArray(Meshes[l].TexturedTriangles); tmpwriter.Flush(); tmpwriter.Close(); } totalBytes += diff;// numBytes; numBytes = 0; l++; } Array.Resize(ref Meshes, l); NumMeshes = (uint)Meshes.Length; reader.ReadBlock(out NumMeshPointers); reader.ReadBlockArray(out MeshPointers, NumMeshPointers); reader.ReadBlock(out NumAnimations); reader.ReadBlockArray(out Animations, NumAnimations); reader.ReadBlock(out NumStateChanges); reader.ReadBlockArray(out StateChanges, NumStateChanges); reader.ReadBlock(out NumAnimDispatches); reader.ReadBlockArray(out AnimDispatches, NumAnimDispatches); reader.ReadBlock(out NumAnimCommands); reader.ReadBlockArray(out AnimCommands, NumAnimCommands); reader.ReadBlock(out NumMeshTrees); reader.ReadBlockArray(out MeshTrees, NumMeshTrees); logger.Debug(reader.BaseStream.Position.ToString()); reader.ReadBlock(out NumFrames); reader.ReadBlockArray(out Frames, NumFrames); reader.ReadBlock(out NumMoveables); reader.ReadBlockArray(out Moveables, NumMoveables); reader.ReadBlock(out NumStaticMeshes); reader.ReadBlockArray(out StaticMeshes, NumStaticMeshes); reader.ReadBlockArray(out SPR, 3); reader.ReadBlock(out NumSpriteTextures); reader.ReadBlockArray(out SpriteTextures, NumSpriteTextures); reader.ReadBlock(out NumSpriteSequences); reader.ReadBlockArray(out SpriteSequences, NumSpriteSequences); reader.ReadBlock(out NumCameras); reader.ReadBlockArray(out Cameras, NumCameras); reader.ReadBlock(out NumFlyByCameras); reader.ReadBlockArray(out FlyByCameras, NumFlyByCameras * 40); reader.ReadBlock(out NumSoundSources); reader.ReadBlockArray(out SoundSources, NumSoundSources); reader.ReadBlock(out NumBoxes); reader.ReadBlockArray(out Boxes, NumBoxes); reader.ReadBlock(out NumOverlaps); reader.ReadBlockArray(out Overlaps, NumOverlaps); // reader.ReadBlockArray(out Zones, NumBoxes * 10); Zones = new short[NumBoxes * 10]; for (int n = 0; n < NumBoxes * 10; n++) { Zones[n] = reader.ReadInt16(); } reader.ReadBlock(out NumAnimatedTextures); short[] animTextures; reader.ReadBlockArray(out animTextures, NumAnimatedTextures); string fn = Path.GetFileNameWithoutExtension(fileName); if (File.Exists("pathfinding." + fn + "." + outFileName + ".txt")) { File.Delete("pathfinding." + fn + "." + outFileName + ".txt"); } StreamWriter writer = new StreamWriter(new FileStream("pathfinding." + fn + "." + outFileName + ".txt", FileMode.Create, FileAccess.Write, FileShare.None)); writer.WriteLine("BOXES"); for (int n = 0; n < Boxes.Length; n++) { writer.WriteLine("[" + n + "] " + "Xmin: " + Boxes[n].Xmin + ", " + "Xmax: " + Boxes[n].Xmax + ", " + "Zmin: " + Boxes[n].Zmin + ", " + "Zmax: " + Boxes[n].Zmax + ", " + "Floor: " + Boxes[n].TrueFloor + ", Overlap Index: " + Boxes[n].OverlapIndex); } writer.WriteLine(" "); writer.WriteLine("OVERLAPS"); for (int n = 0; n < Overlaps.Length; n++) { writer.WriteLine("[" + n + "] " + (Overlaps[n] & 0x7fff)); if ((Overlaps[n] & 0x8000) != 0) { writer.WriteLine("--- END OF LIST ---"); } } writer.WriteLine(" "); writer.WriteLine("ZONES"); for (int n = 0; n < Boxes.Length; n++) { /*writer.WriteLine("[" + n + "] " + "Ground1: " + Zones[n * 10 + 0] + ", " + "Ground2: " + Zones[n * 10 + 1] + ", " + * "Ground3: " + Zones[n * 10 + 2] + ", " + "Ground4: " + Zones[n * 10 + 3] + ", " + * "Fly: " + Zones[n * 10 + 4] + ", A_Ground1: " + Zones[n * 10 + 5] + ", " + "A_Ground2: " + Zones[n * 10 + 6] + ", " + * "A_Ground3: " + Zones[n * 10 + 7] + ", " + "A_Ground4: " + Zones[n * 10 + 8] + ", " + * "A_Fly: " + Zones[n * 10 + 9]);*/ writer.WriteLine("[" + n + "] " + "Ground1: " + Zones[n] + ", " + "Ground2: " + Zones[1 * NumBoxes + n] + ", " + "Ground3: " + Zones[2 * NumBoxes + n] + ", " + "Ground4: " + Zones[3 * NumBoxes + n] + ", " + "Fly: " + Zones[4 * NumBoxes + n] + ", A_Ground1: " + Zones[5 * NumBoxes + n] + ", " + "A_Ground2: " + Zones[6 * NumBoxes + n] + ", " + "A_Ground3: " + Zones[7 * NumBoxes + n] + ", " + "A_Ground4: " + Zones[8 * NumBoxes + n] + ", " + "A_Fly: " + Zones[9 * NumBoxes + n]); } writer.Flush(); writer.Close(); reader.ReadBlockArray(out TEX, 4); reader.ReadBlock(out NumObjectTextures); reader.ReadBlockArray(out ObjectTextures, NumObjectTextures); if (File.Exists("textures." + fn + "." + outFileName + ".txt")) { File.Delete("textures." + fn + "." + outFileName + ".txt"); } writer = new StreamWriter(new FileStream("textures." + fn + "." + outFileName + ".txt", FileMode.Create, FileAccess.Write, FileShare.None)); for (int ii = 0; ii < NumObjectTextures; ii++) { writer.WriteLine("TEXTURE #" + ii); writer.WriteLine(" TileAndFlags: " + (ObjectTextures[ii].Tile).ToString()); writer.WriteLine(" NewFlags: " + (ObjectTextures[ii].Flags).ToString()); writer.WriteLine(" Tile: " + (ObjectTextures[ii].Tile & 0xFF).ToString()); for (int jj = 0; jj < 4; jj++) { writer.WriteLine(" " + jj + " X: " + ((ushort)(ObjectTextures[ii].Vertices[jj].Xpixel << 8 + ObjectTextures[ii].Vertices[jj].Xcoordinate)).ToString() + " Y: " + ((ushort)(ObjectTextures[ii].Vertices[jj].Ypixel << 8 + ObjectTextures[ii].Vertices[jj].Ycoordinate)).ToString() + " (" + ObjectTextures[ii].Vertices[jj].Xpixel + ", " + ObjectTextures[ii].Vertices[jj].Ypixel + ")"); } /* BinaryWriterEx tmpwriter2 = new BinaryWriterEx(new FileStream("test\\cleopal_" + ii + ".text", FileMode.Create, FileAccess.Write, FileShare.None)); * tmpwriter2.WriteBlock(ObjectTextures[ii]); * tmpwriter2.Flush(); * tmpwriter2.Close();*/ } writer.Flush(); writer.Close(); reader.ReadBlock(out NumItems); reader.ReadBlockArray(out Items, NumItems); reader.ReadBlock(out NumAiItems); reader.ReadBlockArray(out AiItems, NumAiItems); StreamWriter aiw = new StreamWriter(new FileStream("AI" + outFileName + ".txt", FileMode.Create, FileAccess.Write, FileShare.None)); for (int n = 0; n < NumAiItems; n++) { aiw.WriteLine("[" + n + "]"); aiw.WriteLine(" ObjectID: " + AiItems[n].ObjectID); aiw.WriteLine(" X: " + AiItems[n].X); aiw.WriteLine(" Y: " + AiItems[n].Y); aiw.WriteLine(" Z: " + AiItems[n].Z); aiw.WriteLine(" Room: " + AiItems[n].Room); aiw.WriteLine(" Angle: " + AiItems[n].Angle); } aiw.Flush(); aiw.Close(); BinaryWriterEx bwex = new BinaryWriterEx(new FileStream("sounds" + outFileName + ".sfx", FileMode.Create, FileAccess.Write, FileShare.None)); var numDemo = reader.ReadInt16(); byte[] soundmap = reader.ReadBytes((numDemo != 0 ? numDemo * 2 : 740)); int numSoundDetails = reader.ReadInt32(); byte[] details = reader.ReadBytes(8 * numSoundDetails); int numIndices = reader.ReadInt32(); byte[] indices = reader.ReadBytes(4 * numIndices); bwex.Write(soundmap); bwex.Write(numSoundDetails); bwex.Write(details); bwex.Write(numIndices); bwex.Write(indices); bwex.Flush(); bwex.Close(); List <byte> bytes = new List <byte>(); while (reader.BaseStream.Position < reader.BaseStream.Length) { bytes.Add(reader.ReadByte()); } }
private void WriteLevelTr2() { // Now begin to compile the geometry block in a MemoryStream using (var writer = new BinaryWriterEx(new FileStream(_dest, FileMode.Create, FileAccess.Write, FileShare.None))) { ReportProgress(80, "Writing geometry data to memory buffer"); // Write version writer.WriteBlockArray(new byte[] { 0x2D, 0x00, 0x00, 0x00 }); // TODO: for now I write fake palette, they should be needed only for 8 bit textures tr_color[] palette8 = new tr_color[256]; //Following colors have hardcoded meaning in TR2 // https://github.com/Arsunt/TR2Main/blob/0586ba8965fc3c260080d9e6ea05f3e17033ba4b/global/types.h#L931 palette8[1] = new tr_color() { Red = 128, Green = 128, Blue = 128 }; palette8[2] = new tr_color() { Red = 255, Green = 255, Blue = 255 }; palette8[3] = new tr_color() { Red = 255, Green = 0, Blue = 0 }; palette8[4] = new tr_color() { Red = 255, Green = 165, Blue = 0 }; palette8[5] = new tr_color() { Red = 255, Green = 255, Blue = 0 }; palette8[12] = new tr_color() { Red = 0, Green = 128, Blue = 0 }; palette8[13] = new tr_color() { Red = 0, Green = 255, Blue = 0 }; palette8[14] = new tr_color() { Red = 0, Green = 255, Blue = 255 }; palette8[14] = new tr_color() { Red = 0, Green = 0, Blue = 255 }; palette8[15] = new tr_color() { Red = 255, Green = 0, Blue = 255 }; foreach (tr_color c in palette8) { c.write(writer); } for (var i = 0; i < 1024; i++) { writer.Write((byte)0x00); } // Write textures int numTextureTiles = _texture32Data.GetLength(0) / (256 * 256 * 4); writer.Write(numTextureTiles); // TODO 8 bit textures (altough who uses 8 bit textures in 2018?) var fakeTextures = new byte[256 * 256 * numTextureTiles]; writer.Write(fakeTextures); // 16 bit textures byte[] texture16Data = PackTextureMap32To16Bit(_texture32Data, _level.Settings); writer.Write(texture16Data); const int filler = 0; writer.Write(filler); var numRooms = (ushort)_level.Rooms.Count(r => r != null); writer.Write(numRooms); long offset; long offset2; foreach (var r in _level.Rooms.Where(r => r != null)) { _tempRooms[r].WriteTr2(writer); } // Write floordata var numFloorData = (uint)_floorData.Count; writer.Write(numFloorData); writer.WriteBlockArray(_floorData); // Write meshes offset = writer.BaseStream.Position; const int numMeshData = 0; writer.Write(numMeshData); var totalMeshSize = 0; for (var i = 0; i < _meshes.Count; i++) { var meshSize = _meshes[i].WriteTr3(writer); totalMeshSize += (int)meshSize; } offset2 = writer.BaseStream.Position; uint meshDataSize = (uint)((offset2 - offset - 4) / 2); // Save the size of the meshes writer.BaseStream.Seek(offset, SeekOrigin.Begin); writer.Write(meshDataSize); writer.BaseStream.Seek(offset2, SeekOrigin.Begin); // Write mesh pointers writer.Write((uint)_meshPointers.Count); writer.WriteBlockArray(_meshPointers); // Write animations' data writer.Write((uint)_animations.Count); foreach (var anim in _animations) { anim.Write(writer, _level); } writer.Write((uint)_stateChanges.Count); writer.WriteBlockArray(_stateChanges); writer.Write((uint)_animDispatches.Count); writer.WriteBlockArray(_animDispatches); writer.Write((uint)_animCommands.Count); writer.WriteBlockArray(_animCommands); writer.Write((uint)_meshTrees.Count); writer.WriteBlockArray(_meshTrees); writer.Write((uint)_frames.Count); writer.WriteBlockArray(_frames); writer.Write((uint)_moveables.Count); writer.WriteBlockArray(_moveables); writer.Write((uint)_staticMeshes.Count); writer.WriteBlockArray(_staticMeshes); // Write object textures _textureInfoManager.WriteTextureInfos(writer, _level); // Sprites writer.Write((uint)_spriteTextures.Count); writer.WriteBlockArray(_spriteTextures); writer.Write((uint)_spriteSequences.Count); writer.WriteBlockArray(_spriteSequences); // Write camera, sound sources writer.Write((uint)_cameras.Count); writer.WriteBlockArray(_cameras); writer.Write((uint)_soundSources.Count); writer.WriteBlockArray(_soundSources); // Write pathfinding data writer.Write((uint)_boxes.Length); writer.WriteBlockArray(_boxes); writer.Write((uint)_overlaps.Length); writer.WriteBlockArray(_overlaps); for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone1_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone2_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone3_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone4_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].FlyZone_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone1_Alternate); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone2_Alternate); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone3_Alternate); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone4_Alternate); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].FlyZone_Alternate); } // Write animated textures _textureInfoManager.WriteAnimatedTextures(writer); // Write items and AI objects writer.Write((uint)_items.Count); writer.WriteBlockArray(_items); // TODO Figure out light map var lightmap = new byte[8192]; writer.Write(lightmap); const ushort numDemo = 0; const ushort numCinematicFrames = 0; writer.Write(numDemo); writer.Write(numCinematicFrames); // Write sound meta data PrepareSoundsData(); WriteSoundMetadata(writer); } }
private void WriteLevelTr4(string ngVersion = null) { // Now begin to compile the geometry block in a MemoryStream byte[] geometryDataBuffer; using (var geometryDataStream = new MemoryStream()) { var writer = new BinaryWriterEx(geometryDataStream); // Don't dispose ReportProgress(80, "Writing geometry data to memory buffer"); const int filler = 0; writer.Write(filler); var numRooms = (ushort)_level.Rooms.Count(r => r != null); writer.Write(numRooms); foreach (var r in _level.Rooms.Where(r => r != null)) { _tempRooms[r].WriteTr4(writer); } // Write floordata var numFloorData = (uint)_floorData.Count; writer.Write(numFloorData); writer.WriteBlockArray(_floorData); // Write meshes var offset = writer.BaseStream.Position; const int numMeshData = 0; writer.Write(numMeshData); var totalMeshSize = 0; for (var i = 0; i < _meshes.Count; i++) { var meshSize = _meshes[i].WriteTr4AndTr5(writer); totalMeshSize += (int)meshSize; } var offset2 = writer.BaseStream.Position; // ReSharper disable once SuggestVarOrType_BuiltInTypes uint meshDataSize = (uint)((offset2 - offset - 4) / 2); // Save the size of the meshes writer.BaseStream.Seek(offset, SeekOrigin.Begin); writer.Write(meshDataSize); writer.BaseStream.Seek(offset2, SeekOrigin.Begin); // Write mesh pointers writer.Write((uint)_meshPointers.Count); writer.WriteBlockArray(_meshPointers); // Write animations' data writer.Write((uint)_animations.Count); foreach (var anim in _animations) { anim.Write(writer, _level); } writer.Write((uint)_stateChanges.Count); writer.WriteBlockArray(_stateChanges); writer.Write((uint)_animDispatches.Count); writer.WriteBlockArray(_animDispatches); writer.Write((uint)_animCommands.Count); writer.WriteBlockArray(_animCommands); writer.Write((uint)_meshTrees.Count); writer.WriteBlockArray(_meshTrees); writer.Write((uint)_frames.Count); writer.WriteBlockArray(_frames); writer.Write((uint)_moveables.Count); writer.WriteBlockArray(_moveables); writer.Write((uint)_staticMeshes.Count); writer.WriteBlockArray(_staticMeshes); // SPR block writer.WriteBlockArray(new byte[] { 0x53, 0x50, 0x52 }); writer.Write((uint)_spriteTextures.Count); writer.WriteBlockArray(_spriteTextures); writer.Write((uint)_spriteSequences.Count); writer.WriteBlockArray(_spriteSequences); // Write camera, flyby and sound sources writer.Write((uint)_cameras.Count); writer.WriteBlockArray(_cameras); writer.Write((uint)_flyByCameras.Count); writer.WriteBlockArray(_flyByCameras); writer.Write((uint)_soundSources.Count); writer.WriteBlockArray(_soundSources); // Write pathfinding data writer.Write((uint)_boxes.Length); writer.WriteBlockArray(_boxes); writer.Write((uint)_overlaps.Length); writer.WriteBlockArray(_overlaps); for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone1_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone2_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone3_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone4_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].FlyZone_Normal); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone1_Alternate); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone2_Alternate); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone3_Alternate); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].GroundZone4_Alternate); } for (var i = 0; i < _boxes.Length; i++) { writer.Write(_zones[i].FlyZone_Alternate); } // Write animated textures _textureInfoManager.WriteAnimatedTextures(writer); // Write object textures writer.Write(checked ((byte)_textureInfoManager.UvRotateCount)); writer.Write(new byte[] { 0x54, 0x45, 0x58 }); _textureInfoManager.WriteTextureInfos(writer, _level); // Write items and AI objects writer.Write((uint)_items.Count); writer.WriteBlockArray(_items); writer.Write((uint)_aiItems.Count); writer.WriteBlockArray(_aiItems); // Write sound meta data PrepareSoundsData(); WriteSoundMetadata(writer); // Finish it writer.Write((short)0); writer.Write((short)0); writer.Write((short)0); geometryDataBuffer = geometryDataStream.ToArray(); } using (var writer = new BinaryWriterEx(new FileStream(_dest, FileMode.Create, FileAccess.Write, FileShare.None))) { ReportProgress(90, "Writing final level"); writer.WriteBlockArray(new byte[] { 0x54, 0x52, 0x34, 0x00 }); ReportProgress(91, "Writing textures"); writer.Write((ushort)_textureInfoManager.NumRoomPages); writer.Write((ushort)_textureInfoManager.NumObjectsPages); // Bump map pages must be multiplied by 2 or tile index will be wrong writer.Write((ushort)(_textureInfoManager.NumBumpPages * 2)); // Compress data ReportProgress(95, "Compressing data"); byte[] texture32 = null; int texture32UncompressedSize = -1; byte[] texture16 = null; int texture16UncompressedSize = -1; byte[] textureMisc = null; int textureMiscUncompressedSize = -1; byte[] geometryData = null; int geometryDataUncompressedSize = -1; using (Task Texture32task = Task.Factory.StartNew(() => { texture32 = ZLib.CompressData(_texture32Data); texture32UncompressedSize = _texture32Data.Length; })) using (Task Texture16task = Task.Factory.StartNew(() => { byte[] texture16Data = PackTextureMap32To16Bit(_texture32Data, _level.Settings); texture16 = ZLib.CompressData(texture16Data); texture16UncompressedSize = texture16Data.Length; })) using (Task textureMiscTask = Task.Factory.StartNew(() => { Stream textureMiscData = PrepareFontAndSkyTexture(); textureMisc = ZLib.CompressData(textureMiscData); textureMiscUncompressedSize = (int)textureMiscData.Length; })) using (Task GeometryDataTask = Task.Factory.StartNew(() => { geometryData = ZLib.CompressData(geometryDataBuffer); geometryDataUncompressedSize = geometryDataBuffer.Length; })) Task.WaitAll(Texture32task, Texture16task, textureMiscTask, GeometryDataTask); // Write data ReportProgress(96, "Writing compressed data to file."); writer.Write(texture32UncompressedSize); writer.Write(texture32.Length); writer.Write(texture32); writer.Write(texture16UncompressedSize); writer.Write(texture16.Length); writer.Write(texture16); writer.Write(textureMiscUncompressedSize); writer.Write(textureMisc.Length); writer.Write(textureMisc); writer.Write(geometryDataUncompressedSize); writer.Write(geometryData.Length); writer.Write(geometryData); ReportProgress(97, "Writing WAVE sounds"); WriteSoundData(writer); // Write NG header if (!string.IsNullOrEmpty(ngVersion)) { ReportProgress(98, "Writing NG header"); WriteNgHeader(writer, ngVersion); } ReportProgress(99, "Done"); } }
public void WriteTr5(BinaryWriterEx writer) { var roomStartOffset = writer.BaseStream.Position; var xela = System.Text.Encoding.ASCII.GetBytes("XELA"); writer.Write(xela); var startOfRoomPosition = writer.BaseStream.Position; var roomDataSize = 0; writer.Write((uint)roomDataSize); var separator = 0xcdcdcdcd; writer.Write(separator); var EndSDOffsetPosition = writer.BaseStream.Position; var EndSDOffset = (uint)0; writer.Write(EndSDOffset); var StartOfSDOffsetPosition = writer.BaseStream.Position; var StartOfSDOffset = (uint)0; writer.Write(StartOfSDOffset); writer.Write(separator); var EndPortalOffsetPosition = writer.BaseStream.Position; var EndPortalOffset = (uint)0; writer.Write(EndPortalOffset); // tr5_room_info writer.Write(Info.X); writer.Write(0); writer.Write(Info.Z); writer.Write(Info.YBottom); writer.Write(Info.YTop); writer.Write(NumZSectors); writer.Write(NumXSectors); writer.Write(AmbientIntensity); writer.Write((ushort)Lights.Count); writer.Write((ushort)StaticMeshes.Count); writer.Write(ReverbInfo); writer.Write(AlternateGroup); writer.Write(WaterScheme); writer.Write((byte)0); writer.Write((uint)0x00007fff); writer.Write((uint)0x00007fff); writer.Write(0xcdcdcdcd); writer.Write(0xcdcdcdcd); writer.Write(0xffffffff); writer.Write(AlternateRoom); writer.Write(Flags); writer.Write((ushort)0xffff); writer.Write((ushort)0); writer.Write((uint)0); writer.Write((uint)0); writer.Write(0xcdcdcdcd); writer.Write((uint)0); writer.Write((float)Info.X); writer.Write((float)Info.YBottom); writer.Write((float)Info.Z); writer.Write(0xcdcdcdcd); writer.Write(0xcdcdcdcd); writer.Write(0xcdcdcdcd); writer.Write(0xcdcdcdcd); writer.Write((uint)0); writer.Write(0xcdcdcdcd); writer.Write((uint)Triangles.Count); writer.Write((uint)Quads.Count); writer.Write((uint)0); writer.Write((uint)(Lights.Count * 88)); writer.Write((uint)Lights.Count); writer.Write((uint)0); writer.Write(Info.YTop); writer.Write(Info.YBottom); writer.Write((uint)1); var LayerOffsetPosition = writer.BaseStream.Position; var LayerOffset = 0; writer.Write(LayerOffset); var VerticesOffsetPosition = writer.BaseStream.Position; var VerticesOffset = 0; writer.Write(VerticesOffset); var PolyOffsetPosition = writer.BaseStream.Position; var PolyOffset = 0; writer.Write(PolyOffset); writer.Write(PolyOffset); writer.Write((uint)(Vertices.Count * 28)); writer.Write(0xcdcdcdcd); writer.Write(0xcdcdcdcd); writer.Write(0xcdcdcdcd); writer.Write(0xcdcdcdcd); // Start of room data (after 216 bytes from XELA) foreach (var light in Lights) { writer.Write((float)light.X); writer.Write((float)light.Y); writer.Write((float)light.Z); writer.Write(light.Color.Red / 255.0f); writer.Write(light.Color.Green / 255.0f); writer.Write(light.Color.Blue / 255.0f); writer.Write(0xcdcdcdcd); writer.Write(light.In); writer.Write(light.Out); writer.Write((float)(light.LightType == 2 ? Math.Acos(light.In) * 2.0f : 0)); writer.Write((float)(light.LightType == 2 ? Math.Acos(light.Out) * 2.0f : 0)); writer.Write(light.CutOff); writer.Write(light.DirectionX); writer.Write(light.DirectionY); writer.Write(light.DirectionZ); writer.Write(light.X); writer.Write(light.Y); writer.Write(light.Z); writer.Write((int)light.DirectionX); writer.Write((int)light.DirectionY); writer.Write((int)light.DirectionZ); writer.Write(light.LightType); writer.Write((byte)0xcd); writer.Write((byte)0xcd); writer.Write((byte)0xcd); } StartOfSDOffset = (uint)(writer.BaseStream.Position - roomStartOffset - 216); writer.WriteBlockArray(Sectors); EndSDOffset = (uint)(StartOfSDOffset + NumXSectors * NumZSectors * 8); writer.Write((ushort)Portals.Count); if (Portals.Count != 0) { writer.WriteBlockArray(Portals); } writer.Write((ushort)0xcdcd); EndPortalOffset = (uint)(writer.BaseStream.Position - roomStartOffset - 216); if (StaticMeshes.Count != 0) { writer.WriteBlockArray(StaticMeshes); } LayerOffset = (int)(writer.BaseStream.Position - roomStartOffset - 216); // Write just one layer writer.Write((uint)Vertices.Count); writer.Write((ushort)0); writer.Write((ushort)Quads.Count); writer.Write((ushort)Triangles.Count); writer.Write((ushort)0); writer.Write((ushort)0); writer.Write((ushort)0); writer.Write(1024.0f); writer.Write((float)Info.YBottom); writer.Write(1024.0f); writer.Write((NumXSectors - 1) * 1024.0f); writer.Write((float)Info.YTop); writer.Write((NumZSectors - 1) * 1024.0f); writer.Write((uint)0); var LayerVerticesOffset = writer.BaseStream.Position; writer.Write((uint)0); var LayerPolygonsOffset = writer.BaseStream.Position; writer.Write((uint)0); writer.Write((uint)0); PolyOffset = LayerOffset + 56; for (var k = 0; k < Quads.Count; k++) { Quads[k].Write(writer); writer.Write((ushort)0); } for (var k = 0; k < Triangles.Count; k++) { Triangles[k].Write(writer); writer.Write((ushort)0); } if (Triangles.Count % 2 != 0) { writer.Write((ushort)0xcdcd); } VerticesOffset = (int)(writer.BaseStream.Position - roomStartOffset - 216); foreach (var vertex in Vertices) { writer.Write((float)vertex.Position.X); writer.Write((float)vertex.Position.Y); writer.Write((float)vertex.Position.Z); writer.Write((float)vertex.Normal.X); writer.Write((float)vertex.Normal.Y); writer.Write((float)vertex.Normal.Z); writer.Write(vertex.Color); } var endOfRoomOffset = writer.BaseStream.Position; roomDataSize = (int)(endOfRoomOffset - roomStartOffset - 8); writer.Seek((int)startOfRoomPosition, SeekOrigin.Begin); writer.Write(roomDataSize); writer.Seek((int)EndSDOffsetPosition, SeekOrigin.Begin); writer.Write((int)EndSDOffset); writer.Write((int)StartOfSDOffset); writer.Seek((int)EndPortalOffsetPosition, SeekOrigin.Begin); writer.Write((int)EndPortalOffset); writer.Seek((int)LayerOffsetPosition, SeekOrigin.Begin); writer.Write(LayerOffset); writer.Write(VerticesOffset); writer.Write(PolyOffset); writer.Write(PolyOffset); writer.Seek((int)LayerVerticesOffset, SeekOrigin.Begin); writer.Write(VerticesOffset); writer.Write(PolyOffset); writer.Write(PolyOffset); writer.Seek((int)endOfRoomOffset, SeekOrigin.Begin); }
public void WriteTr4(BinaryWriterEx writer) { writer.WriteBlock(Info); var offset = writer.BaseStream.Position; writer.Write(0); writer.Write((ushort)Vertices.Count); for (var k = 0; k < Vertices.Count; k++) { writer.Write(Vertices[k].Position.X); writer.Write(Vertices[k].Position.Y); writer.Write(Vertices[k].Position.Z); writer.Write(Vertices[k].Lighting1); writer.Write(Vertices[k].Attributes); writer.Write(Vertices[k].Lighting2); } writer.Write((ushort)Quads.Count); for (var k = 0; k < Quads.Count; k++) { Quads[k].Write(writer); } writer.Write((ushort)Triangles.Count); for (var k = 0; k < Triangles.Count; k++) { Triangles[k].Write(writer); } // For sprites, not used writer.Write((ushort)0); // Now save current offset and calculate the size of the geometry var offset2 = writer.BaseStream.Position; // ReSharper disable once SuggestVarOrType_BuiltInTypes ushort roomGeometrySize = (ushort)((offset2 - offset - 4) / 2); // Save the size of the geometry writer.BaseStream.Seek(offset, SeekOrigin.Begin); writer.Write(roomGeometrySize); writer.BaseStream.Seek(offset2, SeekOrigin.Begin); // Write portals writer.WriteBlock((ushort)Portals.Count); if (Portals.Count != 0) { writer.WriteBlockArray(Portals); } // Write sectors writer.Write(NumZSectors); writer.Write(NumXSectors); writer.WriteBlockArray(Sectors); // Write room color writer.Write(AmbientIntensity); // Write lights writer.WriteBlock((ushort)Lights.Count); if (Lights.Count != 0) { writer.WriteBlockArray(Lights); } // Write static meshes writer.WriteBlock((ushort)StaticMeshes.Count); if (StaticMeshes.Count != 0) { writer.WriteBlockArray(StaticMeshes); } // Write final data writer.Write(AlternateRoom); writer.Write(Flags); writer.Write(WaterScheme); writer.Write(ReverbInfo); writer.Write(AlternateGroup); }
public void WriteTr3(BinaryWriterEx writer) { writer.WriteBlock(Info); var offset = writer.BaseStream.Position; writer.Write(0); writer.Write((ushort)Vertices.Count); for (var k = 0; k < Vertices.Count; k++) { writer.Write(Vertices[k].Position.X); writer.Write(Vertices[k].Position.Y); writer.Write(Vertices[k].Position.Z); writer.Write(Vertices[k].Lighting1); writer.Write(Vertices[k].Attributes); writer.Write(Vertices[k].Lighting2); } writer.Write((ushort)Quads.Count); for (var k = 0; k < Quads.Count; k++) { Quads[k].Write(writer); } writer.Write((ushort)Triangles.Count); for (var k = 0; k < Triangles.Count; k++) { Triangles[k].Write(writer); } // For sprites, not used writer.Write((ushort)0); // Now save current offset and calculate the size of the geometry var offset2 = writer.BaseStream.Position; // ReSharper disable once SuggestVarOrType_BuiltInTypes ushort roomGeometrySize = (ushort)((offset2 - offset - 4) / 2); // Save the size of the geometry writer.BaseStream.Seek(offset, SeekOrigin.Begin); writer.Write(roomGeometrySize); writer.BaseStream.Seek(offset2, SeekOrigin.Begin); // Write portals writer.WriteBlock((ushort)Portals.Count); if (Portals.Count != 0) { writer.WriteBlockArray(Portals); } // Write sectors writer.Write(NumZSectors); writer.Write(NumXSectors); writer.WriteBlockArray(Sectors); // Write room color writer.Write((ushort)(AmbientIntensity)); // Light mode is broken in TR3 writer.Write((ushort)0x00); // Write lights writer.WriteBlock((ushort)Lights.Count); if (Lights.Count != 0) { foreach (var light in Lights) { writer.Write(light.X); writer.Write(light.Y); writer.Write(light.Z); writer.Write(light.Color.Red); writer.Write(light.Color.Green); writer.Write(light.Color.Blue); writer.Write(light.LightType); if (light.LightType == 0) // FIXME: TR3 sun type - UNKNOWN NORMALS FORMAT! { writer.Write((ushort)(light.X + (light.DirectionX * 1024.0f))); writer.Write((ushort)(light.Y + (light.DirectionY * 1024.0f))); writer.Write((ushort)(light.Z + (light.DirectionZ * 1024.0f))); writer.Write((ushort)0x0000); // Padding } else { writer.Write((uint)light.Intensity); writer.Write((uint)light.Out); } } } // Write static meshes writer.WriteBlock((ushort)StaticMeshes.Count); if (StaticMeshes.Count != 0) { writer.WriteBlockArray(StaticMeshes); } // Write final data writer.Write(AlternateRoom); writer.Write(Flags); writer.Write(WaterScheme); writer.Write(ReverbInfo); writer.Write((byte)0x00); // Alternate group was introduced in TR4 }