private static bool LoadSoundInfos(ChunkReader chunkIO, ChunkId idOuter, Wad2 wad, ref Dictionary <long, WadSoundInfo> outSoundInfos, Dictionary <long, WadSample> samples) { if (idOuter != Wad2Chunks.SoundInfos) { return(false); } var soundInfos = new Dictionary <long, WadSoundInfo>(); chunkIO.ReadChunks((id, chunkSize) => { if (id != Wad2Chunks.SoundInfo) { return(false); } WadSoundInfo soundInfo; long index; LoadSoundInfo(chunkIO, wad, samples, out soundInfo, out index); soundInfos.Add(index, soundInfo); return(true); }); outSoundInfos = soundInfos; return(true); }
private static bool LoadSprites(ChunkReader chunkIO, ChunkId idOuter, Wad2 wad, ref Dictionary <long, WadSprite> outSprites) { if (idOuter != Wad2Chunks.Sprites) { return(false); } var sprites = new Dictionary <long, WadSprite>(); long obsoleteIndex = 0; // Move this into each chunk once we got rid of old style *.wad2 files. chunkIO.ReadChunks((id, chunkSize) => { if (id != Wad2Chunks.Sprite) { return(false); } int width = LEB128.ReadInt(chunkIO.Raw); int height = LEB128.ReadInt(chunkIO.Raw); byte[] imageData = null; RectangleInt2 rect = new RectangleInt2(); chunkIO.ReadChunks((id2, chunkSize2) => { if (id2 == Wad2Chunks.SpriteIndex) { obsoleteIndex = chunkIO.ReadChunkLong(chunkSize2); } else if (id2 == Wad2Chunks.SpriteData) { imageData = chunkIO.ReadChunkArrayOfBytes(chunkSize2); } else if (id2 == Wad2Chunks.SpriteSides) { rect.X0 = chunkIO.Raw.ReadInt32(); rect.Y0 = chunkIO.Raw.ReadInt32(); rect.X1 = chunkIO.Raw.ReadInt32(); rect.Y1 = chunkIO.Raw.ReadInt32(); } else { return(false); } return(true); }); sprites.Add(obsoleteIndex++, new WadSprite { Texture = new WadTexture(ImageC.FromByteArray(imageData, width, height)), Alignment = rect }) ; return(true); }); outSprites = sprites; return(true); }
private static void WriteWad2(ChunkWriter chunkIO, Wad2 wad) { chunkIO.WriteChunkInt(Wad2Chunks.GameVersion, (long)wad.GameVersion); chunkIO.WriteChunkInt(Wad2Chunks.SoundSystem, (long)wad.SoundSystem); var meshTable = new List <WadMesh>(wad.MeshesUnique); var spriteTable = new List <WadSprite>(wad.SpriteSequences.Values.SelectMany(spriteSequence => spriteSequence.Sprites)); var textureTable = new List <WadTexture>(wad.MeshTexturesUnique); WriteTextures(chunkIO, textureTable); WriteSprites(chunkIO, spriteTable); WriteSpriteSequences(chunkIO, wad, spriteTable); WriteMoveables(chunkIO, wad, textureTable); WriteStatics(chunkIO, wad, textureTable); chunkIO.WriteChunkEnd(); }
private static bool LoadTextures(ChunkReader chunkIO, ChunkId idOuter, Wad2 wad, ref Dictionary <long, WadTexture> outTextures) { if (idOuter != Wad2Chunks.Textures) { return(false); } Dictionary <long, WadTexture> textures = new Dictionary <long, WadTexture>(); long obsoleteIndex = 0; // Move this into each chunk once we got rid of old style *.wad2 files. chunkIO.ReadChunks((id, chunkSize) => { if (id != Wad2Chunks.Texture) { return(false); } var width = LEB128.ReadInt(chunkIO.Raw); var height = LEB128.ReadInt(chunkIO.Raw); byte[] textureData = null; chunkIO.ReadChunks((id2, chunkSize2) => { if (id2 == Wad2Chunks.TextureIndex) { obsoleteIndex = chunkIO.ReadChunkLong(chunkSize2); } if (id2 == Wad2Chunks.TextureData) { textureData = chunkIO.ReadChunkArrayOfBytes(chunkSize2); } else { return(false); } return(true); }); var texture = ImageC.FromByteArray(textureData, width, height); texture.ReplaceColor(new ColorC(255, 0, 255, 255), new ColorC(0, 0, 0, 0)); textures.Add(obsoleteIndex++, new WadTexture(texture)); return(true); }); outTextures = textures; return(true); }
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); }); } }); }
public static void SaveToFile(Wad2 wad, string filename) { // We save first to a temporary memory stream using (var stream = new MemoryStream()) { SaveToStream(wad, stream); // Save to temporary file as well, so original wad2 won't vanish in case of crash var tempName = filename + ".tmp"; if (File.Exists(tempName)) { File.Delete(tempName); } stream.Seek(0, SeekOrigin.Begin); using (var writer = new BinaryWriter(new FileStream(tempName, FileMode.Create, FileAccess.Write, FileShare.None))) { var buffer = stream.ToArray(); writer.Write(buffer, 0, buffer.Length); } // Save successful, write temp file over original (if exists) if (File.Exists(filename)) { File.Delete(filename); } File.Move(tempName, filename); } // Save sounds to XML file if (wad.Sounds.SoundInfos.Count > 0) { string xmlFilename = Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename) + ".xml"); WadSounds.SaveToXml(xmlFilename, wad.Sounds); } }
private static Wad2 LoadWad2(ChunkReader chunkIO, bool obsolete) { if (obsolete) { LEB128.ReadUInt(chunkIO.Raw); } var wad = new Wad2(); Dictionary <long, WadTexture> textures = null; Dictionary <long, WadSample> samples = null; Dictionary <long, WadSoundInfo> soundInfos = null; Dictionary <long, WadSprite> sprites = null; wad.SoundSystem = SoundSystem.Dynamic; chunkIO.ReadChunks((id, chunkSize) => { if (id == Wad2Chunks.GameVersion) { wad.GameVersion = (TRVersion.Game)chunkIO.ReadChunkLong(chunkSize); return(true); } else if (id == Wad2Chunks.SoundSystem) { wad.SoundSystem = (SoundSystem)chunkIO.ReadChunkLong(chunkSize); return(true); } else if (LoadTextures(chunkIO, id, wad, ref textures)) { return(true); } else if (LoadSamples(chunkIO, id, wad, ref samples, obsolete)) { return(true); } else if (LoadSoundInfos(chunkIO, id, wad, ref soundInfos, samples)) { return(true); } else if (LoadFixedSoundInfos(chunkIO, id, wad, soundInfos)) { return(true); } else if (LoadAdditionalSoundInfos(chunkIO, id, wad, soundInfos, samples)) { return(true); } else if (LoadSprites(chunkIO, id, wad, ref sprites)) { return(true); } else if (LoadSpriteSequences(chunkIO, id, wad, sprites)) { return(true); } else if (LoadMoveables(chunkIO, id, wad, soundInfos, textures)) { return(true); } else if (LoadStatics(chunkIO, id, wad, textures)) { return(true); } return(false); }); if (obsolete) { foreach (KeyValuePair <long, WadSoundInfo> soundInfo in soundInfos) { if (TrCatalog.IsSoundFixedByDefault(TRVersion.Game.TR4, checked ((uint)soundInfo.Key))) { var Id = new WadFixedSoundInfoId(checked ((uint)soundInfo.Key)); wad.FixedSoundInfosObsolete.Add(Id, new WadFixedSoundInfo(Id) { SoundInfo = soundInfo.Value }); } } } // XML_SOUND_SYSTEM: Used for conversion of Wad2 to new sound system wad.AllLoadedSoundInfos = soundInfos; // Force wad to be xml wad in case there's no sound infos at all if (wad.SoundSystem != SoundSystem.Xml && wad.AllLoadedSoundInfos?.Count == 0) { wad.SoundSystem = SoundSystem.Xml; } return(wad); }
private static bool LoadAdditionalSoundInfos(ChunkReader chunkIO, ChunkId idOuter, Wad2 wad, Dictionary <long, WadSoundInfo> soundInfos, Dictionary <long, WadSample> samples) { if (idOuter == Wad2Chunks.AdditionalSoundInfosObsolete) { chunkIO.ReadChunks((id, chunkSize) => { if (id != Wad2Chunks.SoundInfo) { return(false); } WadSoundInfo soundInfo; long index; LoadSoundInfo(chunkIO, wad, samples, out soundInfo, out index); var wId = new WadAdditionalSoundInfoId("Unnamed " + soundInfo.Name); wad.AdditionalSoundInfosObsolete.Add(wId, new WadAdditionalSoundInfo(wId) { SoundInfo = soundInfo }); return(true); }); return(true); } else if (idOuter == Wad2Chunks.AdditionalSoundInfos) { var additionalSoundInfos = new SortedList <WadAdditionalSoundInfoId, WadAdditionalSoundInfo>(); chunkIO.ReadChunks((id, chunkSize) => { if (id != Wad2Chunks.AdditionalSoundInfo) { return(false); } string soundName = null; int SoundInfoId = -1; chunkIO.ReadChunks((id2, chunkSize2) => { if (id2 == Wad2Chunks.AdditionalSoundInfoName) { soundName = chunkIO.ReadChunkString(chunkSize2); } else if (id2 == Wad2Chunks.AdditionalSoundInfoSoundInfoId) { SoundInfoId = chunkIO.ReadChunkInt(chunkSize2); } else { return(false); } return(true); }); var Id = new WadAdditionalSoundInfoId(soundName); additionalSoundInfos.Add(Id, new WadAdditionalSoundInfo(Id) { SoundInfo = soundInfos[SoundInfoId] }); return(true); }); wad.AdditionalSoundInfosObsolete = additionalSoundInfos; return(true); } return(false); }
private static bool LoadFixedSoundInfos(ChunkReader chunkIO, ChunkId idOuter, Wad2 wad, Dictionary <long, WadSoundInfo> soundInfos) { if (idOuter != Wad2Chunks.FixedSoundInfos) { return(false); } var fixedSoundInfos = new SortedList <WadFixedSoundInfoId, WadFixedSoundInfo>(); chunkIO.ReadChunks((id, chunkSize) => { if (id != Wad2Chunks.FixedSoundInfo) { return(false); } int soundId = -1; int SoundInfoId = -1; chunkIO.ReadChunks((id2, chunkSize2) => { if (id2 == Wad2Chunks.FixedSoundInfoId) { soundId = chunkIO.ReadChunkInt(chunkSize2); } else if (id2 == Wad2Chunks.FixedSoundInfoSoundInfoId) { SoundInfoId = chunkIO.ReadChunkInt(chunkSize2); } else { return(false); } return(true); }); if (soundId == -1 || SoundInfoId == -1) { throw new Exception("Invalid fixed sound info."); } var Id = new WadFixedSoundInfoId(checked ((uint)soundId)); fixedSoundInfos.Add(Id, new WadFixedSoundInfo(Id) { SoundInfo = soundInfos[SoundInfoId] }); return(true); }); wad.FixedSoundInfosObsolete = fixedSoundInfos; return(true); }
private static bool LoadSoundInfo(ChunkReader chunkIO, Wad2 wad, Dictionary <long, WadSample> samples, out WadSoundInfo soundInfo, out long index) { var tempSoundInfo = new WadSoundInfo(0); long tempIndex = 0; float volume = 0; float chance = 0; float pitch = 0; float range = 0; chunkIO.ReadChunks((id2, chunkSize2) => { // XML_SOUND_SYSTEM if (id2 == Wad2Chunks.SoundInfoIndex) { tempIndex = chunkIO.ReadChunkLong(chunkSize2); } else if (id2 == Wad2Chunks.SoundInfoVolume) { volume = chunkIO.ReadChunkFloat(chunkSize2); } else if (id2 == Wad2Chunks.SoundInfoRange) { range = chunkIO.ReadChunkFloat(chunkSize2); } else if (id2 == Wad2Chunks.SoundInfoPitch) { pitch = chunkIO.ReadChunkFloat(chunkSize2); } else if (id2 == Wad2Chunks.SoundInfoChance) { chance = chunkIO.ReadChunkFloat(chunkSize2); } else if (id2 == Wad2Chunks.SoundInfoDisablePanning) { tempSoundInfo.DisablePanning = chunkIO.ReadChunkBool(chunkSize2); } else if (id2 == Wad2Chunks.SoundInfoRandomizePitch) { tempSoundInfo.RandomizePitch = chunkIO.ReadChunkBool(chunkSize2); } else if (id2 == Wad2Chunks.SoundInfoRandomizeVolume) { tempSoundInfo.RandomizeVolume = chunkIO.ReadChunkBool(chunkSize2); } else if (id2 == Wad2Chunks.SoundInfoLoopBehaviour) { tempSoundInfo.LoopBehaviour = (WadSoundLoopBehaviour)(3 & chunkIO.ReadChunkByte(chunkSize2)); } else if (id2 == Wad2Chunks.SoundInfoName || id2 == Wad2Chunks.SoundInfoNameObsolete) { tempSoundInfo.Name = chunkIO.ReadChunkString(chunkSize2); } else if (id2 == Wad2Chunks.SoundInfoSampleIndex) { tempSoundInfo.Samples.Add(samples[chunkIO.ReadChunkInt(chunkSize2)]); // Legacy } else { return(false); } return(true); }); // Convert from floats to ints tempSoundInfo.Volume = (int)Math.Round(volume * 100.0f); tempSoundInfo.RangeInSectors = (int)range; tempSoundInfo.Chance = (int)Math.Round(chance * 100.0f); tempSoundInfo.PitchFactor = (int)Math.Round((pitch - 1.0f) * 100.0f); // Try to get the old ID tempSoundInfo.Id = TrCatalog.TryGetSoundInfoIdByDescription(wad.GameVersion, tempSoundInfo.Name); if (string.IsNullOrWhiteSpace(tempSoundInfo.Name)) { tempSoundInfo.Name = TrCatalog.GetOriginalSoundName(wad.GameVersion, unchecked ((uint)tempIndex)); } index = tempIndex; soundInfo = tempSoundInfo; return(true); }
private static bool LoadStatics(ChunkReader chunkIO, ChunkId idOuter, Wad2 wad, /*Dictionary<long, WadMesh> meshes*/ Dictionary <long, WadTexture> textures) { if (idOuter != Wad2Chunks.Statics) { return(false); } chunkIO.ReadChunks((id, chunkSize) => { if (id != Wad2Chunks.Static) { return(false); } var s = new WadStatic(new WadStaticId(LEB128.ReadUInt(chunkIO.Raw))); //s.Mesh = meshes[LEB128.ReadInt(chunkIO.Raw)]; s.Flags = LEB128.ReadShort(chunkIO.Raw); s.LightingType = (WadMeshLightingType)LEB128.ReadShort(chunkIO.Raw); chunkIO.ReadChunks((id2, chunkSize2) => { if (id2 == Wad2Chunks.StaticVisibilityBox) { var min = Vector3.Zero; var max = Vector3.Zero; chunkIO.ReadChunks((id3, chunkSize3) => { if (id3 == Wad2Chunks.MeshBoundingBoxMin) { min = chunkIO.ReadChunkVector3(chunkSize3); } else if (id3 == Wad2Chunks.MeshBoundingBoxMax) { max = chunkIO.ReadChunkVector3(chunkSize3); } else { return(false); } return(true); }); s.VisibilityBox = new BoundingBox(min, max); } else if (id2 == Wad2Chunks.StaticCollisionBox) { var min = Vector3.Zero; var max = Vector3.Zero; chunkIO.ReadChunks((id3, chunkSize3) => { if (id3 == Wad2Chunks.MeshBoundingBoxMin) { min = chunkIO.ReadChunkVector3(chunkSize3); } else if (id3 == Wad2Chunks.MeshBoundingBoxMax) { max = chunkIO.ReadChunkVector3(chunkSize3); } else { return(false); } return(true); }); s.CollisionBox = new BoundingBox(min, max); } else if (id2 == Wad2Chunks.Mesh) { s.Mesh = LoadMesh(chunkIO, chunkSize2, textures); } else if (id2 == Wad2Chunks.StaticAmbientLight) { s.AmbientLight = chunkIO.ReadChunkShort(chunkSize2); } else if (id2 == Wad2Chunks.StaticLight) { var light = new WadLight(); chunkIO.ReadChunks((id3, chunkSize3) => { if (id3 == Wad2Chunks.StaticLightPosition) { light.Position = chunkIO.ReadChunkVector3(chunkSize3); } else if (id3 == Wad2Chunks.StaticLightRadius) { light.Radius = chunkIO.ReadChunkFloat(chunkSize3); } else if (id3 == Wad2Chunks.StaticLightIntensity) { light.Intensity = chunkIO.ReadChunkFloat(chunkSize3); } else { return(false); } return(true); }); s.Lights.Add(light); } else { return(false); } return(true); }); wad.Statics.Add(s.Id, s); return(true); }); return(true); }
public static void SaveToBinaryWriterFast(Wad2 wad, BinaryWriterFast fastWriter) { using (var chunkIO = new ChunkWriter(Wad2Chunks.MagicNumber, fastWriter)) WriteWad2(chunkIO, wad); }
public static void SaveToStream(Wad2 wad, Stream stream) { using (var chunkIO = new ChunkWriter(Wad2Chunks.MagicNumber, stream, ChunkWriter.Compression.None)) WriteWad2(chunkIO, wad); }
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)); }); } }); } }); }
private static bool LoadSpriteSequences(ChunkReader chunkIO, ChunkId idOuter, Wad2 wad, Dictionary <long, WadSprite> sprites) { if (idOuter != Wad2Chunks.SpriteSequences) { return(false); } var spriteSequences = new SortedList <WadSpriteSequenceId, WadSpriteSequence>(); chunkIO.ReadChunks((id, chunkSize) => { if (id != Wad2Chunks.SpriteSequence) { return(false); } var s = new WadSpriteSequence(new WadSpriteSequenceId(LEB128.ReadUInt(chunkIO.Raw))); chunkIO.ReadChunks((id2, chunkSize2) => { if (id2 == Wad2Chunks.SpriteSequenceSpriteIndex) { s.Sprites.Add(sprites[chunkIO.ReadChunkInt(chunkSize2)]); } else { return(false); } return(true); }); spriteSequences.Add(s.Id, s); return(true); }); wad.SpriteSequences = spriteSequences; return(true); }
private static bool LoadMoveables(ChunkReader chunkIO, ChunkId idOuter, Wad2 wad, Dictionary <long, WadSoundInfo> soundInfos, Dictionary <long, WadTexture> textures) { if (idOuter != Wad2Chunks.Moveables) { return(false); } chunkIO.ReadChunks((id, chunkSize) => { if (id != Wad2Chunks.Moveable) { return(false); } uint objTypeId = LEB128.ReadUInt(chunkIO.Raw); var mov = new WadMoveable(new WadMoveableId(objTypeId)); var meshes = new List <WadMesh>(); chunkIO.ReadChunks((id2, chunkSize2) => { if (id2 == Wad2Chunks.Mesh) { var mesh = LoadMesh(chunkIO, chunkSize2, textures); meshes.Add(mesh); } else if (id2 == Wad2Chunks.MoveableBone) { var skeleton = LoadBone(chunkIO, mov, meshes); // Now convert the skeleton in the new (?) format. Ugly system but this is required for // setting exact hardcoded ID for some moveables (i.e. gun mesh of an enemy, the engine // has hardcoded mesh indices for effects) var bones = new List <WadBone>(); var root = new WadBone(); root.Name = skeleton.Name; root.Translation = Vector3.Zero; root.Mesh = skeleton.Mesh; bones.Add(root); BuildNewMeshTree(skeleton, bones); mov.Bones.AddRange(bones); } else if (id2 == Wad2Chunks.MoveableBoneNew) { var bone = new WadBone(); bone.OpCode = (WadLinkOpcode)LEB128.ReadByte(chunkIO.Raw); bone.Name = chunkIO.Raw.ReadStringUTF8(); chunkIO.ReadChunks((id3, chunkSize3) => { if (id3 == Wad2Chunks.MoveableBoneTranslation) { bone.Translation = chunkIO.ReadChunkVector3(chunkSize); } else if (id3 == Wad2Chunks.MoveableBoneMeshPointer) { bone.Mesh = meshes[chunkIO.ReadChunkInt(chunkSize)]; } else { return(false); } return(true); }); mov.Bones.Add(bone); } else if (id2 == Wad2Chunks.AnimationObsolete || id2 == Wad2Chunks.Animation || id2 == Wad2Chunks.Animation2) { var animation = new WadAnimation(); animation.StateId = LEB128.ReadUShort(chunkIO.Raw); animation.EndFrame = LEB128.ReadUShort(chunkIO.Raw); animation.FrameRate = LEB128.ReadByte(chunkIO.Raw); if (id2 == Wad2Chunks.AnimationObsolete) { LEB128.ReadUShort(chunkIO.Raw); LEB128.ReadUShort(chunkIO.Raw); } int oldSpeed, oldAccel, oldLatSpeed, oldLatAccel; oldSpeed = oldAccel = oldLatSpeed = oldLatAccel = 0; if (id2 != Wad2Chunks.Animation2) { // Use old speeds/accels for legacy chunk versions oldSpeed = LEB128.ReadInt(chunkIO.Raw); oldAccel = LEB128.ReadInt(chunkIO.Raw); oldLatSpeed = LEB128.ReadInt(chunkIO.Raw); oldLatAccel = LEB128.ReadInt(chunkIO.Raw); // Correct EndFrame for legacy chunk versions if (animation.EndFrame > 0) { animation.EndFrame--; } } // Fix possibly corrupted EndFrame value which was caused by bug introduced in 1.2.9 if (animation.EndFrame == ushort.MaxValue) { animation.EndFrame = 0; } animation.NextAnimation = LEB128.ReadUShort(chunkIO.Raw); animation.NextFrame = LEB128.ReadUShort(chunkIO.Raw); bool foundNewVelocitiesChunk = false; chunkIO.ReadChunks((id3, chunkSize3) => { if (id3 == Wad2Chunks.AnimationName) { animation.Name = chunkIO.ReadChunkString(chunkSize3); } else if (id3 == Wad2Chunks.AnimationVelocities) { foundNewVelocitiesChunk = true; var velocities = chunkIO.ReadChunkVector4(chunkSize); animation.StartVelocity = velocities.X; animation.EndVelocity = velocities.Y; animation.StartLateralVelocity = velocities.Z; animation.EndLateralVelocity = velocities.W; } else if (id3 == Wad2Chunks.KeyFrame) { var keyframe = new WadKeyFrame(); chunkIO.ReadChunks((id4, chunkSize4) => { if (id4 == Wad2Chunks.KeyFrameOffset) { keyframe.Offset = chunkIO.ReadChunkVector3(chunkSize4); } else if (id4 == Wad2Chunks.KeyFrameBoundingBox) { var kfMin = Vector3.Zero; var kfMax = Vector3.Zero; chunkIO.ReadChunks((id5, chunkSize5) => { if (id5 == Wad2Chunks.MeshBoundingBoxMin) { kfMin = chunkIO.ReadChunkVector3(chunkSize5); } else if (id5 == Wad2Chunks.MeshBoundingBoxMax) { kfMax = chunkIO.ReadChunkVector3(chunkSize5); } else { return(false); } return(true); }); keyframe.BoundingBox = new BoundingBox(kfMin, kfMax); } else if (id4 == Wad2Chunks.KeyFrameAngle) { var angle = new WadKeyFrameRotation(); angle.Rotations = chunkIO.ReadChunkVector3(chunkSize4); keyframe.Angles.Add(angle); } else { return(false); } return(true); }); animation.KeyFrames.Add(keyframe); } else if (id3 == Wad2Chunks.StateChange) { var stateChange = new WadStateChange(); stateChange.StateId = LEB128.ReadUShort(chunkIO.Raw); chunkIO.ReadChunks((id4, chunkSize4) => { if (id4 == Wad2Chunks.Dispatch) { var dispatch = new WadAnimDispatch(); dispatch.InFrame = LEB128.ReadUShort(chunkIO.Raw); dispatch.OutFrame = LEB128.ReadUShort(chunkIO.Raw); dispatch.NextAnimation = LEB128.ReadUShort(chunkIO.Raw); dispatch.NextFrame = LEB128.ReadUShort(chunkIO.Raw); stateChange.Dispatches.Add(dispatch); } else { return(false); } return(true); }); animation.StateChanges.Add(stateChange); } else if (id3 == Wad2Chunks.AnimCommand) { var command = new WadAnimCommand(); long offset = chunkIO.Raw.BaseStream.Position; command.Type = (WadAnimCommandType)LEB128.ReadUShort(chunkIO.Raw); command.Parameter1 = LEB128.ReadShort(chunkIO.Raw); command.Parameter2 = LEB128.ReadShort(chunkIO.Raw); command.Parameter3 = LEB128.ReadShort(chunkIO.Raw); chunkIO.ReadChunks((id4, chunkSize4) => { if (id4 == Wad2Chunks.AnimCommandSoundInfo) { var info = chunkIO.ReadChunkInt(chunkSize4); if (info != -1) { command.SoundInfoObsolete = soundInfos[info]; } return(true); } else { return(false); } }); animation.AnimCommands.Add(command); } else { return(false); } return(true); }); // Legacy code for calculating start and end velocities if (!foundNewVelocitiesChunk) { float acceleration = oldAccel / 65536.0f; animation.StartVelocity = oldSpeed / 65536.0f; animation.EndVelocity = animation.StartVelocity + acceleration * (animation.KeyFrames.Count - 1) * animation.FrameRate; float lateralAcceleration = oldLatAccel / 65536.0f; animation.StartLateralVelocity = oldLatSpeed / 65536.0f; animation.EndLateralVelocity = animation.StartLateralVelocity + lateralAcceleration * (animation.KeyFrames.Count - 1) * animation.FrameRate; } mov.Animations.Add(animation); } else { return(false); } return(true); }); wad.Moveables.Add(mov.Id, mov); return(true); }); return(true); }
private static bool LoadSamples(ChunkReader chunkIO, ChunkId idOuter, Wad2 wad, ref Dictionary <long, WadSample> outSamples, bool obsolete) { if (idOuter != Wad2Chunks.Samples) { return(false); } var samples = new Dictionary <long, WadSample>(); long obsoleteIndex = 0; // Move this into each chunk once we got rid of old style *.wad2 files. chunkIO.ReadChunks((id, chunkSize) => { if (id != Wad2Chunks.Sample) { return(false); } string FilenameObsolete = null; byte[] data = null; chunkIO.ReadChunks((id2, chunkSize2) => { if (id2 == Wad2Chunks.SampleIndex) { obsoleteIndex = chunkIO.ReadChunkLong(chunkSize2); } else if (id2 == Wad2Chunks.SampleFilenameObsolete) { FilenameObsolete = chunkIO.ReadChunkString(chunkSize2); } else if (id2 == Wad2Chunks.SampleData) { data = chunkIO.ReadChunkArrayOfBytes(chunkSize2); } else { return(false); } return(true); }); if (data == null && !string.IsNullOrEmpty(FilenameObsolete)) { string fullPath = Path.Combine(PathC.GetDirectoryNameTry(Assembly.GetEntryAssembly().Location), "Sounds\\TR4\\Samples", FilenameObsolete + ".wav"); data = File.ReadAllBytes(fullPath); } samples.Add(obsoleteIndex++, new WadSample("", WadSample.ConvertSampleFormat(data, sampleRate => obsolete ? new WadSample.ResampleInfo { Resample = false, SampleRate = WadSample.GameSupportedSampleRate } : new WadSample.ResampleInfo { Resample = true, SampleRate = sampleRate }))); return(true); }); outSamples = samples; return(true); }