public Mapd(SegmentStream stream) { // This is damn ugly, but it seems MAPD uses offsets from lvl start. var basePosition = ((SegmentStream)stream.BaseStream).BaseStream.Position - 8; var test = stream.ReadInt32(); stream.Position += test * 4; var generation = stream.ReadInt32() == 256 ? Generation.Gen1 : Generation.Gen2; stream.Position -= (test + 2) * 4; if (generation == Generation.Gen2) { stream.ReadInt32(); // Unk } var layerOffsets = new int[stream.ReadInt32()]; Layers = new MapdLayer[layerOffsets.Length]; for (var i = 0; i < layerOffsets.Length; i++) { layerOffsets[i] = stream.ReadInt32(); } var palette = new byte[stream.ReadInt32() * 4]; if (generation == Generation.Gen2) { for (var i = 0; i < palette.Length;) { var color16 = stream.ReadUInt16(); // aRRRRRGGGGGBBBBB palette[i++] = (byte)(((color16 & 0x7c00) >> 7) & 0xff); palette[i++] = (byte)(((color16 & 0x03e0) >> 2) & 0xff); palette[i++] = (byte)(((color16 & 0x001f) << 3) & 0xff); palette[i++] = 0xff; } } else { stream.Read(palette); for (var i = 0; i < palette.Length / 4; i++) { palette[i * 4 + 3] = 0xff; } } for (var i = 0; i < Layers.Length; i++) { stream.Position = layerOffsets[i] - basePosition; var type = new string(stream.ReadASCII(4).Reverse().ToArray()); if (type != "SCRL") { throw new Exception("Unknown type."); } var tileWidth = stream.ReadInt32(); var tileHeight = stream.ReadInt32(); var tilesX = stream.ReadInt32(); var tilesY = stream.ReadInt32(); if (generation == Generation.Gen2) { stream.ReadInt32(); // Unk stream.ReadInt32(); // Unk stream.ReadInt32(); // Unk } var tilePixels = new Dictionary <int, byte[]>(); var tiles = new List <int>(); for (var y = 0; y < tilesY; y++) { for (var x = 0; x < tilesX; x++) { var tile = stream.ReadInt32(); if (generation == Generation.Gen2) { tile -= tile % 4; } tiles.Add(tile); if (tile != 0 && !tilePixels.ContainsKey(tile)) { tilePixels.Add(tile, new byte[tileWidth * tileHeight * 4]); } } } foreach (var(offset, pixels) in tilePixels) { stream.Position = offset - basePosition; if (generation == Generation.Gen1) { stream.ReadInt32(); // Unk } for (var y = 0; y < tileHeight; y++) { for (var x = 0; x < tileWidth; x++) { var index = stream.ReadByte(); if (index == 0 && i != 0) { continue; } Array.Copy(palette, index * 4, pixels, (y * tileWidth + x) * 4, 4); } } } var layer = new MapdLayer(tilesX * tileWidth, tilesY * tileHeight); Layers[i] = layer; for (var y = 0; y < tilesY; y++) { for (var x = 0; x < tilesX; x++) { var tile = tiles[y * tilesX + x]; if (tile == 0) { continue; } var pixels = tilePixels[tile]; var offset = (y * tileHeight * tilesX + x) * tileWidth; for (var row = 0; row < tileHeight; row++) { Array.Copy(pixels, row * tileWidth * 4, layer.Pixels, (offset + row * layer.Width) * 4, tileWidth * 4); } } } } }
public uint[,] ApplyFrame(uint[,] oldFrame, ref uint[] palette, ref string textData) { var width = oldFrame.GetLength(1); var height = oldFrame.GetLength(0); var newFrame = new uint[height, width]; // We use Buffer.BlockCopy as Array.Copy does not properly handle 2d array! var shift = (globalMotion.X + globalMotion.Y * width) * 4; if (shift >= 0) { Buffer.BlockCopy(oldFrame, shift, newFrame, 0, oldFrame.Length * 4 - shift); } else { Buffer.BlockCopy(oldFrame, 0, newFrame, -shift, oldFrame.Length * 4 + shift); } int[] patterns = { 0x0660, 0xFF00, 0xCCCC, 0xF000, 0x8888, 0x000F, 0x1111, 0xFEC8, 0x8CEF, 0x137F, 0xF731, 0xC800, 0x008C, 0x0013, 0x3100, 0xCC00, 0x00CC, 0x0033, 0x3300, 0x0FF0, 0x6666, 0x00F0, 0x0F00, 0x2222, 0x4444, 0xF600, 0x8CC8, 0x006F, 0x1331, 0x318C, 0xC813, 0x33CC, 0x6600, 0x0CC0, 0x0066, 0x0330, 0xF900, 0xC88C, 0x009F, 0x3113, 0x6000, 0x0880, 0x0006, 0x0110, 0xCC88, 0xFC00, 0x00CF, 0x88CC, 0x003F, 0x1133, 0x3311, 0xF300, 0x6FF6, 0x0603, 0x08C6, 0x8C63, 0xC631, 0x6310, 0xC060, 0x0136, 0x136C, 0x36C8, 0x6C80, 0x324C }; if (colors != null) { colors.Position = 0; var firstIndex = colors.ReadUInt8(); var numColors = (colors.ReadUInt8() - 1) & 0xff; for (var i = 0; i <= numColors; i++) { palette[firstIndex + i] = (uint)((0xff << 24) | (colors.ReadUInt8() << 16) | (colors.ReadUInt8() << 8) | (colors.ReadUInt8() << 0)); } } video.Position = 0; for (var by = 0; by < height / 4; by++) { for (var bx = 0; bx < width / 4;) { var blockTypes = video.ReadUInt8(); for (var i = 0; i < 4; i++, bx++) { var blockType = (blockTypes >> (6 - i * 2)) & 0x03; switch (blockType) { case 0: { break; } case 1: { var motion = video.ReadUInt8(); if (motion == 0) { for (var y = 0; y < 4; y++) { for (var x = 0; x < 4; x++) { newFrame[by * 4 + y, bx * 4 + x] = palette[video.ReadByte()]; } } } else { var motionX = ((motion & 0xf) ^ 8) - 8; var motionY = ((motion >> 4) ^ 8) - 8; for (var y = 0; y < 4; y++) { for (var x = 0; x < 4; x++) { newFrame[by * 4 + y, bx * 4 + x] = oldFrame[by * 4 + y + globalMotion.Y + motionY, bx * 4 + x + globalMotion.X + motionX]; } } } break; } case 2: { var color = palette[video.ReadUInt8()]; for (var y = 0; y < 4; y++) { for (var x = 0; x < 4; x++) { newFrame[by * 4 + y, bx * 4 + x] = color; } } break; } case 3: { var patternData = video.ReadUInt8(); var patternType = patternData >> 6; var pattern = patterns[patternData & 0x3f]; switch (patternType) { case 0: { var pixel0 = palette[video.ReadUInt8()]; var pixel1 = palette[video.ReadUInt8()]; for (var y = 0; y < 4; y++) { for (var x = 0; x < 4; x++) { newFrame[by * 4 + y, bx * 4 + x] = ((pattern >> (y * 4 + x)) & 1) == 0 ? pixel0 : pixel1; } } break; } case 1: { var pixel = palette[video.ReadUInt8()]; for (var y = 0; y < 4; y++) { for (var x = 0; x < 4; x++) { if (((pattern >> (y * 4 + x)) & 1) == 1) { newFrame[by * 4 + y, bx * 4 + x] = pixel; } } } break; } case 2: { var pixel = palette[video.ReadUInt8()]; for (var y = 0; y < 4; y++) { for (var x = 0; x < 4; x++) { if (((pattern >> (y * 4 + x)) & 1) == 0) { newFrame[by * 4 + y, bx * 4 + x] = pixel; } } } break; } } break; } } } } } if (Text != null) { textData = Text; } return(newFrame); }