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); }
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); }
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}"); } } }
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}"); } }