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 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 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 WadMesh LoadMesh(ChunkReader chunkIO, long chunkSize, Dictionary <long, WadTexture> textures) { var mesh = new WadMesh(); long obsoleteIndex = 0; chunkIO.ReadChunks((id2, chunkSize2) => { if (id2 == Wad2Chunks.MeshIndex) { obsoleteIndex = chunkIO.ReadChunkLong(chunkSize2); } else if (id2 == Wad2Chunks.MeshName) { mesh.Name = chunkIO.ReadChunkString(chunkSize2); } else if (id2 == Wad2Chunks.MeshSphere) { // Read bounding sphere float radius = 0; Vector3 center = Vector3.Zero; chunkIO.ReadChunks((id3, chunkSize3) => { if (id3 == Wad2Chunks.MeshSphereCenter) { center = chunkIO.ReadChunkVector3(chunkSize3); } else if (id3 == Wad2Chunks.MeshSphereRadius) { radius = chunkIO.ReadChunkFloat(chunkSize3); } else { return(false); } return(true); }); mesh.BoundingSphere = new BoundingSphere(center, radius); } else if (id2 == Wad2Chunks.MeshBoundingBox) { // Read bounding box Vector3 min = Vector3.Zero; Vector3 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); }); mesh.BoundingBox = new BoundingBox(min, max); } else if (id2 == Wad2Chunks.MeshVertexPositions) { chunkIO.ReadChunks((id3, chunkSize3) => { if (id3 == Wad2Chunks.MeshVertexPosition) { mesh.VerticesPositions.Add(chunkIO.ReadChunkVector3(chunkSize3)); } else { return(false); } return(true); }); } else if (id2 == Wad2Chunks.MeshVertexNormals) { chunkIO.ReadChunks((id3, chunkSize3) => { if (id3 == Wad2Chunks.MeshVertexNormal) { mesh.VerticesNormals.Add(chunkIO.ReadChunkVector3(chunkSize3)); } else { return(false); } return(true); }); } else if (id2 == Wad2Chunks.MeshVertexShades) { chunkIO.ReadChunks((id3, chunkSize3) => { if (id3 == Wad2Chunks.MeshVertexShade) { mesh.VerticesShades.Add(chunkIO.ReadChunkShort(chunkSize3)); } else { return(false); } return(true); }); } else if (id2 == Wad2Chunks.MeshPolygons) { chunkIO.ReadChunks((id3, chunkSize3) => { if (id3 == Wad2Chunks.MeshQuad || id3 == Wad2Chunks.MeshTriangle) { var polygon = new WadPolygon(); polygon.Shape = id3 == Wad2Chunks.MeshQuad ? WadPolygonShape.Quad : WadPolygonShape.Triangle; polygon.Index0 = LEB128.ReadInt(chunkIO.Raw); polygon.Index1 = LEB128.ReadInt(chunkIO.Raw); polygon.Index2 = LEB128.ReadInt(chunkIO.Raw); if (id3 == Wad2Chunks.MeshQuad) { polygon.Index3 = LEB128.ReadInt(chunkIO.Raw); } polygon.ShineStrength = LEB128.ReadByte(chunkIO.Raw); TextureArea textureArea = new TextureArea(); textureArea.Texture = textures[LEB128.ReadInt(chunkIO.Raw)]; textureArea.TexCoord0 = chunkIO.Raw.ReadVector2(); textureArea.TexCoord1 = chunkIO.Raw.ReadVector2(); textureArea.TexCoord2 = chunkIO.Raw.ReadVector2(); if (id3 == Wad2Chunks.MeshQuad) { textureArea.TexCoord3 = chunkIO.Raw.ReadVector2(); } else { textureArea.TexCoord3 = textureArea.TexCoord2; } textureArea.BlendMode = (BlendMode)LEB128.ReadLong(chunkIO.Raw); textureArea.DoubleSided = chunkIO.Raw.ReadBoolean(); polygon.Texture = textureArea; chunkIO.ReadChunks((id4, chunkSize4) => { return(false); }); mesh.Polys.Add(polygon); } else { return(false); } return(true); }); } else { return(false); } return(true); }); return(mesh); }