public override Resource LoadResourceData(ScummBinaryReader reader, string resourceId, IDictionary <string, object> parameters) { var charset = new Charset(resourceId); uint blockSize = reader.FindDataBlock("CHAR"); if (blockSize == 0) { throw new InvalidOperationException("Could not find the script header block."); } // Load the room palette associated with the charset // (huge hack - I have no idea what to do when room is 0) if ((byte)parameters["RoomId"] == 0) { parameters["RoomId"] = (byte)10; } long keepPos = reader.BaseStream.Position; var roomPalette = this.resourceManager.Load <Room>("ROOM", (byte)parameters["RoomId"]).Palette; reader.BaseStream.Position = keepPos; // Read charset header information var unknown = reader.ReadBytes(6); byte[] colormap = new byte[16]; colormap[0] = 0; for (int i = 0; i < 15; ++i) { colormap[i + 1] = reader.ReadByte(); } long initPosition = reader.BaseStream.Position; byte numBitsPerPixel = reader.ReadByte(); byte bitMask = (byte)(0xFF << (8 - numBitsPerPixel)); byte fontHeight = reader.ReadByte(); short numChars = reader.ReadInt16(); uint[] offsets = new uint[numChars]; for (int i = 0; i < numChars; ++i) { offsets[i] = reader.ReadUInt32(); } // Read each char for (int i = 0; i < numChars; ++i) { if (offsets[i] == 0) { continue; } reader.BaseStream.Position = initPosition + offsets[i]; charset.Chars[i].width = reader.ReadByte(); charset.Chars[i].height = reader.ReadByte(); // a flag is needed to disable offX charset.Chars[i].offX = 0; reader.ReadByte(); charset.Chars[i].offY = reader.ReadByte(); charset.Chars[i].pic = new Texture2D(graphicsDevice, charset.Chars[i].width, charset.Chars[i].height); byte[] bytes = new byte[charset.Chars[i].width * charset.Chars[i].height * 4]; Byte bits = reader.ReadByte(); Byte remainingBits = 8; for (int y = 0; y < charset.Chars[i].height; ++y) { for (int x = 0; x < charset.Chars[i].width; ++x) { long colorId = (bits & bitMask) >> (8 - numBitsPerPixel); long color = colormap[colorId]; byte alpha = 255; if (colorId == 0) { alpha = 0; } bytes[(y * charset.Chars[i].width + x) * 4] = roomPalette[color].R; bytes[(y * charset.Chars[i].width + x) * 4 + 1] = roomPalette[color].G; bytes[(y * charset.Chars[i].width + x) * 4 + 2] = roomPalette[color].B; bytes[(y * charset.Chars[i].width + x) * 4 + 3] = alpha; bits = (byte)(bits << numBitsPerPixel); remainingBits -= numBitsPerPixel; if (remainingBits <= 0) { bits = reader.ReadByte(); remainingBits = 8; } } } charset.Chars[i].pic.SetData(bytes); } return(charset); }
private CostumeAnimation LoadAnimation(ScummBinaryReader reader, string resourceId, int animationIndex, long startOffset, ushort[] animationOffsets, ushort[] limbOffsets, ushort animationCommandOffset, byte[] palette, Color[] roomPalette, bool containsRedirection, bool mirror) { if (animationOffsets[animationIndex] == 0) { return(null); } reader.BaseStream.Position = startOffset + animationOffsets[animationIndex]; var costumeAnimation = new CostumeAnimation(); costumeAnimation.IsMirrored = mirror; var currentFrameIndex = 0; var framesCount = 0; var startAnimationPosition = reader.BaseStream.Position; while (currentFrameIndex < framesCount || currentFrameIndex == 0) { var mask = reader.ReadUInt16(); var costumeFrame = new CostumeFrame(); var imageData = new LayeredImageData(); var i = 0; do { if ((mask & 0x8000) != 0) { var startAnimationCommandOffset = reader.ReadUInt16(); if (startAnimationCommandOffset != 0xFFFF) { var flags = reader.ReadByte(); var loop = flags & 0x8000; var endFrame = flags & 0x7F; if (currentFrameIndex == 0 && framesCount == 0) { framesCount = Math.Max(framesCount, endFrame) + 1; } var oldStreamPosition = reader.BaseStream.Position; reader.BaseStream.Position = startOffset + animationCommandOffset + startAnimationCommandOffset + Math.Min(currentFrameIndex, endFrame); var animationCommandValue = reader.ReadByte(); if (animationCommandValue == 0x71) { // TODO: Handle special commands (sounds, etc.) } else if (animationCommandValue == 0x7A) { // TODO: Implement start command } else if (animationCommandValue == 0x79) { // TODO: Implement stopped command } else { reader.BaseStream.Position = startOffset + limbOffsets[i] + animationCommandValue * 2; var pictOffset = reader.ReadUInt16(); reader.BaseStream.Position = startOffset + pictOffset; var width = reader.ReadUInt16(); var height = reader.ReadUInt16(); var relativeX = reader.ReadInt16(); var relativeY = reader.ReadInt16(); var movementX = reader.ReadInt16(); var movementY = reader.ReadInt16(); if (containsRedirection) { var redirectionLimb = reader.ReadByte(); var redirectionPict = reader.ReadByte(); } imageData.CreateLayer(width, height, new Vector2(relativeX, relativeY)); DecodeImageData(reader, imageData, width, height, palette, roomPalette); } reader.BaseStream.Position = oldStreamPosition; } } mask = (ushort)(mask << 1); i++; } while ((mask & 0xFFFF) != 0); costumeFrame.FrameType = CostumeFrameType.Frame; // TODO: Fill offset and movement vector var textureData = imageData.GetBytes(); costumeFrame.Data = new Microsoft.Xna.Framework.Graphics.Texture2D(this.graphicsDevice, imageData.Width, imageData.Height, false, Microsoft.Xna.Framework.Graphics.SurfaceFormat.Color); costumeFrame.Data.SetData(textureData); costumeAnimation.Frames.Add(costumeFrame); if (!Directory.Exists("DebugAnims\\" + resourceId)) { Directory.CreateDirectory("DebugAnims\\" + resourceId); } costumeFrame.Data.SaveAsPng(File.Create(string.Format("DebugAnims\\" + resourceId + "\\Anim{0}_{1}.png", animationIndex, currentFrameIndex)), costumeFrame.Data.Width, costumeFrame.Data.Height); reader.BaseStream.Position = startAnimationPosition; currentFrameIndex++; } return(costumeAnimation); }