Example #1
0
        /// <summary>
        /// Reconstructs the sprite info table from OAM.
        /// </summary>
        public void ReconstructOAMTable()
        {
            for (int i = 0; i < SpriteInfoTable.Length; i++)
            {
                int off = i << 2;
                SpriteInfoTable[i].OAMIndex = off;
                SpriteInfoTable[i].YOffset = OAM[off + 0] - 16;
                SpriteInfoTable[i].XOffset = OAM[off + 1] - 8;
                SpriteInfoTable[i].TileOffset = OAM[off + 2] << 4;//index * 16 = offset in VRAM of tile
                SpriteInfoTable[i].SpriteProperties = OAM[off + 3];

                // Sprites are sorted by their X position. In the case that their Xs are equal,
                // the one with the lower OAM position takes priority. Because they are already
                // 'sorted by OAM offset', only Xs need to be compared.
                int x = i;
                while (x > 0 && (SpriteInfoTable[x].XOffset < SpriteInfoTable[x - 1].XOffset))
                {
                    SpriteInfo temp = SpriteInfoTable[x - 1];
                    SpriteInfoTable[x - 1] = SpriteInfoTable[x];
                    SpriteInfoTable[x] = temp;
                    x--;
                }
            }
            for (int i = 0; i < SpritesOnScanline.Length; i++)
            {
                SpritesOnScanline[i] = new SpriteInfo()
                {
                    OAMIndex = int.MaxValue,
                    XOffset = int.MaxValue,
                    YOffset = int.MaxValue
                };
            }
        }
Example #2
0
        /// <summary>
        /// Draws the sprites on the current scanline.
        /// </summary>
        private void DrawSpriteScanline()
        {
            int LineSpriteCount = 0;

            for (int i = 0; i < SpriteInfoTable.Length; i++)
            {
                SpriteInfo currentSprite = SpriteInfoTable[i];

                // Only draw if the sprite is on the scanline
                if (LY >= currentSprite.YOffset && LY < currentSprite.YOffset + SpriteHeight)
                {
                    LineSpriteCount++;
                    if (!currentSprite.IsOnScreen)
                    {
                        continue;
                    }
                    int SpritePixelY     = LY - currentSprite.YOffset;
                    int SpriteTileOffset = 0;
                    if (Sprite8By16Mode)
                    {
                        if (SpritePixelY < 8)
                        {
                            SpriteTileOffset = currentSprite.UpperTileOffset;
                        }
                        else
                        {
                            SpritePixelY    -= 8;
                            SpriteTileOffset = currentSprite.LowerTileOffset;
                        }
                    }
                    else
                    {
                        SpriteTileOffset = currentSprite.TileOffset;
                    }
                    for (int LCD_X = currentSprite.XOffset, SpritePixelX = 0; LCD_X < currentSprite.XOffset + 8; LCD_X++, SpritePixelX++)
                    {
                        if (LCD_X >= LCDWidth)
                        {
                            break;
                        }
                        int SpriteColorNum = GetPixelPaletteNumberFromTile(SpriteTileOffset, SpritePixelX, SpritePixelY, currentSprite.XFlip, currentSprite.YFlip);

                        // Color 0 is never drawn (transparent).
                        // If PriorityOverBG, sprite pixel is drawn over BG, except in the case of sprite color 0.
                        // If !PriorityOverBG, sprite pixel isn't drawn over BG, except when BG color is 0.
                        if (SpriteColorNum == 0)
                        {
                            continue;
                        }
                        bool PriorityOverExistingSprite = (currentSprite.XOffset < SpritesOnScanline[LCD_X].XOffset) || (currentSprite.OAMIndex < SpritesOnScanline[LCD_X].OAMIndex);
                        if (PriorityOverExistingSprite && (currentSprite.PriorityOverBG || BackgroundColorNumOnScanline[LCD_X] == 0))
                        {
                            SetPixel(LCD_X, LY, DMGObjectPalettes[currentSprite.DMGObjectPaletteNum][SpriteColorNum]);
                            SpritesOnScanline[LCD_X] = currentSprite;
                        }
                    }
                }
                if (LineSpriteCount >= 10)
                {
                    break;
                }
            }
        }