public void DrawTiles() { ushort tileBaseAddress = DisFuncs.GetTileBaseAddress(_state.TileBase); ushort tileMapBaseAddress = DisFuncs.GetTileMapBaseAddress(_state.TileMap); for (int tileY = 0; tileY < 18; ++tileY) { for (int tileX = 0; tileX < 20; ++tileX) { int tileOffset; if (_state.NoTileMap) { tileOffset = 16 * tileY + tileX; } else { tileOffset = DisFuncs.GetTileOffset(_disDef, _memory, tileMapBaseAddress, _state.TileBase, tileX, tileY); } byte[] tileData = DisFuncs.GetTileData(_disDef, _memory, tileBaseAddress, tileOffset, false); DrawFuncs.DrawTile(_pixelLookupTable, _disDef, _debugInternalTargets[(int)DebugTargets.Tiles], _tempPixelBuffer, _disDef.ScreenPixelCountX, tileData, 8 * tileX, 8 * tileY, 256, 256); } } }
internal void HandleMemoryChange(MMR mappedRegister, byte value) { switch (mappedRegister) { case MMR.LCDC: // We set all the LCDC bits for (int i = 0; i < 8; ++i) { _state.LCDCBits[i] = (value & (1 << i)) != 0; } break; case MMR.STAT: _state.STAT = value; break; case MMR.SCY: _state.SCY = value; break; case MMR.SCX: _state.SCX = value; break; case MMR.LY: _state.CurrentLine = 0; break; case MMR.LYC: _state.LYC = value; break; case MMR.DMA: LoadSprites(); break; case MMR.BGP: DisFuncs.SetupTilePallete(_disDef, _memory); break; case MMR.OBP0: DisFuncs.SetupSpritePalletes(_disDef, _memory, MMR.OBP0); break; case MMR.OBP1: DisFuncs.SetupSpritePalletes(_disDef, _memory, MMR.OBP1); break; case MMR.WY: _state.WY = value; break; case MMR.WX: _state.WX = value; break; default: throw new InvalidProgramException("All cases should be handled..."); } }
internal void DrawSprite(uint[] spriteData, int spriteCode, int pX, int pY) { DrawFuncs.DrawTransparency(_disDef, spriteData, 8, 0, 0, 8, 16); if (_state.LCDCBits[2]) { spriteCode = spriteCode & 0xFE; // We remove the last bit } // We draw the top part byte[] pixels = DisFuncs.GetTileData(_disDef, _memory, 0x8000, spriteCode, _state.LCDCBits[2]); DrawFuncs.DrawTile(_pixelLookupTable, _disDef, spriteData, _tempPixelBuffer, 8, pixels, pX, pY, _disDef.ScreenPixelCountX, _disDef.ScreenPixelCountY); }
DrawTile(short[] pixelLookupTable, DisplayDefinition disDef, uint[] bitmapData, uint[] pixelBuffer, int stride, byte[] tileData, int pX, int pY, int maxPx, int maxPy) { // We iterate for the actual bytes for (int j = 0; j < tileData.Length; j += 2) { int pixelY = pY + (j / 2); if (pixelY < 0) { continue; } if (pixelY >= maxPy) { break; } // We can continue no further int index = pixelY * stride; // Only add every 2 bytes DisFuncs.GetPixelsFromTileBytes(pixelLookupTable, ref pixelBuffer, disDef.TilePallete, disDef.PixelPerTileX, tileData[j], tileData[j + 1]); for (int i = 0; i < 8; i++) { int pixelX = pX + i; if (pixelX < 0) { continue; } if (pixelX >= maxPx) { break; } int pIndex = index + pixelX; bitmapData[pIndex] = pixelBuffer[i]; } } }
public void DrawFrame(int rowBegin, int rowEnd) { if (!_state.Enabled) { return; } if (rowBegin > 143) { return; } #region BACKGROUND bool drawBackground = _state.LCDCBits[0]; // We copy the information from the background tile to the effective screen for (int y = rowBegin; y < rowEnd; y++) { // We obtain the correct row int bY = (y + _state.SCY) % _disDef.FramePixelCountY; DisFuncs.GetRowPixels(ref _tempFrameLineBuffer, _pixelLookupTable, _disDef, _memory, _tempPixelBuffer, bY, _state.LCDCBits[3], _state.LCDCBits[4]); if (_updateDebugTargets[(int)DebugTargets.Background]) { // TODO(Cristian): Draw the whole debug target DrawFuncs.DrawLine(_disDef, _debugInternalTargets[(int)DebugTargets.Background], _disDef.FramePixelCountX, _tempFrameLineBuffer, 0, bY, 0, _disDef.FramePixelCountX); } if (drawBackground) { DrawFuncs.DrawLine(_disDef, _screenInternalBuffer, _disDef.ScreenPixelCountX, _tempFrameLineBuffer, 0, y, _state.SCX, _disDef.FramePixelCountX, false, true); } } #endregion #region WINDOW int rWX = _state.WX - 7; // The window pos is (WX - 7, WY) // TODO(Cristian): If BG display is off, it actually prints white bool drawWindow = _state.LCDCBits[5]; for (int row = rowBegin; row < rowEnd; row++) { if ((row >= _state.CurrentWY) && (row < 144)) { // The offset indexes represent that the window is drawn from it's beggining // at (WX, WY) DisFuncs.GetRowPixels(ref _tempFrameLineBuffer, _pixelLookupTable, _disDef, _memory, _tempPixelBuffer, row - _state.CurrentWY, _state.LCDCBits[6], _state.LCDCBits[4]); // Independent target if (_updateDebugTargets[(int)DebugTargets.Window]) { DrawFuncs.DrawLine(_disDef, _debugInternalTargets[(int)DebugTargets.Window], _disDef.ScreenPixelCountX, _tempFrameLineBuffer, rWX, row, 0, _disDef.ScreenPixelCountX - rWX); } // Screen target if (drawWindow) { DrawFuncs.DrawLine(_disDef, _screenInternalBuffer, _disDef.ScreenPixelCountX, _tempFrameLineBuffer, rWX, row, 0, _disDef.ScreenPixelCountX - rWX); } } } #endregion #region SPRITES bool drawSprites = _state.LCDCBits[1]; for (int row = rowBegin; row < rowEnd; row++) { if (_updateDebugTargets[(int)DebugTargets.SpriteLayer]) { // Independent target uint[] pixels = new uint[_disDef.ScreenPixelCountX]; DisFuncs.GetSpriteRowPixels(_pixelLookupTable, _disDef, _memory, _spriteOAMs, pixels, _tempPixelBuffer, row, _state.LCDCBits[2], true); DrawFuncs.DrawLine(_disDef, _debugInternalTargets[(int)DebugTargets.SpriteLayer], _disDef.ScreenPixelCountX, pixels, 0, row, 0, _disDef.ScreenPixelCountX); } // Screen Target if (drawSprites) { DisFuncs.GetPixelRowFromBitmap(ref _tempFrameLineBuffer, _disDef, _screenInternalBuffer, row, _disDef.ScreenPixelCountX); DisFuncs.GetSpriteRowPixels(_pixelLookupTable, _disDef, _memory, _spriteOAMs, _tempFrameLineBuffer, _tempPixelBuffer, row, _state.LCDCBits[2]); DrawFuncs.DrawLine(_disDef, _screenInternalBuffer, _disDef.ScreenPixelCountX, _tempFrameLineBuffer, 0, row, 0, _disDef.ScreenPixelCountX); } } #endregion }