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); }
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"); } } }
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 WriteLevelTr5() { AddNecessaryTr5Items(); // 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 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"); // 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); ReportProgress(99, "Done"); } }
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 }
private void WriteSoundMetadata(BinaryWriter writer) { if (_level.Settings.GameVersion > TRVersion.Game.TR3) { // In TRNG and TR5Main NumDemoData is used as sound map size writer.Write((ushort)(_level.Settings.GameVersion == TRVersion.Game.TRNG || _level.Settings.GameVersion == TRVersion.Game.TR5Main ? _soundMapSize : 0)); } using (var ms = new MemoryStream()) { using (var bw = new BinaryWriterEx(ms)) { // Write soundmap to level file for (int i = 0; i < _finalSoundMap.Length; i++) { bw.Write(_finalSoundMap[i]); } // Write sound details int lastSampleIndex = 0; bw.Write((uint)_finalSoundInfosList.Count); for (int i = 0; i < _finalSoundInfosList.Count; i++) { var soundDetail = _finalSoundInfosList[i]; if (soundDetail.Samples.Count > 0x0F) { throw new Exception("Too many sound effects for sound info '" + soundDetail.Name + "'."); } ushort characteristics = (ushort)(3 & (int)soundDetail.LoopBehaviour); characteristics |= (ushort)(soundDetail.Samples.Count << 2); if (soundDetail.DisablePanning) { characteristics |= 0x1000; } if (soundDetail.RandomizePitch) { characteristics |= 0x2000; } if (soundDetail.RandomizeVolume) { characteristics |= 0x4000; } if (_level.Settings.GameVersion <= TRVersion.Game.TR2) { var newSoundDetail = new tr_sound_details(); newSoundDetail.Sample = (ushort)lastSampleIndex; newSoundDetail.Volume = (ushort)Math.Round(soundDetail.Volume / 100.0f * 32767.0f); newSoundDetail.Chance = (byte)Math.Round((soundDetail.Chance == 100 ? 0 : soundDetail.Chance) / 100.0f * 32767.0f); newSoundDetail.Characteristics = characteristics; bw.WriteBlock(newSoundDetail); } else { var newSoundDetail = new tr3_sound_details(); newSoundDetail.Sample = (ushort)lastSampleIndex; newSoundDetail.Volume = (byte)Math.Round(soundDetail.Volume / 100.0f * 255.0f); newSoundDetail.Range = (byte)soundDetail.RangeInSectors; newSoundDetail.Chance = (byte)Math.Round((soundDetail.Chance == 100 ? 0 : soundDetail.Chance) / 100.0f * 255.0f); newSoundDetail.Pitch = (byte)Math.Round(soundDetail.PitchFactor / 100.0f * 127.0f + (soundDetail.PitchFactor < 0 ? 256 : 0)); newSoundDetail.Characteristics = characteristics; bw.WriteBlock(newSoundDetail); } lastSampleIndex += soundDetail.Samples.Count; } if (_level.Settings.GameVersion < TRVersion.Game.TR5Main && lastSampleIndex > 255) { _progressReporter.ReportWarn("Level contains " + lastSampleIndex + " samples, while maximum is 256. Level will crash. Turn off some sounds to prevent that."); } // Write sample indices (not used but parsed in TR4-5) bw.Write((uint)_finalSoundIndicesList.Count); for (int i = 0; i < _finalSoundIndicesList.Count; i++) { bw.Write((uint)_finalSoundIndicesList[i]); } } writer.Write(ms.ToArray()); } }