private static void WriteTextures(ChunkWriter chunkIO, List <WadTexture> textureTable) { chunkIO.WriteChunkWithChildren(Wad2Chunks.Textures, () => { foreach (var texture in textureTable) { chunkIO.WriteChunkWithChildren(Wad2Chunks.Texture, () => { LEB128.Write(chunkIO.Raw, texture.Image.Width); LEB128.Write(chunkIO.Raw, texture.Image.Height); chunkIO.WriteChunkArrayOfBytes(Wad2Chunks.TextureData, texture.Image.ToByteArray()); }); } }); }
private static void WriteSpriteSequences(ChunkWriter chunkIO, Wad2 wad, List <WadSprite> spriteTable) { chunkIO.WriteChunkWithChildren(Wad2Chunks.SpriteSequences, () => { foreach (var sequence in wad.SpriteSequences.Values) { chunkIO.WriteChunkWithChildren(Wad2Chunks.SpriteSequence, () => { LEB128.Write(chunkIO.Raw, sequence.Id.TypeId); foreach (var spr in sequence.Sprites) { chunkIO.WriteChunkInt(Wad2Chunks.SpriteSequenceSpriteIndex, spriteTable.IndexOf(spr)); } }); } }); }
private static void WriteStatics(ChunkWriter chunkIO, Wad2 wad, List <WadTexture> textureTable) { chunkIO.WriteChunkWithChildren(Wad2Chunks.Statics, () => { foreach (var staticMesh in wad.Statics) { chunkIO.WriteChunkWithChildren(Wad2Chunks.Static, () => { var s = staticMesh.Value; LEB128.Write(chunkIO.Raw, s.Id.TypeId); LEB128.Write(chunkIO.Raw, s.Flags); LEB128.Write(chunkIO.Raw, (short)s.LightingType); WriteMesh(chunkIO, s.Mesh, textureTable); chunkIO.WriteChunkInt(Wad2Chunks.StaticAmbientLight, s.AmbientLight); foreach (var light in s.Lights) { chunkIO.WriteChunkWithChildren(Wad2Chunks.StaticLight, () => { chunkIO.WriteChunkVector3(Wad2Chunks.StaticLightPosition, light.Position); chunkIO.WriteChunkFloat(Wad2Chunks.StaticLightRadius, light.Radius); chunkIO.WriteChunkFloat(Wad2Chunks.StaticLightIntensity, light.Intensity); }); } chunkIO.WriteChunkWithChildren(Wad2Chunks.StaticVisibilityBox, () => { chunkIO.WriteChunkVector3(Wad2Chunks.MeshBoundingBoxMin, s.VisibilityBox.Minimum); chunkIO.WriteChunkVector3(Wad2Chunks.MeshBoundingBoxMax, s.VisibilityBox.Maximum); }); chunkIO.WriteChunkWithChildren(Wad2Chunks.StaticCollisionBox, () => { chunkIO.WriteChunkVector3(Wad2Chunks.MeshBoundingBoxMin, s.CollisionBox.Minimum); chunkIO.WriteChunkVector3(Wad2Chunks.MeshBoundingBoxMax, s.CollisionBox.Maximum); }); //chunkIO.WriteChunkString(Wad2Chunks.StaticName, s.Name); }); } }); }
private static void WriteSprites(ChunkWriter chunkIO, List <WadSprite> spriteTable) { chunkIO.WriteChunkWithChildren(Wad2Chunks.Sprites, () => { for (int i = 0; i < spriteTable.Count; ++i) { var sprite = spriteTable[i]; chunkIO.WriteChunkWithChildren(Wad2Chunks.Sprite, () => { LEB128.Write(chunkIO.Raw, sprite.Texture.Image.Width); LEB128.Write(chunkIO.Raw, sprite.Texture.Image.Height); chunkIO.WriteChunkInt(Wad2Chunks.SpriteIndex, i); chunkIO.WriteChunkArrayOfBytes(Wad2Chunks.SpriteData, sprite.Texture.Image.ToByteArray()); chunkIO.WriteChunk(Wad2Chunks.SpriteSides, () => { chunkIO.Raw.Write(sprite.Alignment.X0); chunkIO.Raw.Write(sprite.Alignment.Y0); chunkIO.Raw.Write(sprite.Alignment.X1); chunkIO.Raw.Write(sprite.Alignment.Y1); }); }); } }); }
private bool BuildScripts() { string scriptPath = _dstPath + "\\Script.dat"; if (File.Exists(scriptPath)) { File.Delete(scriptPath); } using (var stream = File.OpenWrite(scriptPath)) { var chunkIO = new ChunkWriter(new byte[] { 0x54, 0x52, 0x35, 0x4D }, new BinaryWriterFast(stream)); // Main flags chunkIO.WriteChunk(Tr5MainFlags, () => { LEB128.Write(chunkIO.Raw, (_loadSave ? 1 : 0)); LEB128.Write(chunkIO.Raw, (_playAnyLevel ? 1 : 0)); LEB128.Write(chunkIO.Raw, (_flyCheat ? 1 : 0)); LEB128.Write(chunkIO.Raw, (_diagnostics ? 1 : 0)); LEB128.Write(chunkIO.Raw, _levelFarView); chunkIO.Raw.WriteStringUTF8(_intro); }); // Game strings foreach (var stringsObj in _languageStrings) { chunkIO.WriteChunk(Tr5MainStrings, () => { chunkIO.Raw.WriteStringUTF8(stringsObj.Name); LEB128.Write(chunkIO.Raw, stringsObj.Strings.Count); foreach (var str in stringsObj.Strings) { chunkIO.Raw.WriteStringUTF8(str); } }); } // Audio tracks chunkIO.WriteChunk(Tr5MainAudioTracks, () => { LEB128.Write(chunkIO.Raw, _tracks.Count); foreach (var track in _tracks) { chunkIO.Raw.WriteStringUTF8(track); } }); // Levels foreach (var level in _levels) { chunkIO.WriteChunkWithChildren(Tr5MainLevel, () => { // Level informations chunkIO.WriteChunk(Tr5MainLevelInfo, () => { chunkIO.Raw.WriteStringUTF8(level.FileName); chunkIO.Raw.WriteStringUTF8(level.LoadScreen); chunkIO.Raw.WriteStringUTF8(level.Background); LEB128.Write(chunkIO.Raw, GetStringIndex(level.Name)); LEB128.Write(chunkIO.Raw, level.AudioTrack); }); // Level flags chunkIO.WriteChunk(Tr5MainLevelFlags, () => { LEB128.Write(chunkIO.Raw, (level.Horizon ? 1 : 0)); LEB128.Write(chunkIO.Raw, (level.Sky ? 1 : 0)); LEB128.Write(chunkIO.Raw, (level.ColAddHorizon ? 1 : 0)); LEB128.Write(chunkIO.Raw, (level.Lightning ? 1 : 0)); LEB128.Write(chunkIO.Raw, (level.ResetInventory ? 1 : 0)); LEB128.Write(chunkIO.Raw, level.LaraType); LEB128.Write(chunkIO.Raw, level.UVRotate); LEB128.Write(chunkIO.Raw, (level.LevelFarView != 0 ? level.LevelFarView : _levelFarView)); LEB128.Write(chunkIO.Raw, (level.Rumble ? 1 : 0)); LEB128.Write(chunkIO.Raw, (byte)(level.Weather)); LEB128.Write(chunkIO.Raw, (level.UnlimitedAir ? 1 : 0)); }); // Puzzles and various things foreach (var entry in level.Entries) { if (entry.Command.Name == "Puzzle") { chunkIO.WriteChunk(Tr5MainLevelPuzzle, () => { LEB128.Write(chunkIO.Raw, byte.Parse(entry.Parameters[0].ToString())); LEB128.Write(chunkIO.Raw, (int)GetStringIndex(entry.Parameters[1].ToString())); for (int j = 2; j < 8; j++) { LEB128.Write(chunkIO.Raw, short.Parse(entry.Parameters[j].ToString())); } }); } else if (entry.Command.Name == "Key") { chunkIO.WriteChunk(Tr5MainLevelKey, () => { LEB128.Write(chunkIO.Raw, byte.Parse(entry.Parameters[0].ToString())); LEB128.Write(chunkIO.Raw, (int)GetStringIndex(entry.Parameters[1].ToString())); for (int j = 2; j < 8; j++) { LEB128.Write(chunkIO.Raw, short.Parse(entry.Parameters[j].ToString())); } }); } else if (entry.Command.Name == "Pickup") { chunkIO.WriteChunk(Tr5MainLevelPickup, () => { LEB128.Write(chunkIO.Raw, byte.Parse(entry.Parameters[0].ToString())); LEB128.Write(chunkIO.Raw, (int)GetStringIndex(entry.Parameters[1].ToString())); for (int j = 2; j < 8; j++) { LEB128.Write(chunkIO.Raw, short.Parse(entry.Parameters[j].ToString())); } }); } if (entry.Command.Name == "Examine") { chunkIO.WriteChunk(Tr5MainLevelExamine, () => { LEB128.Write(chunkIO.Raw, byte.Parse(entry.Parameters[0].ToString())); LEB128.Write(chunkIO.Raw, (int)GetStringIndex(entry.Parameters[1].ToString())); for (int j = 2; j < 8; j++) { LEB128.Write(chunkIO.Raw, short.Parse(entry.Parameters[j].ToString())); } }); } if (entry.Command.Name == "PuzzleCombo") { chunkIO.WriteChunk(Tr5MainLevelPuzzleCombo, () => { LEB128.Write(chunkIO.Raw, byte.Parse(entry.Parameters[0].ToString())); LEB128.Write(chunkIO.Raw, byte.Parse(entry.Parameters[1].ToString())); LEB128.Write(chunkIO.Raw, (int)GetStringIndex(entry.Parameters[2].ToString())); for (int j = 3; j < 9; j++) { LEB128.Write(chunkIO.Raw, short.Parse(entry.Parameters[j].ToString())); } }); } else if (entry.Command.Name == "KeyCombo") { chunkIO.WriteChunk(Tr5MainLevelKeyCombo, () => { LEB128.Write(chunkIO.Raw, byte.Parse(entry.Parameters[0].ToString())); LEB128.Write(chunkIO.Raw, byte.Parse(entry.Parameters[1].ToString())); LEB128.Write(chunkIO.Raw, (int)GetStringIndex(entry.Parameters[2].ToString())); for (int j = 3; j < 9; j++) { LEB128.Write(chunkIO.Raw, short.Parse(entry.Parameters[j].ToString())); } }); } else if (entry.Command.Name == "PickupCombo") { chunkIO.WriteChunk(Tr5MainLevelPickupCombo, () => { LEB128.Write(chunkIO.Raw, byte.Parse(entry.Parameters[0].ToString())); LEB128.Write(chunkIO.Raw, byte.Parse(entry.Parameters[1].ToString())); LEB128.Write(chunkIO.Raw, (int)GetStringIndex(entry.Parameters[2].ToString())); for (int j = 3; j < 9; j++) { LEB128.Write(chunkIO.Raw, short.Parse(entry.Parameters[j].ToString())); } }); } else if (entry.Command.Name == "Layer1") { chunkIO.WriteChunk(Tr5MainLevelLayer, () => { LEB128.Write(chunkIO.Raw, 1); LEB128.Write(chunkIO.Raw, byte.Parse(entry.Parameters[0].ToString())); LEB128.Write(chunkIO.Raw, byte.Parse(entry.Parameters[1].ToString())); LEB128.Write(chunkIO.Raw, byte.Parse(entry.Parameters[2].ToString())); LEB128.Write(chunkIO.Raw, sbyte.Parse(entry.Parameters[3].ToString())); }); } else if (entry.Command.Name == "Layer2") { chunkIO.WriteChunk(Tr5MainLevelLayer, () => { LEB128.Write(chunkIO.Raw, 2); LEB128.Write(chunkIO.Raw, byte.Parse(entry.Parameters[0].ToString())); LEB128.Write(chunkIO.Raw, byte.Parse(entry.Parameters[1].ToString())); LEB128.Write(chunkIO.Raw, byte.Parse(entry.Parameters[2].ToString())); LEB128.Write(chunkIO.Raw, sbyte.Parse(entry.Parameters[3].ToString())); }); } else if (entry.Command.Name == "DistantFog") { chunkIO.WriteChunk(Tr5MainLevelLayer, () => { LEB128.Write(chunkIO.Raw, byte.Parse(entry.Parameters[0].ToString())); LEB128.Write(chunkIO.Raw, byte.Parse(entry.Parameters[1].ToString())); LEB128.Write(chunkIO.Raw, byte.Parse(entry.Parameters[2].ToString())); LEB128.Write(chunkIO.Raw, int.Parse(entry.Parameters[3].ToString())); }); } else if (entry.Command.Name == "OnLevelStart" || entry.Command.Name == "OnLevelFinish" || entry.Command.Name == "OnLoadGame" || entry.Command.Name == "OnSaveGame" || entry.Command.Name == "OnLaraDeath" || entry.Command.Name == "OnLevelControl" || entry.Command.Name == "OnBeginFrame") { chunkIO.WriteChunk(Tr5MainLevelLuaEvent, () => { chunkIO.Raw.WriteStringUTF8(entry.Command.Name); chunkIO.Raw.WriteStringUTF8(entry.Parameters[0].ToString()); }); } } }); } // EOF chunkIO.Raw.Write((int)0); chunkIO.Raw.Flush(); } return(true); }
private static void WriteObjects(ChunkWriter chunkIO, IEnumerable <ObjectInstance> objects, Dictionary <Room, int> rooms, LevelSettingsIds levelSettingIds, Dictionary <ObjectInstance, int> objectInstanceLookup) { using (var chunkObjects = chunkIO.WriteChunk(Prj2Chunks.Objects, long.MaxValue)) { foreach (var o in objects) { if (o is MoveableInstance) { chunkIO.WriteChunkWithChildren(Prj2Chunks.ObjectMovable3, () => { var instance = (MoveableInstance)o; LEB128.Write(chunkIO.Raw, objectInstanceLookup.TryGetOrDefault(instance, -1)); chunkIO.Raw.Write(instance.Position); chunkIO.Raw.Write(instance.RotationY); LEB128.Write(chunkIO.Raw, (long?)instance.ScriptId ?? -1); chunkIO.Raw.Write(instance.WadObjectId.TypeId); chunkIO.Raw.Write(instance.Ocb); chunkIO.Raw.Write(instance.Invisible); chunkIO.Raw.Write(instance.ClearBody); chunkIO.Raw.Write(instance.CodeBits); chunkIO.Raw.Write(instance.Color); chunkIO.WriteChunkInt(Prj2Chunks.ObjectItemLuaId, instance.LuaId); }); } else if (o is StaticInstance) { chunkIO.WriteChunkWithChildren(Prj2Chunks.ObjectStatic2, () => { var instance = (StaticInstance)o; LEB128.Write(chunkIO.Raw, objectInstanceLookup.TryGetOrDefault(instance, -1)); chunkIO.Raw.Write(instance.Position); chunkIO.Raw.Write(instance.RotationY); LEB128.Write(chunkIO.Raw, (long?)instance.ScriptId ?? -1); chunkIO.Raw.Write(instance.WadObjectId.TypeId); chunkIO.Raw.Write(instance.Color); chunkIO.Raw.Write((int)0); // Unused 32 bit value chunkIO.Raw.Write(instance.Ocb); chunkIO.WriteChunkInt(Prj2Chunks.ObjectItemLuaId, instance.LuaId); }); } else if (o is CameraInstance) { using (var chunk = chunkIO.WriteChunk(Prj2Chunks.ObjectCamera, LEB128.MaximumSize1Byte)) { var instance = (CameraInstance)o; LEB128.Write(chunkIO.Raw, objectInstanceLookup.TryGetOrDefault(instance, -1)); chunkIO.Raw.Write(instance.Position); LEB128.Write(chunkIO.Raw, (long?)instance.ScriptId ?? -1); chunkIO.Raw.Write(instance.Fixed); } } else if (o is FlybyCameraInstance) { chunkIO.WriteChunkWithChildren(Prj2Chunks.ObjectFlyBy, () => { var instance = (FlybyCameraInstance)o; LEB128.Write(chunkIO.Raw, objectInstanceLookup.TryGetOrDefault(instance, -1)); chunkIO.Raw.Write(instance.Position); chunkIO.Raw.Write(instance.RotationY); chunkIO.Raw.Write(instance.RotationX); chunkIO.Raw.Write(instance.Roll); LEB128.Write(chunkIO.Raw, (long?)instance.ScriptId ?? -1); chunkIO.Raw.Write(instance.Speed); chunkIO.Raw.Write(instance.Fov); LEB128.Write(chunkIO.Raw, instance.Flags); LEB128.Write(chunkIO.Raw, instance.Number); LEB128.Write(chunkIO.Raw, instance.Sequence); LEB128.Write(chunkIO.Raw, instance.Timer); }); } else if (o is SinkInstance) { using (var chunk = chunkIO.WriteChunk(Prj2Chunks.ObjectSink, LEB128.MaximumSize1Byte)) { var instance = (SinkInstance)o; LEB128.Write(chunkIO.Raw, objectInstanceLookup.TryGetOrDefault(instance, -1)); chunkIO.Raw.Write(instance.Position); LEB128.Write(chunkIO.Raw, (long?)instance.ScriptId ?? -1); chunkIO.Raw.Write(instance.Strength); } } else if (o is SoundSourceInstance) { using (var chunk = chunkIO.WriteChunk(Prj2Chunks.ObjectSoundSourceFinal, LEB128.MaximumSize1Byte)) { var instance = (SoundSourceInstance)o; LEB128.Write(chunkIO.Raw, objectInstanceLookup.TryGetOrDefault(instance, -1)); chunkIO.Raw.Write(instance.Position); chunkIO.Raw.Write(instance.SoundId); chunkIO.Raw.Write((int)instance.PlayMode); LEB128.Write(chunkIO.Raw, -1); } } else if (o is LightInstance) { using (var chunk = chunkIO.WriteChunk(Prj2Chunks.ObjectLight4, LEB128.MaximumSize2Byte)) { var instance = (LightInstance)o; LEB128.Write(chunkIO.Raw, objectInstanceLookup.TryGetOrDefault(instance, -1)); LEB128.Write(chunkIO.Raw, (long)instance.Type); chunkIO.Raw.Write(instance.Position); chunkIO.Raw.Write(instance.RotationY); chunkIO.Raw.Write(instance.RotationX); chunkIO.Raw.Write(instance.Intensity); chunkIO.Raw.Write(instance.Color); chunkIO.Raw.Write(instance.InnerRange); chunkIO.Raw.Write(instance.OuterRange); chunkIO.Raw.Write(instance.InnerAngle); chunkIO.Raw.Write(instance.OuterAngle); chunkIO.Raw.Write(instance.Enabled); chunkIO.Raw.Write(instance.IsObstructedByRoomGeometry); chunkIO.Raw.Write(instance.IsDynamicallyUsed); chunkIO.Raw.Write(instance.IsStaticallyUsed); chunkIO.Raw.Write(instance.IsUsedForImportedGeometry); chunkIO.Raw.Write((byte)instance.Quality); } } else if (o is PortalInstance && rooms.ContainsKey(((PortalInstance)o).AdjoiningRoom)) { using (var chunk = chunkIO.WriteChunk(Prj2Chunks.ObjectPortal, LEB128.MaximumSize2Byte)) { var instance = (PortalInstance)o; LEB128.Write(chunkIO.Raw, objectInstanceLookup.TryGetOrDefault(instance, -1)); LEB128.Write(chunkIO.Raw, instance.Area.X0); LEB128.Write(chunkIO.Raw, instance.Area.Y0); LEB128.Write(chunkIO.Raw, instance.Area.X1); LEB128.Write(chunkIO.Raw, instance.Area.Y1); LEB128.Write(chunkIO.Raw, rooms[instance.AdjoiningRoom]); chunkIO.Raw.Write((byte)instance.Direction); chunkIO.Raw.Write((byte)instance.Opacity); } } else if (o is GhostBlockInstance) { using (var chunk = chunkIO.WriteChunk(Prj2Chunks.ObjectGhostBlock, LEB128.MaximumSize2Byte)) { var instance = (GhostBlockInstance)o; LEB128.Write(chunkIO.Raw, objectInstanceLookup.TryGetOrDefault(instance, -1)); LEB128.Write(chunkIO.Raw, instance.Area.X0); LEB128.Write(chunkIO.Raw, instance.Area.Y0); LEB128.Write(chunkIO.Raw, instance.Floor.XnZn); LEB128.Write(chunkIO.Raw, instance.Floor.XnZp); LEB128.Write(chunkIO.Raw, instance.Floor.XpZn); LEB128.Write(chunkIO.Raw, instance.Floor.XpZp); LEB128.Write(chunkIO.Raw, instance.Ceiling.XnZn); LEB128.Write(chunkIO.Raw, instance.Ceiling.XnZp); LEB128.Write(chunkIO.Raw, instance.Ceiling.XpZn); LEB128.Write(chunkIO.Raw, instance.Ceiling.XpZp); } } else if (o is VolumeInstance) { using (var chunk = chunkIO.WriteChunk(Prj2Chunks.ObjectTriggerVolumeTest, LEB128.MaximumSize2Byte)) { var instance = (VolumeInstance)o; LEB128.Write(chunkIO.Raw, objectInstanceLookup.TryGetOrDefault(instance, -1)); var shape = instance.Shape(); chunkIO.Raw.Write((byte)shape); switch (shape) { case VolumeShape.Box: { var bv = instance as BoxVolumeInstance; chunkIO.Raw.Write(bv.Size); chunkIO.Raw.Write(bv.RotationY); chunkIO.Raw.Write(bv.RotationX); } break; case VolumeShape.Prism: { var pv = instance as PrismVolumeInstance; chunkIO.Raw.Write(pv.Scale); chunkIO.Raw.Write(pv.RotationY); } break; case VolumeShape.Sphere: chunkIO.Raw.Write((instance as SphereVolumeInstance).Scale); break; } chunkIO.Raw.Write(instance.Position); chunkIO.Raw.Write((ushort)instance.Activators); chunkIO.Raw.WriteStringUTF8(instance.Scripts.Name); chunkIO.Raw.WriteStringUTF8(instance.Scripts.Environment); chunkIO.Raw.WriteStringUTF8(instance.Scripts.OnEnter); chunkIO.Raw.WriteStringUTF8(instance.Scripts.OnInside); chunkIO.Raw.WriteStringUTF8(instance.Scripts.OnLeave); } } else if (o is TriggerInstance) { using (var chunk = chunkIO.WriteChunk(Prj2Chunks.ObjectTrigger2, LEB128.MaximumSize2Byte)) { Action <ITriggerParameter> writeTriggerParameter = (ITriggerParameter parameter) => { if (parameter is TriggerParameterUshort) { LEB128.Write(chunkIO.Raw, 0); LEB128.Write(chunkIO.Raw, ((TriggerParameterUshort)parameter).Key); } else if (parameter is ObjectInstance) { LEB128.Write(chunkIO.Raw, 1); LEB128.Write(chunkIO.Raw, objectInstanceLookup.TryGetOrDefault((ObjectInstance)parameter)); } else if (parameter is Room) { LEB128.Write(chunkIO.Raw, 2); LEB128.Write(chunkIO.Raw, rooms.TryGetOrDefault((Room)parameter)); } else { LEB128.Write(chunkIO.Raw, -1); }; }; var instance = (TriggerInstance)o; LEB128.Write(chunkIO.Raw, objectInstanceLookup.TryGetOrDefault(instance, -1)); LEB128.Write(chunkIO.Raw, instance.Area.X0); LEB128.Write(chunkIO.Raw, instance.Area.Y0); LEB128.Write(chunkIO.Raw, instance.Area.X1); LEB128.Write(chunkIO.Raw, instance.Area.Y1); chunkIO.WriteChunkInt(Prj2Chunks.ObjectTrigger2Type, (long)instance.TriggerType); chunkIO.WriteChunkInt(Prj2Chunks.ObjectTrigger2TargetType, (long)instance.TargetType); chunkIO.WriteChunk(Prj2Chunks.ObjectTrigger2Target, () => writeTriggerParameter(instance.Target), 32); chunkIO.WriteChunk(Prj2Chunks.ObjectTrigger2Timer, () => writeTriggerParameter(instance.Timer), 32); chunkIO.WriteChunk(Prj2Chunks.ObjectTrigger2Extra, () => writeTriggerParameter(instance.Extra), 32); chunkIO.WriteChunkInt(Prj2Chunks.ObjectTrigger2CodeBits, instance.CodeBits); chunkIO.WriteChunkBool(Prj2Chunks.ObjectTrigger2OneShot, instance.OneShot); chunkIO.WriteChunkEnd(); } } else if (o is ImportedGeometryInstance) { chunkIO.WriteChunkWithChildren(Prj2Chunks.ObjectImportedGeometry3, () => { var instance = (ImportedGeometryInstance)o; LEB128.Write(chunkIO.Raw, objectInstanceLookup.TryGetOrDefault(instance, -1)); chunkIO.Raw.Write(instance.Position); chunkIO.Raw.Write(instance.RotationY); chunkIO.Raw.Write(instance.RotationX); chunkIO.Raw.Write(instance.Roll); chunkIO.Raw.Write(instance.Scale); LEB128.Write(chunkIO.Raw, instance.Model == null ? -1 : levelSettingIds.ImportedGeometries[instance.Model]); chunkIO.WriteChunkInt(Prj2Chunks.ObjectImportedGeometryLightingModel, (int)instance.LightingModel); chunkIO.WriteChunkBool(Prj2Chunks.ObjectImportedGeometrySharpEdges, instance.SharpEdges); chunkIO.WriteChunkBool(Prj2Chunks.ObjectImportedGeometryHidden, instance.Hidden); }); } else { logger.Warn("Object " + o + " not supported."); } } chunkIO.WriteChunkEnd(); }; }
private static void WriteRooms(ChunkWriter chunkIO, Dictionary <Room, int> rooms, LevelSettingsIds levelSettingIds) { // Allocate object indices var objectInstanceLookup = new Dictionary <ObjectInstance, int>(); foreach (Room room in rooms.Keys) { foreach (ObjectInstance objectInstance in room.AnyObjects) { objectInstanceLookup.Add(objectInstance, objectInstanceLookup.Count); } } // Save using (var chunkRooms = chunkIO.WriteChunk(Prj2Chunks.Rooms, long.MaxValue)) { foreach (Room room in rooms.Keys) { using (var chunkRoom = chunkIO.WriteChunk(Prj2Chunks.Room, long.MaxValue)) { LEB128.Write(chunkIO.Raw, room.NumXSectors); LEB128.Write(chunkIO.Raw, room.NumZSectors); // Write basic properties chunkIO.WriteChunkInt(Prj2Chunks.RoomIndex, rooms.TryGetOrDefault(room, -1)); chunkIO.WriteChunkString(Prj2Chunks.RoomName, room.Name); chunkIO.WriteChunkVector3(Prj2Chunks.RoomPosition, room.Position); chunkIO.WriteChunkArrayOfBytes(Prj2Chunks.RoomTags, System.Text.Encoding.UTF8.GetBytes(string.Join(" ", room.Tags))); // Write sectors using (var chunkRoomSectors = chunkIO.WriteChunk(Prj2Chunks.RoomSectors)) { for (int z = 0; z < room.NumZSectors; z++) { for (int x = 0; x < room.NumXSectors; x++) { using (var chunkSector = chunkIO.WriteChunk(Prj2Chunks.Sector, LEB128.MaximumSize2Byte)) { chunkIO.Raw.Write(x + z * room.NumXSectors); var b = room.Blocks[x, z]; long combinedFlag = (b.IsAnyWall ? 1L : 0) | (b.ForceFloorSolid ? 2L : 0) | ((long)b.Flags << 2); chunkIO.WriteChunkInt(Prj2Chunks.SectorProperties, combinedFlag); using (var chunkSectorFloor = chunkIO.WriteChunk(Prj2Chunks.SectorFloor, LEB128.MaximumSize1Byte)) { long flag = (b.Floor.SplitDirectionIsXEqualsZ ? 1L : 0) | ((long)b.Floor.DiagonalSplit << 1); LEB128.Write(chunkIO.Raw, flag); for (BlockEdge edge = 0; edge < BlockEdge.Count; ++edge) { LEB128.Write(chunkIO.Raw, b.Floor.GetHeight(edge)); } for (BlockEdge edge = 0; edge < BlockEdge.Count; ++edge) { LEB128.Write(chunkIO.Raw, b.GetHeight(BlockVertical.Ed, edge)); } } using (var chunkSectorCeiling = chunkIO.WriteChunk(Prj2Chunks.SectorCeiling, LEB128.MaximumSize1Byte)) { long flag = (b.Ceiling.SplitDirectionIsXEqualsZ ? 1L : 0) | ((long)b.Ceiling.DiagonalSplit << 1); LEB128.Write(chunkIO.Raw, flag); for (BlockEdge edge = 0; edge < BlockEdge.Count; ++edge) { LEB128.Write(chunkIO.Raw, b.Ceiling.GetHeight(edge)); } for (BlockEdge edge = 0; edge < BlockEdge.Count; ++edge) { LEB128.Write(chunkIO.Raw, b.GetHeight(BlockVertical.Rf, edge)); } } for (BlockFace face = 0; face < BlockFace.Count; face++) { var texture = b.GetFaceTexture(face); if (texture.Texture == null) { continue; } if (texture.Texture is LevelTexture) { using (var chunkTextureLevelTexture = chunkIO.WriteChunk(Prj2Chunks.TextureLevelTexture2, LEB128.MaximumSize1Byte)) { int textureIndex = levelSettingIds.LevelTextures[(LevelTexture)texture.Texture]; LEB128.Write(chunkIO.Raw, (long)face); chunkIO.Raw.Write(texture.TexCoord0); chunkIO.Raw.Write(texture.TexCoord1); chunkIO.Raw.Write(texture.TexCoord2); chunkIO.Raw.Write(texture.TexCoord3); chunkIO.Raw.Write(texture.ParentArea.Start); chunkIO.Raw.Write(texture.ParentArea.End); LEB128.Write(chunkIO.Raw, (texture.DoubleSided ? 1L : 0) | ((long)texture.BlendMode << 1)); LEB128.Write(chunkIO.Raw, textureIndex); } } else if (texture.Texture == TextureInvisible.Instance) { chunkIO.WriteChunkInt(Prj2Chunks.TextureInvisible, (long)face); } else { throw new NotSupportedException("Unsupported texture type " + texture.Texture.GetType().Name); } } chunkIO.WriteChunkEnd(); } } } chunkIO.WriteChunkEnd(); } // Write room properties chunkIO.WriteChunkVector3(Prj2Chunks.RoomAmbientLight, room.AmbientLight); chunkIO.WriteChunkBool(Prj2Chunks.RoomFlagCold, room.FlagCold); chunkIO.WriteChunkBool(Prj2Chunks.RoomFlagDamage, room.FlagDamage); chunkIO.WriteChunkBool(Prj2Chunks.RoomFlagHorizon, room.FlagHorizon); chunkIO.WriteChunkBool(Prj2Chunks.RoomFlagOutside, room.FlagOutside); chunkIO.WriteChunkBool(Prj2Chunks.RoomFlagNoLensflare, room.FlagNoLensflare); chunkIO.WriteChunkBool(Prj2Chunks.RoomFlagExcludeFromPathFinding, room.FlagExcludeFromPathFinding); chunkIO.WriteChunkInt(Prj2Chunks.RoomType, (int)room.Type); chunkIO.WriteChunkInt(Prj2Chunks.RoomTypeStrength, room.TypeStrength); chunkIO.WriteChunkInt(Prj2Chunks.RoomLightEffect, (int)room.LightEffect); chunkIO.WriteChunkInt(Prj2Chunks.RoomLightEffectStrength2, room.LightEffectStrength); chunkIO.WriteChunkInt(Prj2Chunks.RoomReverberation, (int)room.Reverberation); chunkIO.WriteChunkInt(Prj2Chunks.RoomLightInterpolationMode, (int)room.LightInterpolationMode); chunkIO.WriteChunkBool(Prj2Chunks.RoomLocked, room.Locked); chunkIO.WriteChunkBool(Prj2Chunks.RoomHidden, room.Hidden); if (room.AlternateRoom != null && rooms.ContainsKey(room.AlternateRoom)) { using (var chunkRoomAlternate = chunkIO.WriteChunk(Prj2Chunks.RoomAlternate, LEB128.MaximumSize1Byte)) { chunkIO.WriteChunkInt(Prj2Chunks.AlternateGroup, room.AlternateGroup); chunkIO.WriteChunkInt(Prj2Chunks.AlternateRoom, rooms[room.AlternateRoom]); chunkIO.WriteChunkEnd(); } } // Write room objects WriteObjects(chunkIO, room.AnyObjects, rooms, levelSettingIds, objectInstanceLookup); chunkIO.WriteChunkEnd(); } } chunkIO.WriteChunkEnd(); } }
private static LevelSettingsIds WriteLevelSettings(ChunkWriter chunkIO, LevelSettings settings) { var levelSettingIds = new LevelSettingsIds(settings); using (var chunkSettings = chunkIO.WriteChunk(Prj2Chunks.Settings, long.MaxValue)) { chunkIO.WriteChunkString(Prj2Chunks.FontTextureFilePath, settings.FontTextureFilePath ?? ""); chunkIO.WriteChunkString(Prj2Chunks.SkyTextureFilePath, settings.SkyTextureFilePath ?? ""); chunkIO.WriteChunkString(Prj2Chunks.Tr5ExtraSpritesFilePath, settings.Tr5ExtraSpritesFilePath ?? ""); using (var chunkOldWadSoundPaths = chunkIO.WriteChunk(Prj2Chunks.OldWadSoundPaths)) { chunkIO.WriteChunkEmpty(Prj2Chunks.OldWadSoundUpdateTag1_0_8); foreach (WadSoundPath soundPath in settings.WadSoundPaths) { using (var chunkOldWadSoundPath = chunkIO.WriteChunk(Prj2Chunks.OldWadSoundPath)) { chunkIO.WriteChunkString(Prj2Chunks.OldWadSoundPathPath, soundPath.Path); chunkIO.WriteChunkEnd(); } } chunkIO.WriteChunkEnd(); } chunkIO.WriteChunkString(Prj2Chunks.GameDirectory, settings.GameDirectory ?? ""); chunkIO.WriteChunkString(Prj2Chunks.GameLevelFilePath, settings.GameLevelFilePath ?? ""); chunkIO.WriteChunkString(Prj2Chunks.GameExecutableFilePath, settings.GameExecutableFilePath ?? ""); chunkIO.WriteChunkBool(Prj2Chunks.GameEnableQuickStartFeature, settings.GameEnableQuickStartFeature); chunkIO.WriteChunkInt(Prj2Chunks.GameVersion, (long)settings.GameVersion); chunkIO.WriteChunkInt(Prj2Chunks.Tr5LaraType, (long)settings.Tr5LaraType); chunkIO.WriteChunkInt(Prj2Chunks.Tr5Weather, (long)settings.Tr5WeatherType); chunkIO.WriteChunkInt(Prj2Chunks.TexturePadding, (long)settings.TexturePadding); chunkIO.WriteChunkBool(Prj2Chunks.RemapAnimatedTextures, settings.RemapAnimatedTextures); chunkIO.WriteChunkBool(Prj2Chunks.Dither16BitTextures, settings.Dither16BitTextures); chunkIO.WriteChunkBool(Prj2Chunks.AgressiveTexturePacking, settings.AgressiveTexturePacking); chunkIO.WriteChunkBool(Prj2Chunks.AgressiveFloordataPacking, settings.AgressiveFloordataPacking); chunkIO.WriteChunkVector3(Prj2Chunks.DefaultAmbientLight, settings.DefaultAmbientLight); chunkIO.WriteChunkInt(Prj2Chunks.DefaultLightQuality, (long)settings.DefaultLightQuality); chunkIO.WriteChunkBool(Prj2Chunks.OverrideLightQuality, settings.OverrideIndividualLightQualitySettings); chunkIO.WriteChunkString(Prj2Chunks.ScriptDirectory, settings.ScriptDirectory ?? ""); chunkIO.WriteChunkInt(Prj2Chunks.SoundSystem, (int)settings.SoundSystem); using (var chunkWads = chunkIO.WriteChunk(Prj2Chunks.Wads, long.MaxValue)) { foreach (ReferencedWad wad in settings.Wads) { using (var chunkWad = chunkIO.WriteChunk(Prj2Chunks.Wad)) { chunkIO.WriteChunkString(Prj2Chunks.WadPath, wad.Path ?? ""); chunkIO.WriteChunkEnd(); } } chunkIO.WriteChunkEnd(); } using (var chunkSounds = chunkIO.WriteChunk(Prj2Chunks.SoundsCatalogs, long.MaxValue)) { foreach (ReferencedSoundsCatalog soundRef in settings.SoundsCatalogs) { using (var chunkSound = chunkIO.WriteChunk(Prj2Chunks.SoundsCatalog)) { chunkIO.WriteChunkString(Prj2Chunks.SoundsCatalogPath, soundRef.Path ?? ""); chunkIO.WriteChunkEnd(); } } chunkIO.WriteChunkEnd(); } using (var chunkSelectedSounds = chunkIO.WriteChunk(Prj2Chunks.SelectedSounds, long.MaxValue)) { foreach (int selectedSound in settings.SelectedSounds) { chunkIO.WriteChunkInt(Prj2Chunks.SelectedSound, selectedSound); } chunkIO.WriteChunkEnd(); } using (var chunkTextures = chunkIO.WriteChunk(Prj2Chunks.Textures, long.MaxValue)) { int index = 0; foreach (LevelTexture texture in settings.Textures) { using (var chunkLevelTexture = chunkIO.WriteChunk(Prj2Chunks.LevelTexture)) { chunkIO.WriteChunkInt(Prj2Chunks.LevelTextureIndex, index); chunkIO.WriteChunkString(Prj2Chunks.LevelTexturePath, texture.Path ?? ""); chunkIO.WriteChunkString(Prj2Chunks.LevelTextureCustomBumpmapPath, texture.BumpPath ?? ""); chunkIO.WriteChunkBool(Prj2Chunks.LevelTextureConvert512PixelsToDoubleRows, texture.Convert512PixelsToDoubleRows); chunkIO.WriteChunkBool(Prj2Chunks.LevelTextureReplaceMagentaWithTransparency, texture.ReplaceMagentaWithTransparency); using (var chunkLevelTextureFootStepSounds = chunkIO.WriteChunk(Prj2Chunks.LevelTextureFootStepSounds)) { chunkIO.Raw.Write(texture.FootStepSoundWidth); chunkIO.Raw.Write(texture.FootStepSoundHeight); for (int y = 0; y < texture.FootStepSoundHeight; ++y) { for (int x = 0; x < texture.FootStepSoundWidth; ++x) { chunkIO.Raw.Write((byte)texture.GetFootStepSound(x, y)); } } } using (var chunkLevelTextureBumpmaps = chunkIO.WriteChunk(Prj2Chunks.LevelTextureBumpmaps)) { chunkIO.Raw.Write(texture.BumpMappingWidth); chunkIO.Raw.Write(texture.BumpMappingHeight); for (int y = 0; y < texture.BumpMappingHeight; ++y) { for (int x = 0; x < texture.BumpMappingWidth; ++x) { chunkIO.Raw.Write((byte)texture.GetBumpMapLevel(x, y)); } } } chunkIO.WriteChunkEnd(); } levelSettingIds.LevelTextures.Add(texture, index++); } chunkIO.WriteChunkEnd(); } using (var chunkImportedGeometries = chunkIO.WriteChunk(Prj2Chunks.ImportedGeometries, long.MaxValue)) { int index = 0; foreach (ImportedGeometry importedGeometry in settings.ImportedGeometries) { using (var chunkImportedGeometry = chunkIO.WriteChunk(Prj2Chunks.ImportedGeometry)) { chunkIO.WriteChunkInt(Prj2Chunks.ImportedGeometryIndex, index); chunkIO.WriteChunkString(Prj2Chunks.ImportedGeometryName, importedGeometry.Info.Name); chunkIO.WriteChunkString(Prj2Chunks.ImportedGeometryPath, importedGeometry.Info.Path); chunkIO.WriteChunkFloat(Prj2Chunks.ImportedGeometryScale, importedGeometry.Info.Scale); chunkIO.WriteChunkInt(Prj2Chunks.ImportedGeometryPosAxisFlags, (importedGeometry.Info.SwapXY ? 1 : 0) | (importedGeometry.Info.SwapXZ ? 2 : 0) | (importedGeometry.Info.SwapYZ ? 4 : 0) | (importedGeometry.Info.FlipX ? 8 : 0) | (importedGeometry.Info.FlipY ? 16 : 0) | (importedGeometry.Info.FlipZ ? 32 : 0)); chunkIO.WriteChunkInt(Prj2Chunks.ImportedGeometryTexAxisFlags, importedGeometry.Info.FlipUV_V ? 4 : 0); chunkIO.WriteChunkBool(Prj2Chunks.ImportedGeometryInvertFaces, importedGeometry.Info.InvertFaces); chunkIO.WriteChunkEnd(); } levelSettingIds.ImportedGeometries.Add(importedGeometry, index++); } chunkIO.WriteChunkEnd(); } using (var chunkAnimatedTextureSets = chunkIO.WriteChunk(Prj2Chunks.AnimatedTextureSets, long.MaxValue)) { foreach (AnimatedTextureSet set in settings.AnimatedTextureSets) { using (var chunkAnimatedTextureSet = chunkIO.WriteChunk(Prj2Chunks.AnimatedTextureSet)) { chunkIO.WriteChunkString(Prj2Chunks.AnimatedTextureSetName, set.Name ?? ""); chunkIO.WriteChunkInt(Prj2Chunks.AnimatedTextureSetType, (int)set.AnimationType); chunkIO.WriteChunkFloat(Prj2Chunks.AnimatedTextureSetFps, set.Fps); chunkIO.WriteChunkInt(Prj2Chunks.AnimatedTextureSetUvRotate, set.UvRotate); using (var chunkAnimatedTextureFrames = chunkIO.WriteChunk(Prj2Chunks.AnimatedTextureFrames)) { foreach (AnimatedTextureFrame frame in set.Frames) { using (var chunkAnimatedTextureFrame = chunkIO.WriteChunk(Prj2Chunks.AnimatedTextureFrame, 120)) { LEB128.Write(chunkIO.Raw, levelSettingIds.LevelTextures[frame.Texture]); chunkIO.Raw.Write(frame.TexCoord0); chunkIO.Raw.Write(frame.TexCoord1); chunkIO.Raw.Write(frame.TexCoord2); chunkIO.Raw.Write(frame.TexCoord3); LEB128.Write(chunkIO.Raw, frame.Repeat); } } chunkIO.WriteChunkEnd(); } chunkIO.WriteChunkEnd(); } } chunkIO.WriteChunkEnd(); } using (var chunkAutoMergeStatics = chunkIO.WriteChunk(Prj2Chunks.AutoMergeStaticMeshes, UInt16.MaxValue)) { foreach (var entry in settings.AutoStaticMeshMerges) { using (var chunkAutoMergeEntry = chunkIO.WriteChunk(Prj2Chunks.AutoMergeStaticMeshEntry3)) { chunkIO.Raw.Write(entry.meshId); chunkIO.Raw.Write(entry.InterpretShadesAsEffect); chunkIO.Raw.Write(entry.TintAsAmbient); chunkIO.Raw.Write(entry.ClearShades); } } chunkIO.WriteChunkEnd(); } using (var chunkPalette = chunkIO.WriteChunk(Prj2Chunks.Palette, UInt16.MaxValue)) { chunkIO.Raw.Write((ushort)settings.Palette.Count); foreach (var color in settings.Palette) { chunkIO.Raw.Write(color.R); chunkIO.Raw.Write(color.G); chunkIO.Raw.Write(color.B); } chunkIO.WriteChunkEnd(); } chunkIO.WriteChunkEnd(); }; return(levelSettingIds); }
private static void WriteMoveables(ChunkWriter chunkIO, Wad2 wad, List <WadTexture> textureTable) { chunkIO.WriteChunkWithChildren(Wad2Chunks.Moveables, () => { foreach (var moveable in wad.Moveables) { chunkIO.WriteChunkWithChildren(Wad2Chunks.Moveable, () => { var m = moveable.Value; LEB128.Write(chunkIO.Raw, m.Id.TypeId); foreach (var mesh in m.Meshes) { WriteMesh(chunkIO, mesh, textureTable); } foreach (var b in m.Bones) { chunkIO.WriteChunkWithChildren(Wad2Chunks.MoveableBoneNew, () => { LEB128.Write(chunkIO.Raw, (byte)b.OpCode); chunkIO.Raw.WriteStringUTF8(b.Name); chunkIO.WriteChunkVector3(Wad2Chunks.MoveableBoneTranslation, b.Translation); chunkIO.WriteChunkInt(Wad2Chunks.MoveableBoneMeshPointer, m.Bones.IndexOf(b)); }); } foreach (var animation in m.Animations) { chunkIO.WriteChunkWithChildren(Wad2Chunks.Animation2, () => { LEB128.Write(chunkIO.Raw, animation.StateId); LEB128.Write(chunkIO.Raw, animation.EndFrame); LEB128.Write(chunkIO.Raw, animation.FrameRate); LEB128.Write(chunkIO.Raw, animation.NextAnimation); LEB128.Write(chunkIO.Raw, animation.NextFrame); chunkIO.WriteChunkString(Wad2Chunks.AnimationName, animation.Name); foreach (var kf in animation.KeyFrames) { chunkIO.WriteChunkWithChildren(Wad2Chunks.KeyFrame, () => { chunkIO.WriteChunkVector3(Wad2Chunks.KeyFrameOffset, kf.Offset); chunkIO.WriteChunkWithChildren(Wad2Chunks.KeyFrameBoundingBox, () => { chunkIO.WriteChunkVector3(Wad2Chunks.MeshBoundingBoxMin, kf.BoundingBox.Minimum); chunkIO.WriteChunkVector3(Wad2Chunks.MeshBoundingBoxMax, kf.BoundingBox.Maximum); }); foreach (var angle in kf.Angles) { chunkIO.WriteChunkVector3(Wad2Chunks.KeyFrameAngle, angle.Rotations); } }); } foreach (var stateChange in animation.StateChanges) { chunkIO.WriteChunkWithChildren(Wad2Chunks.StateChange, () => { LEB128.Write(chunkIO.Raw, stateChange.StateId); foreach (var dispatch in stateChange.Dispatches) { chunkIO.WriteChunk(Wad2Chunks.Dispatch, () => { LEB128.Write(chunkIO.Raw, dispatch.InFrame); LEB128.Write(chunkIO.Raw, dispatch.OutFrame); LEB128.Write(chunkIO.Raw, dispatch.NextAnimation); LEB128.Write(chunkIO.Raw, dispatch.NextFrame); }); } }); } foreach (var command in animation.AnimCommands) { chunkIO.WriteChunkWithChildren(Wad2Chunks.AnimCommand, () => { LEB128.Write(chunkIO.Raw, (ushort)command.Type); LEB128.Write(chunkIO.Raw, command.Parameter1); LEB128.Write(chunkIO.Raw, command.Parameter2); LEB128.Write(chunkIO.Raw, command.Parameter3); chunkIO.WriteChunkInt(Wad2Chunks.AnimCommandSoundInfo, -1); }); } // New chunk for velocities chunkIO.WriteChunkVector4(Wad2Chunks.AnimationVelocities, new System.Numerics.Vector4(animation.StartVelocity, animation.EndVelocity, animation.StartLateralVelocity, animation.EndLateralVelocity)); }); } }); } }); }
public static void WriteMesh(ChunkWriter chunkIO, WadMesh mesh, List <WadTexture> textureTable) { chunkIO.WriteChunkWithChildren(Wad2Chunks.Mesh, () => { chunkIO.WriteChunkInt(Wad2Chunks.MeshIndex, 0); chunkIO.WriteChunkString(Wad2Chunks.MeshName, mesh.Name); // Write bounding sphere chunkIO.WriteChunkWithChildren(Wad2Chunks.MeshSphere, () => { chunkIO.WriteChunkVector3(Wad2Chunks.MeshSphereCenter, mesh.BoundingSphere.Center); chunkIO.WriteChunkFloat(Wad2Chunks.MeshSphereRadius, mesh.BoundingSphere.Radius); }); // Write bounding box chunkIO.WriteChunkWithChildren(Wad2Chunks.MeshBoundingBox, () => { chunkIO.WriteChunkVector3(Wad2Chunks.MeshBoundingBoxMin, mesh.BoundingBox.Minimum); chunkIO.WriteChunkVector3(Wad2Chunks.MeshBoundingBoxMax, mesh.BoundingBox.Maximum); }); // Write positions chunkIO.WriteChunkWithChildren(Wad2Chunks.MeshVertexPositions, () => { foreach (var pos in mesh.VerticesPositions) { chunkIO.WriteChunkVector3(Wad2Chunks.MeshVertexPosition, pos); } }); // Write normals chunkIO.WriteChunkWithChildren(Wad2Chunks.MeshVertexNormals, () => { foreach (var normal in mesh.VerticesNormals) { chunkIO.WriteChunkVector3(Wad2Chunks.MeshVertexNormal, normal); } }); // Write shades chunkIO.WriteChunkWithChildren(Wad2Chunks.MeshVertexShades, () => { foreach (var shade in mesh.VerticesShades) { chunkIO.WriteChunkInt(Wad2Chunks.MeshVertexShade, shade); } }); // Write polygons chunkIO.WriteChunkWithChildren(Wad2Chunks.MeshPolygons, () => { foreach (var poly in mesh.Polys) { bool isQuad = poly.Shape == WadPolygonShape.Quad; chunkIO.WriteChunkWithChildren(isQuad ? Wad2Chunks.MeshQuad : Wad2Chunks.MeshTriangle, () => { LEB128.Write(chunkIO.Raw, poly.Index0); LEB128.Write(chunkIO.Raw, poly.Index1); LEB128.Write(chunkIO.Raw, poly.Index2); if (isQuad) { LEB128.Write(chunkIO.Raw, poly.Index3); } LEB128.Write(chunkIO.Raw, poly.ShineStrength); LEB128.Write(chunkIO.Raw, textureTable.IndexOf(poly.Texture.Texture as WadTexture)); chunkIO.Raw.Write(poly.Texture.TexCoord0); chunkIO.Raw.Write(poly.Texture.TexCoord1); chunkIO.Raw.Write(poly.Texture.TexCoord2); if (isQuad) { chunkIO.Raw.Write(poly.Texture.TexCoord3); } LEB128.Write(chunkIO.Raw, (long)poly.Texture.BlendMode); chunkIO.Raw.Write(poly.Texture.DoubleSided); }); } }); }); }