private static Block LoadBlock(byte[] data) { var block = new Block(); var outerStream = new BitStream(data); var buf = new byte[4]; outerStream.Read(buf, 32); // total wrapper data size outerStream.Read(buf, 32); var inflatedSize = Util.MakeI32(buf); outerStream.Read(buf, 16); block.X = Util.MakeI16(buf); outerStream.Read(buf, 16); block.Y = Util.MakeI16(buf); outerStream.Read(buf, 16); // ignored outerStream.Read(buf, 16); var sliceCount = Util.MakeU16(buf); outerStream.Read(buf, 8); var extraEagerSlice = buf[0] != 0; Trace("block {0:X4} {1:X4} {2}", block.X, block.Y, extraEagerSlice); // in the original source it's 17, which is the total of the sizes of the fields read above. // however, here we pass 19 instead of 17 so as to skip the 2-byte zlib header of 78 9C if (data[17] != 0x78 || data[18] != 0x9c) throw new InvalidDataException(); var deflate = new DeflateStream(new MemoryStream(data, 19, data.Length - 19), CompressionMode.Decompress); var innerData = new byte[inflatedSize]; deflate.Read(innerData, 0, inflatedSize); // var innerStream = new BitStream(innerData); // innerStream.Read(buf, 32); // var innerDataSize = Util.MakeI32(buf); // innerStream.Read(buf, 16); // var more = Util.MakeU16(buf) > 4; // innerStream.Read(buf, 8); // var something3 = buf[0]; // innerStream.Read(buf, 8); // var something4 = buf[0]; // innerStream.Read(buf, 8); // ignored // if (more) { // innerStream.Read(buf, 32); // innerStream.Read(buf, 16); // innerStream.Read(buf, 16); // } // Trace("{0:X4} {1:X4} {2:X4} | {3}", something1, something2, somethingCount, Hexify(innerData)); var innerStream = new BitStream(innerData); var innerDataPos = 0; for (var i = 0; i <= sliceCount; ++i) { if (i == sliceCount && !extraEagerSlice) break; var innerDataSize = Util.MakeI32(innerData, innerDataPos); innerStream.BitPosition = innerDataPos * 8; // the game streams in all but the optional last slice. uncomment // this conditional to match the actual game's loading order //if (i >= sliceCount) block.Slices.Add(LoadSlice(innerStream)); innerDataPos += innerDataSize; } return block; }
private void DrawProp(Graphics canvas, Block block, Slice slice, Prop prop) { //Console.WriteLine("{0} {1} {2}", prop.PropGroup, prop.Y, y); var sprite = sprites.LoadProp(prop.PropSet, prop.PropGroup, prop.PropIndex, prop.Palette); if (sprite == null) return; var dstRect = new Rectangle((int) prop.X, (int) prop.Y, sprite.Hitbox.Width, sprite.Hitbox.Height); // no idea what the deal with this is. it isn't perfect, but it's at least closer than just using the raw numbers, usually… // no idea what significance the constants have. dstRect.Y += (dstRect.Y / 232) * 32; dstRect.X -= (dstRect.X / 286) * 32; if (prop.LayerGroup <= 5) { dstRect.X = (int) (dstRect.X * (0.05 * prop.LayerGroup)); // multiply the position by the layer's parallax dstRect.Y = (int) (dstRect.Y * (0.05 * prop.LayerGroup)); dstRect.Width *= 2; dstRect.Height *= 2; } if (prop.FlipHorz) // dstRect = new Rectangle(dstRect.Left - sprite.Hitbox.Left, dstRect.Top, -dstRect.Width, dstRect.Height); // dstRect = new Rectangle(dstRect.Left - dstRect.Width - sprite.Hitbox.Left, dstRect.Top, -dstRect.Width, dstRect.Height); // dstRect = new Rectangle(dstRect.Left - sprite.Hitbox.Left - sprite.Hitbox.Right, dstRect.Top, -dstRect.Width, dstRect.Height); // dstRect = new Rectangle(dstRect.Left - dstRect.Width - sprite.Hitbox.Left - sprite.Hitbox.Right, dstRect.Top, -dstRect.Width, dstRect.Height); // dstRect = new Rectangle(dstRect.Left , dstRect.Top, -dstRect.Width, dstRect.Height); // dstRect = new Rectangle(dstRect.Left + dstRect.Width, dstRect.Top, -dstRect.Width, dstRect.Height); // dstRect = new Rectangle(dstRect.Left - sprite.Hitbox.Left, dstRect.Top, -dstRect.Width, dstRect.Height); // dstRect = new Rectangle(dstRect.Left + dstRect.Width - sprite.Hitbox.Left, dstRect.Top, -dstRect.Width, dstRect.Height); // dstRect = new Rectangle(dstRect.Left - sprite.Hitbox.Right, dstRect.Top, -dstRect.Width, dstRect.Height); // dstRect = new Rectangle(dstRect.Left + dstRect.Width - sprite.Hitbox.Right, dstRect.Top, -dstRect.Width, dstRect.Height); // dstRect = new Rectangle(dstRect.Left - sprite.Hitbox.Left - sprite.Hitbox.Right, dstRect.Top, -dstRect.Width, dstRect.Height); dstRect = new Rectangle(dstRect.Right - sprite.Hitbox.Left - sprite.Hitbox.Right, dstRect.Top, -dstRect.Width, dstRect.Height); if (prop.FlipVert) dstRect = new Rectangle(dstRect.Left, dstRect.Bottom - sprite.Hitbox.Top - sprite.Hitbox.Bottom, dstRect.Width, -dstRect.Height); //var attrs = new ImageAttributes(); //attrs.SetColorMatrix(MakeFogMatrix(prop.LayerGroup)); dstRect.X += sprite.Hitbox.Left; dstRect.Y += sprite.Hitbox.Top; dstRect.X -= (block.X * App.SlicesPerBlock + slice.Header.X) * App.PixelsPerSlice; dstRect.Y -= (block.Y * App.SlicesPerBlock + slice.Header.Y) * App.PixelsPerSlice; dstRect.X += sliceOverdraw; dstRect.Y += sliceOverdraw; canvas.DrawImage(sprite.Image, dstRect, 0, 0, sprite.Hitbox.Width, sprite.Hitbox.Height, GraphicsUnit.Pixel); }
private bool DrawProps(Graphics canvas, Block block, Slice slice, int layer) { var drewAnything = false; // foreach (var prop in slice.Props) { // if (prop.LayerGroup == layer) { // DrawProp(canvas, block, slice, prop); // drewAnything = true; // } // } // TODO: this is garbage; optimize this foreach (var b in level.Blocks) foreach (var s in b.Slices) foreach (var p in s.Props) if (p.LayerGroup == layer) { DrawProp(canvas, block, slice, p); drewAnything = true; } return drewAnything; }
private void DrawBlock(Block block) { foreach (var slicesByPos in block.Slices.GroupBy(s => Tuple.Create(s.Header.X, s.Header.Y))) { var sliceX = slicesByPos.Key.Item1; var sliceY = slicesByPos.Key.Item2; for (byte layer = 1; layer <= App.NumLayers; ++layer) { using (var image = new Bitmap(App.PixelsPerSlice + sliceOverdraw * 2, App.PixelsPerSlice + sliceOverdraw * 2)) using (var canvas = Graphics.FromImage(image)) { bool drewAnything = false; foreach (var slice in slicesByPos) drewAnything |= DrawTiles(canvas, slice, layer); if (!drewAnything) continue; var x = ((block.X * App.SlicesPerBlock) + sliceX) * App.PixelsPerSlice; var y = ((block.Y * App.SlicesPerBlock) + sliceY) * App.PixelsPerSlice; var path = Path.Combine(App.IntermediatePath, name, string.Format("{0}_{1}_{2}.png", layer, x, y)); using (var file = File.Open(path, FileMode.Create, FileAccess.Write)) { image.Save(file, ImageFormat.Png); } var area = new Rectangle(x - sliceOverdraw, y - sliceOverdraw, App.PixelsPerSlice, App.PixelsPerSlice); result.Tiles.Add(new RenderedTiles(level, path, area, layer)); } } } }