public uint[] GetSprite(int index) { OAM oam = GetOAM(index); DrawSprite(_sprite, oam.SpriteCode, 0, 0); return(_sprite); }
internal void RefreshSprite(uint[] pixels, OAM oam) { Utils.TransferBytesToWriteableBitmap(_spriteImage, pixels); OnPropertyChanged(() => SpriteImage); _spriteData = oam; OnPropertyChanged(() => SpriteData); }
internal static void GetSpriteRowPixels(short[] pixelLookupTable, DisplayDefinition disDef, Memory memory, OAM[] spriteOAMs, uint[] targetPixels, uint[] pixelBuffer, int row, bool LCDCBit2, bool ignoreBackgroundPriority = false) { int scanLineSize = GetScanLineOAMs(disDef, spriteOAMs, row, LCDCBit2); // We obtain the pixels we want from it for (int oamIndex = scanLineSize - 1; oamIndex >= 0; --oamIndex) { OAM oam = scanLineOAMs[oamIndex]; bool flipX = Utils.UtilFuncs.TestBit(oam.Flags, 5) != 0; bool flipY = Utils.UtilFuncs.TestBit(oam.Flags, 6) != 0; byte[] tilePixels = GetTileData(disDef, memory, 0x8000, oam.SpriteCode, LCDCBit2, flipX, flipY); int x = oam.X - 8; int y = row - (oam.Y - 16); uint[] spritePallete = (Utils.UtilFuncs.TestBit(oam.Flags, 4) == 0) ? disDef.SpritePallete0 : disDef.SpritePallete1; GetPixelsFromTileBytes(pixelLookupTable, ref pixelBuffer, spritePallete, disDef.PixelPerTileX, tilePixels[2 * y], tilePixels[2 * y + 1]); bool backgroundPriority = (Utils.UtilFuncs.TestBit(oam.Flags, 7) != 0); if (ignoreBackgroundPriority) { backgroundPriority = false; } for (int i = 0; i < 8; ++i) { int pX = x + i; if (pX < 0) { continue; } if (pX >= disDef.ScreenPixelCountX) { break; } uint color = pixelBuffer[i]; if (color == 0) { continue; } // transparent pixel // NOTE(Cristian): If the BG priority bit is set, the sprite is hidden // on every color except tile color 0 if (backgroundPriority) { if (targetPixels[pX] != disDef.TileColors[0]) { continue; } } targetPixels[pX] = color; } } }
/// <summary> /// Gets the OAMs for the a certain row /// </summary> /// <param name="spriteOAMs"></param> /// <param name="row"></param> /// <param name="LCDCBit2"></param> /// <returns></returns> internal static int GetScanLineOAMs(DisplayDefinition disDef, OAM[] spriteOAMs, int row, bool LCDCBit2) { int spriteSize = disDef.BytesPerTileShort / 2; if (LCDCBit2) { spriteSize = disDef.BytesPerTileLong / 2; } // Then we select the 10 that correspond int scanLineSize = 0; int maxScanLineSize = 10; foreach (OAM oam in spriteOAMs) { int y = oam.Y - 16; if ((y <= row) && (row < (y + spriteSize))) { scanLineOAMs[scanLineSize++] = oam; if (scanLineSize == maxScanLineSize) { break; } } } return scanLineSize; }
internal void Reset() { /*** DISPLAY DEFINITION ***/ _disDef.FramePixelCountX = 256; _disDef.FramePixelCountY = 256; _disDef.ScreenPixelCountX = 160; _disDef.ScreenPixelCountY = 144; _disDef.TimingPixelCountX = 256; _disDef.TimingPixelCountY = 154; _disDef.FrameTileCountX = 32; _disDef.FrameTileCountY = 32; _disDef.ScreenTileCountX = 20; _disDef.ScreenTileCountY = 18; _disDef.BytesPerTileShort = 16; _disDef.BytesPerTileLong = 32; _disDef.PixelPerTileX = 8; _disDef.PixelPerTileY = 8; _disDef.BytesPerPixel = 4; _disDef.PixelFormat = PixelFormat.Format32bppArgb; // TODO(Cristian): Output the color to the view for custom setting _disDef.TileColors = new uint[4] { 0xFFFFFFFF, 0xFFBBBBBB, 0xFF666666, 0xFF000000 }; _disDef.TilePallete = new uint[4]; // TODO(Cristian): Output the color to the view for custom setting _disDef.SpriteColors = new uint[4] { 0xFFFFFFFF, 0xFFBBBBBB, 0xFF666666, 0xFF000000 }; _disDef.SpritePallete0 = new uint[4]; _disDef.SpritePallete1 = new uint[4]; // Tile stargets _spriteOAMs = new OAM[_spriteCount]; for (int i = 0; i < _spriteOAMs.Length; ++i) { _spriteOAMs[i] = new OAM(); } /*** DISPLAY STATUS ***/ _state.PrevTickCount = 0; _state.CurrentLineTickCount = 0; _state.CurrentLine = 0; // NOTE(Cristian): This are default values when there are no sprites // They should change on runtime _state.OAMSearchTickCount = 83; _state.DataTransferTickCount = 83 + 175; _state.TotalLineTickCount = 456; _state.Enabled = true; // TODO(Cristian): Find out at what state the display starts! _state.DisplayMode = DisplayModes.Mode10; _state.TileBase = true; _state.NoTileMap = false; _state.TileMap = false; _state.LCDCBits = new bool[8]; // We start the registers correctly HandleMemoryChange(MMR.LCDC, _memory.LowLevelRead((ushort)MMR.LCDC)); HandleMemoryChange(MMR.LCDC, _memory.LowLevelRead((ushort)MMR.LCDC)); HandleMemoryChange(MMR.SCY, _memory.LowLevelRead((ushort)MMR.SCY)); HandleMemoryChange(MMR.SCX, _memory.LowLevelRead((ushort)MMR.SCX)); HandleMemoryChange(MMR.LYC, _memory.LowLevelRead((ushort)MMR.LYC)); HandleMemoryChange(MMR.DMA, _memory.LowLevelRead((ushort)MMR.DMA)); HandleMemoryChange(MMR.BGP, _memory.LowLevelRead((ushort)MMR.BGP)); HandleMemoryChange(MMR.OBP0, _memory.LowLevelRead((ushort)MMR.OBP0)); HandleMemoryChange(MMR.OBP1, _memory.LowLevelRead((ushort)MMR.OBP1)); HandleMemoryChange(MMR.WY, _memory.LowLevelRead((ushort)MMR.WY)); HandleMemoryChange(MMR.WX, _memory.LowLevelRead((ushort)MMR.WX)); /*** DRAW TARGETS ***/ // We create the target bitmaps _debugInternalTargets = new uint[Enum.GetNames(typeof(DebugTargets)).Length][]; _debugExternalTargets = new uint[Enum.GetNames(typeof(DebugTargets)).Length][]; _updateDebugTargets = new bool[Enum.GetNames(typeof(DebugTargets)).Length]; _debugInternalTargets[(int)DebugTargets.Background] = new uint[_disDef.FramePixelCountX * _disDef.FramePixelCountY]; _debugExternalTargets[(int)DebugTargets.Background] = new uint[_disDef.FramePixelCountX * _disDef.FramePixelCountY]; _updateDebugTargets[(int)DebugTargets.Background] = false; _debugInternalTargets[(int)DebugTargets.Tiles] = new uint[_disDef.ScreenPixelCountX * _disDef.ScreenPixelCountY]; _debugExternalTargets[(int)DebugTargets.Tiles] = new uint[_disDef.ScreenPixelCountX * _disDef.ScreenPixelCountY]; _updateDebugTargets[(int)DebugTargets.Tiles] = false; _debugInternalTargets[(int)DebugTargets.Window] = new uint[_disDef.ScreenPixelCountX * _disDef.ScreenPixelCountY]; _debugExternalTargets[(int)DebugTargets.Window] = new uint[_disDef.ScreenPixelCountX * _disDef.ScreenPixelCountY]; _updateDebugTargets[(int)DebugTargets.Window] = false; _debugInternalTargets[(int)DebugTargets.SpriteLayer] = new uint[_disDef.ScreenPixelCountX * _disDef.ScreenPixelCountY]; _debugExternalTargets[(int)DebugTargets.SpriteLayer] = new uint[_disDef.ScreenPixelCountX * _disDef.ScreenPixelCountY]; _updateDebugTargets[(int)DebugTargets.SpriteLayer] = false; _debugInternalTargets[(int)DebugTargets.DisplayTiming] = new uint[_disDef.TimingPixelCountX * _disDef.TimingPixelCountY]; _debugExternalTargets[(int)DebugTargets.DisplayTiming] = new uint[_disDef.TimingPixelCountX * _disDef.TimingPixelCountY]; _updateDebugTargets[(int)DebugTargets.DisplayTiming] = false; _screenInternalBuffer = new uint[_disDef.ScreenPixelCountX * _disDef.ScreenPixelCountY]; _screenExternalBuffer = new uint[_disDef.ScreenPixelCountX * _disDef.ScreenPixelCountY]; _sprite = new uint[8 * 16]; _tempPixelBuffer = new uint[_disDef.PixelPerTileX]; _tempFrameLineBuffer = new uint[_disDef.FramePixelCountX]; // We update the display status info UpdateDisplayLineInfo(false); }
GetSpriteRowPixels(short[] pixelLookupTable, DisplayDefinition disDef, Memory memory, OAM[] spriteOAMs, uint[] targetPixels, uint[] pixelBuffer, int row, bool LCDCBit2, bool ignoreBackgroundPriority = false) { int scanLineSize = GetScanLineOAMs(disDef, spriteOAMs, row, LCDCBit2); // We obtain the pixels we want from it for (int oamIndex = scanLineSize - 1; oamIndex >= 0; --oamIndex) { OAM oam = scanLineOAMs[oamIndex]; bool flipX = Utils.UtilFuncs.TestBit(oam.Flags, 5) != 0; bool flipY = Utils.UtilFuncs.TestBit(oam.Flags, 6) != 0; byte[] tilePixels = GetTileData(disDef, memory, 0x8000, oam.SpriteCode, LCDCBit2, flipX, flipY); int x = oam.X - 8; int y = row - (oam.Y - 16); uint[] spritePallete = (Utils.UtilFuncs.TestBit(oam.Flags, 4) == 0) ? disDef.SpritePallete0 : disDef.SpritePallete1; GetPixelsFromTileBytes(pixelLookupTable, ref pixelBuffer, spritePallete, disDef.PixelPerTileX, tilePixels[2 * y], tilePixels[2 * y + 1]); bool backgroundPriority = (Utils.UtilFuncs.TestBit(oam.Flags, 7) != 0); if (ignoreBackgroundPriority) { backgroundPriority = false; } for (int i = 0; i < 8; ++i) { int pX = x + i; if (pX < 0) { continue; } if (pX >= disDef.ScreenPixelCountX) { break; } uint color = pixelBuffer[i]; if (color == 0) { continue; } // transparent pixel // NOTE(Cristian): If the BG priority bit is set, the sprite is hidden // on every color except tile color 0 if (backgroundPriority) { if (targetPixels[pX] != disDef.TileColors[0]) { continue; } } targetPixels[pX] = color; } } }