namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS { public sealed partial class Vic { private int _borderPixel; private int _bufferPixel; private int _pixel; private int _pixelCounter; private int _pixelOwner; private Sprite _spr; private int _sprData; private int _sprIndex; private int _sprPixel; private int _srColor0; private int _srColor1; private int _srColor2; private int _srColor3; private int _srData1; private int _srColorEnable; private int _videoMode; private int _borderOnShiftReg; private const int VideoMode000 = 0; private const int VideoMode001 = 1; private const int VideoMode010 = 2; private const int VideoMode011 = 3; private const int VideoMode100 = 4; private const int VideoModeInvalid = -1; private const int SrMask1 = 0x40000; private const int SrSpriteMask = SrSpriteMask2; private const int SrSpriteMask1 = 0x400000; private const int SrSpriteMask2 = SrSpriteMask1 << 1; private const int SrSpriteMask3 = SrSpriteMask1 | SrSpriteMask2; private const int SrSpriteMaskMc = SrSpriteMask3; private void Render() { void PreRenderBorder() { // check left border if (_borderCheckLEnable && (_rasterX == _borderL)) { if (_rasterLine == _borderB) _borderOnVertical = true; if (_cycle == _totalCycles && _rasterLine == _borderT && _displayEnable) _borderOnVertical = false; if (!_borderOnVertical) _borderOnMain = false; } // check right border if (_borderCheckREnable && (_rasterX == _borderR)) _borderOnMain = true; } void PostRenderBorder() { // border doesn't work with the background buffer _borderPixel = _pixBorderBuffer[_pixBufferBorderIndex]; _pixBorderBuffer[_pixBufferBorderIndex] = _borderColor; } if (_rasterX == _hblankEndCheckXRaster) _hblank = false; if (_rasterX == _hblankStartCheckXRaster) _hblank = true; _renderEnabled = !_hblank && !_vblank; _pixelCounter = 4; while (--_pixelCounter >= 0) { PreRenderBorder(); // render graphics if ((_srColorEnable & SrMask1) != 0) { _pixel = ((_srColor0 & SrMask1) >> 18) | ((_srColor1 & SrMask1) >> 17) | ((_srColor2 & SrMask1) >> 16) | ((_srColor3 & SrMask1) >> 15); } else { switch (((_srColor0 & SrMask1) >> 18) | ((_srColor1 & SrMask1) >> 17)) { case 1: _pixel = _idle ? 0 : _backgroundColor1; break; case 2: _pixel = _idle ? 0 : _backgroundColor2; break; case 3: _pixel = _idle ? 0 : _backgroundColor3; break; default: _pixel = _backgroundColor0; break; } } // render sprites _pixelOwner = -1; for (_sprIndex = 0; _sprIndex < 8; _sprIndex++) { _spr = _sprites[_sprIndex]; _sprData = 0; _sprPixel = _pixel; if (_spr.X == _rasterX) { _spr.ShiftEnable = _spr.Display; _spr.XCrunch = !_spr.XExpand; _spr.MulticolorCrunch = false; } else { _spr.XCrunch |= !_spr.XExpand; } if (_spr.ShiftEnable) // sprite rule 6 { if (_spr.Multicolor) { _sprData = _spr.Sr & SrSpriteMaskMc; if (_spr.MulticolorCrunch && _spr.XCrunch && !_rasterXHold) { if (_spr.Loaded == 0) { _spr.ShiftEnable = false; } _spr.Sr <<= 2; _spr.Loaded >>= 2; } _spr.MulticolorCrunch ^= _spr.XCrunch; } else { _sprData = _spr.Sr & SrSpriteMask; if (_spr.XCrunch && !_rasterXHold) { if (_spr.Loaded == 0) { _spr.ShiftEnable = false; } _spr.Sr <<= 1; _spr.Loaded >>= 1; } } _spr.XCrunch ^= _spr.XExpand; if (_sprData != 0) { // sprite-sprite collision if (_pixelOwner < 0) { switch (_sprData) { case SrSpriteMask1: _sprPixel = _spriteMulticolor0; break; case SrSpriteMask2: _sprPixel = _spr.Color; break; case SrSpriteMask3: _sprPixel = _spriteMulticolor1; break; } _pixelOwner = _sprIndex; } else { if (!_borderOnVertical) { _spr.CollideSprite = true; _sprites[_pixelOwner].CollideSprite = true; _intSpriteCollision = true; } } // sprite-data collision if (!_borderOnVertical && (_srData1 & SrMask1) != 0) { _spr.CollideData = true; _intSpriteDataCollision = true; } // sprite priority logic if (_spr.Priority) { _pixel = (_srData1 & SrMask1) != 0 ? _pixel : _sprPixel; } else { _pixel = _sprPixel; } } } } PostRenderBorder(); // plot pixel if within viewing area if (_renderEnabled) { _bufferPixel = (_borderOnShiftReg & 0x80000) != 0 ? _borderPixel : _pixBuffer[_pixBufferIndex]; _buf[_bufOffset] = Palette[_bufferPixel]; _bufOffset++; if (_bufOffset == _bufLength) _bufOffset = 0; } _borderOnShiftReg <<= 1; _borderOnShiftReg |= (_borderOnVertical || _borderOnMain) ? 1 : 0; _pixBuffer[_pixBufferIndex] = _pixel; _pixBufferIndex++; _pixBufferBorderIndex++; if (!_rasterXHold) _rasterX++; _srColor0 <<= 1; _srColor1 <<= 1; _srColor2 <<= 1; _srColor3 <<= 1; _srData1 <<= 1; _srColorEnable <<= 1; } if (_pixBufferBorderIndex >= PixBorderBufferSize) { _pixBufferBorderIndex = 0; } if (_pixBufferIndex >= PixBufferSize) { _pixBufferIndex = 0; } } } }