Example #1
0
        public void TestRenderScreenWithSpriteFlipped()
        {
            var romData = new ROMData();

            romData.Data[ROMs.PAC_MAN_COLOR.FileName]   = VideoHardwareTestData.COLOR_ROM;
            romData.Data[ROMs.PAC_MAN_PALETTE.FileName] = VideoHardwareTestData.PALETTE_ROM;
            romData.Data[ROMs.PAC_MAN_TILE.FileName]    = VideoHardwareTestData.TILE_ROM;
            romData.Data[ROMs.PAC_MAN_SPRITE.FileName]  = VideoHardwareTestData.SPRITE_ROM;

            var video = new VideoHardware(romData);

            video.InitializeColors();
            video.InitializePalettes();
            video.InitializeTiles();
            video.InitializeSprites();

            // Arrange: Load a VRAM dump which contains tiles positions and palettes for each tile.

            var rawMemory = new byte[0xFFFF];

            var vram = File.ReadAllBytes($"../../../TestData/maze-1.vram");

            Array.Copy(vram, 0, rawMemory, 0x4000, 0x0800);

            var memory = new SimpleMemory(rawMemory);

            // Arrange: Setup the sprites to show.

            // Pac-Man facing left sprite (46), flip X/Y (0x02).
            var flags = (byte)((46 << 2) | (0x02));

            memory.Write(0x4FF0, flags);
            memory.Write(0x4FF1, 9); // Palette.

            // Act: Render the image based on the tiles and palettes in memory.

            var spriteCoordinates = new byte[16]
            {
                220, // x
                252, // y
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
            };

            var image = video.Render(memory, spriteCoordinates, true);

            // Assert: the rendered image should be the same as the reference image.

            byte[] actualBytes = null;

            using (var steam = new MemoryStream())
            {
                image.Save(steam, new BmpEncoder());
                actualBytes = steam.ToArray();
            }

            var expectedBytes = File.ReadAllBytes($"../../../ReferenceData/render-maze-1-with-sprites-flipped.bmp");

            Assert.Equal(expectedBytes, actualBytes);
        }
Example #2
0
        public void TestRenderScreen(string vramFile, string expectedBitmapFile, bool flipScreen)
        {
            var romData = new ROMData();

            romData.Data[ROMs.PAC_MAN_COLOR.FileName]   = VideoHardwareTestData.COLOR_ROM;
            romData.Data[ROMs.PAC_MAN_PALETTE.FileName] = VideoHardwareTestData.PALETTE_ROM;
            romData.Data[ROMs.PAC_MAN_TILE.FileName]    = VideoHardwareTestData.TILE_ROM;
            romData.Data[ROMs.PAC_MAN_SPRITE.FileName]  = VideoHardwareTestData.SPRITE_ROM;

            var video = new VideoHardware(romData);

            video.InitializeColors();
            video.InitializePalettes();
            video.InitializeTiles();
            video.InitializeSprites();

            // Arrange: Load a VRAM dump which contains tiles positions and palettes for each tile.

            var rawMemory = new byte[0xFFFF];

            var vram = File.ReadAllBytes($"../../../TestData/{vramFile}");

            Array.Copy(vram, 0, rawMemory, 0x4000, 0x0800);

            var memory = new SimpleMemory(rawMemory);

            // Act: Render the image based on the tiles and palettes in memory.

            var spriteCoordinates = new byte[16];
            var image             = video.Render(memory, spriteCoordinates, flipScreen);

            // Assert: the rendered image should be the same as the reference image.

            byte[] actualBytes = null;

            using (var steam = new MemoryStream())
            {
                image.Save(steam, new BmpEncoder());
                actualBytes = steam.ToArray();
            }

            var expectedBytes = File.ReadAllBytes($"../../../ReferenceData/{expectedBitmapFile}");

            Assert.Equal(expectedBytes, actualBytes);
        }
        public void TestRenderSpriteRendersAllSpritesWithTransparency()
        {
            var romData = new ROMData();

            romData.Data[ROMs.PAC_MAN_COLOR.FileName]   = VideoHardwareTestData.COLOR_ROM;
            romData.Data[ROMs.PAC_MAN_PALETTE.FileName] = VideoHardwareTestData.PALETTE_ROM;
            romData.Data[ROMs.PAC_MAN_TILE.FileName]    = null;
            romData.Data[ROMs.PAC_MAN_SPRITE.FileName]  = null;

            var video = new VideoHardware(romData);

            video.InitializeColors();
            video.InitializePalettes();

            var spriteRenderer = new SpriteRenderer(VideoHardwareTestData.SPRITE_ROM, video._palettes);

            // There are 64 sprites, so we can render a grid of 8x8 sprites.
            // Each sprite is 16x16 pixels.
            var width  = 8 * 16;
            var height = 8 * 16;

            // Holds the (x, y) coordinates of the origin (top/left) of the location
            // to render the next sprite.
            var spriteOriginX = 0;
            var spriteOriginY = 0;

            // The image we'll be rendering all the sprites to.
            var image = new Image <Rgba32>(width, height, new Rgba32()
            {
                R = 255, G = 0, B = 255, A = 255
            });

            // Render each of the 64 sprites.
            for (var spriteIndex = 0; spriteIndex < 64; spriteIndex++)
            {
                // Render the sprite with the given color palette.
                var sprite = spriteRenderer.RenderSprite(spriteIndex, 5);

                // Copy the rendered sprite over into the full image.
                for (var y = 0; y < 16; y++)
                {
                    for (var x = 0; x < 16; x++)
                    {
                        var pixel         = sprite[x, y];
                        var isTransparent = pixel.A == 0;

                        if (!isTransparent)
                        {
                            image[spriteOriginX + x, spriteOriginY + y] = sprite[x, y];
                        }
                    }
                }

                if ((spriteIndex + 1) % 8 == 0)
                {
                    // Row is finished, wrap back around.
                    spriteOriginX  = 0;
                    spriteOriginY += 16;
                }
                else
                {
                    // Next column.
                    spriteOriginX += 16;
                }
            }

            // Assert: the rendered image should be the same as the reference image.

            byte[] actualBytes = null;

            using (var steam = new MemoryStream())
            {
                image.Save(steam, new BmpEncoder());
                actualBytes = steam.ToArray();
            }

            var expectedBytes = File.ReadAllBytes("../../../ReferenceData/render-all-sprites-with-transparency.bmp");

            Assert.Equal(expectedBytes, actualBytes);
        }
        public void TestRenderSpriteRendersAllSpritesWithRotations()
        {
            var romData = new ROMData();

            romData.Data[ROMs.PAC_MAN_COLOR.FileName]   = VideoHardwareTestData.COLOR_ROM;
            romData.Data[ROMs.PAC_MAN_PALETTE.FileName] = VideoHardwareTestData.PALETTE_ROM;
            romData.Data[ROMs.PAC_MAN_TILE.FileName]    = null;
            romData.Data[ROMs.PAC_MAN_SPRITE.FileName]  = null;

            var video = new VideoHardware(romData);

            video.InitializeColors();
            video.InitializePalettes();

            var spriteRenderer = new SpriteRenderer(VideoHardwareTestData.SPRITE_ROM, video._palettes);

            // There are 64 sprites, so we can render a grid of 8x8 sprites.
            // Each sprite is 16x16 pixels.
            var width  = 8 * 16;
            var height = 8 * 16;

            // Holds the (x, y) coordinates of the origin (top/left) of the location
            // to render the next sprite.
            var spriteOriginX = 0;
            var spriteOriginY = 0;

            // The image we'll be rendering all the sprites to.
            var image = new Image <Rgba32>(width, height, new Rgba32()
            {
                R = 0, G = 51, B = 102, A = 255
            });

            // Alternate between not flipping, flipping only X and only Y, and both.

            var flipIndex = 0;

            var flipValues = new List <Tuple <bool, bool> >()
            {
                new Tuple <bool, bool>(false, false),
                new Tuple <bool, bool>(true, false),
                new Tuple <bool, bool>(false, true),
                new Tuple <bool, bool>(true, true),
            };

            // Render each of the 64 sprites.
            for (var spriteIndex = 0; spriteIndex < 64; spriteIndex++)
            {
                // Determine how we'll flip this sprite.
                var flip  = flipValues[flipIndex];
                var flipX = flip.Item1;
                var flipY = flip.Item2;

                // Render the sprite with the given color palette.
                var sprite = spriteRenderer.RenderSprite(spriteIndex, 1, flipX, flipY);

                // Increment the value so we flip differently on the next sprite.

                flipIndex++;

                if (flipIndex == 4)
                {
                    flipIndex = 0;
                }

                // Copy the rendered sprite over into the full image.
                for (var y = 0; y < 16; y++)
                {
                    for (var x = 0; x < 16; x++)
                    {
                        var pixel         = sprite[x, y];
                        var isTransparent = pixel.A == 0;

                        if (!isTransparent)
                        {
                            image[spriteOriginX + x, spriteOriginY + y] = sprite[x, y];
                        }
                    }
                }

                if ((spriteIndex + 1) % 8 == 0)
                {
                    // Row is finished, wrap back around.
                    spriteOriginX  = 0;
                    spriteOriginY += 16;
                }
                else
                {
                    // Next column.
                    spriteOriginX += 16;
                }
            }

            // Assert: the rendered image should be the same as the reference image.

            byte[] actualBytes = null;

            using (var steam = new MemoryStream())
            {
                image.Save(steam, new BmpEncoder());
                actualBytes = steam.ToArray();
            }

            var expectedBytes = File.ReadAllBytes("../../../ReferenceData/render-all-sprites-with-rotations.bmp");

            Assert.Equal(expectedBytes, actualBytes);
        }
        public void TestRenderTileRendersAllTiles(int paletteIndex, string fileToCompare)
        {
            var romData = new ROMData();

            romData.Data[ROMs.PAC_MAN_COLOR.FileName]   = VideoHardwareTestData.COLOR_ROM;
            romData.Data[ROMs.PAC_MAN_PALETTE.FileName] = VideoHardwareTestData.PALETTE_ROM;
            romData.Data[ROMs.PAC_MAN_TILE.FileName]    = null;
            romData.Data[ROMs.PAC_MAN_SPRITE.FileName]  = null;

            var video = new VideoHardware(romData);

            video.InitializeColors();
            video.InitializePalettes();

            var tileRenderer = new TileRenderer(VideoHardwareTestData.TILE_ROM, video._palettes);

            // There are 256 tiles, so we can render a grid of 16x16 tiles.
            // Each tile is 8x8 pixels.
            var width  = 16 * 8;
            var height = 16 * 8;

            // Holds the (x, y) coordinates of the origin (top/left) of the location
            // to render the next tile.
            var tileOriginX = 0;
            var tileOriginY = 0;

            // The image we'll be rendering all the tiles to.
            var image = new Image <Rgba32>(width, height);

            // Render each of the 256 tiles.
            for (var tileIndex = 0; tileIndex < 256; tileIndex++)
            {
                // Render the tile with the given color palette.
                var tile = tileRenderer.RenderTile(tileIndex, paletteIndex);

                // Copy the rendered tile over into the full image.
                for (var y = 0; y < 8; y++)
                {
                    for (var x = 0; x < 8; x++)
                    {
                        image[tileOriginX + x, tileOriginY + y] = tile[x, y];
                    }
                }

                if ((tileIndex + 1) % 16 == 0)
                {
                    // Row is finished, wrap back around.
                    tileOriginX  = 0;
                    tileOriginY += 8;
                }
                else
                {
                    // Next column.
                    tileOriginX += 8;
                }
            }

            // Assert: the rendered image should be the same as the reference image.

            byte[] actualBytes = null;

            using (var steam = new MemoryStream())
            {
                image.Save(steam, new BmpEncoder());
                actualBytes = steam.ToArray();
            }

            var expectedBytes = File.ReadAllBytes($"../../../ReferenceData/{fileToCompare}");

            Assert.Equal(expectedBytes, actualBytes);
        }
Example #6
0
        public void TestInitializePalettesParsesPaletteRomAndBuildsTableCorrectly()
        {
            var romData = new ROMData();

            romData.Data[ROMs.PAC_MAN_COLOR.FileName]   = VideoHardwareTestData.COLOR_ROM;
            romData.Data[ROMs.PAC_MAN_PALETTE.FileName] = VideoHardwareTestData.PALETTE_ROM;
            romData.Data[ROMs.PAC_MAN_TILE.FileName]    = null;
            romData.Data[ROMs.PAC_MAN_SPRITE.FileName]  = null;

            var video = new VideoHardware(romData);

            video.InitializeColors();
            video.InitializePalettes();

            // Expected palette colors values as listed in Chris Lomont's Pac-Man Emulation
            // Guide v0.1, page 6, figure 3.
            var expectedPalettes = new Color[][]
            {
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.FromArgb(222, 222, 255), Color.FromArgb(33, 33, 255), Color.Red, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.FromArgb(222, 222, 255), Color.FromArgb(33, 33, 255), Color.FromArgb(255, 184, 255), },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.FromArgb(222, 222, 255), Color.FromArgb(33, 33, 255), Color.Aqua, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.FromArgb(222, 222, 255), Color.FromArgb(33, 33, 255), Color.FromArgb(255, 184, 81), },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.FromArgb(33, 33, 255), Color.Red, Color.Yellow, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.FromArgb(222, 222, 255), Color.Black, Color.FromArgb(255, 184, 174), },
                new Color[] { Color.Black, Color.Red, Color.Lime, Color.FromArgb(222, 222, 255), },
                new Color[] { Color.Black, Color.FromArgb(255, 184, 174), Color.Black, Color.FromArgb(33, 33, 255), },
                new Color[] { Color.Black, Color.Lime, Color.FromArgb(33, 33, 255), Color.FromArgb(255, 184, 174), },
                new Color[] { Color.Black, Color.Lime, Color.FromArgb(222, 222, 255), Color.Red, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Red, Color.FromArgb(222, 151, 81), Color.FromArgb(222, 222, 255), },
                new Color[] { Color.Black, Color.FromArgb(255, 184, 81), Color.Lime, Color.FromArgb(222, 151, 81), },
                new Color[] { Color.Black, Color.Yellow, Color.FromArgb(71, 184, 255), Color.FromArgb(222, 222, 255), },
                new Color[] { Color.Black, Color.FromArgb(71, 184, 174), Color.Lime, Color.FromArgb(222, 222, 255), },
                new Color[] { Color.Black, Color.Aqua, Color.FromArgb(255, 184, 255), Color.Yellow, },
                new Color[] { Color.Black, Color.FromArgb(222, 222, 255), Color.FromArgb(33, 33, 255), Color.Black, },
                new Color[] { Color.Black, Color.FromArgb(255, 184, 174), Color.Black, Color.FromArgb(33, 33, 255), },
                new Color[] { Color.Black, Color.FromArgb(255, 184, 174), Color.Black, Color.FromArgb(33, 33, 255), },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.FromArgb(222, 222, 255), Color.FromArgb(255, 184, 174), Color.Red },
                new Color[] { Color.Black, Color.FromArgb(222, 222, 255), Color.FromArgb(33, 33, 255), Color.FromArgb(255, 184, 174) },
                new Color[] { Color.Black, Color.FromArgb(255, 184, 174), Color.Black, Color.FromArgb(222, 222, 255) },


                // The last 32 palettes aren't used; they're all just black.
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
                new Color[] { Color.Black, Color.Black, Color.Black, Color.Black, },
            };

            Assert.Equal(64, video._palettes.Length);
            Assert.Equal(64, expectedPalettes.Length);

            for (var i = 0; i < expectedPalettes.Length; i++)
            {
                var actualPalette   = video._palettes[i];
                var expectedPalette = expectedPalettes[i];

                Assert.True(actualPalette.Length == 4, $"The palette at index {i} should have exactly 4 color entries, but found {actualPalette.Length}");

                for (var j = 0; j < 4; j++)
                {
                    var actualColor   = actualPalette[j];
                    var expectedColor = expectedPalette[j];

                    Assert.True(expectedColor.R == actualColor.R, $"The Red value for color at index {j} for the palette at index {i} was expected to be {expectedColor.R} but was actually {actualColor.R}");
                    Assert.True(expectedColor.G == actualColor.G, $"The Green value for color at index {j} for the palette at index {i} was expected to be {expectedColor.G} but was actually {actualColor.G}");
                    Assert.True(expectedColor.B == actualColor.B, $"The Blue value for color at index {j} for the palette at index {i} was expected to be {expectedColor.B} but was actually {actualColor.B}");
                }
            }
        }
Example #7
0
        public void TestInitializeColorsParsesRomColorsCorrectly()
        {
            var romData = new ROMData();

            romData.Data[ROMs.PAC_MAN_COLOR.FileName]   = VideoHardwareTestData.COLOR_ROM;
            romData.Data[ROMs.PAC_MAN_PALETTE.FileName] = null;
            romData.Data[ROMs.PAC_MAN_TILE.FileName]    = null;
            romData.Data[ROMs.PAC_MAN_SPRITE.FileName]  = null;

            var video = new VideoHardware(romData);

            video.InitializeColors();

            // Expected RGB color values as listed in Chris Lomont's Pac-Man Emulation
            // Guide v0.1, page 5, table 3.
            var expectedColors = new Color[]
            {
                Color.FromArgb(0, 0, 0),
                Color.FromArgb(255, 0, 0),
                Color.FromArgb(222, 151, 81),
                Color.FromArgb(255, 184, 255),
                Color.FromArgb(0, 0, 0),
                Color.FromArgb(0, 255, 255),
                Color.FromArgb(71, 184, 255),
                Color.FromArgb(255, 184, 81),

                Color.FromArgb(0, 0, 0),
                Color.FromArgb(255, 255, 0),
                Color.FromArgb(0, 0, 0),
                Color.FromArgb(33, 33, 255),
                Color.FromArgb(0, 255, 0),
                Color.FromArgb(71, 184, 174),
                Color.FromArgb(255, 184, 174),
                Color.FromArgb(222, 222, 255),

                Color.FromArgb(0, 0, 0),
                Color.FromArgb(0, 0, 0),
                Color.FromArgb(0, 0, 0),
                Color.FromArgb(0, 0, 0),
                Color.FromArgb(0, 0, 0),
                Color.FromArgb(0, 0, 0),
                Color.FromArgb(0, 0, 0),
                Color.FromArgb(0, 0, 0),

                Color.FromArgb(0, 0, 0),
                Color.FromArgb(0, 0, 0),
                Color.FromArgb(0, 0, 0),
                Color.FromArgb(0, 0, 0),
                Color.FromArgb(0, 0, 0),
                Color.FromArgb(0, 0, 0),
                Color.FromArgb(0, 0, 0),
                Color.FromArgb(0, 0, 0),
            };

            Assert.Equal(32, video._colors.Length);

            for (var i = 0; i < 32; i++)
            {
                Assert.True(expectedColors[i].R == video._colors[i].R, $"The Red value for color #{i} was expected to be {expectedColors[i].R} but was actually {video._colors[i].R}");
                Assert.True(expectedColors[i].G == video._colors[i].G, $"The Green value for color #{i} was expected to be {expectedColors[i].G} but was actually {video._colors[i].G}");
                Assert.True(expectedColors[i].B == video._colors[i].B, $"The Blue value for color #{i} was expected to be {expectedColors[i].B} but was actually {video._colors[i].B}");
            }
        }