241 lines
5.9 KiB
C#
241 lines
5.9 KiB
C#
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 _srActive;
|
|
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()
|
|
{
|
|
if (_rasterX == _hblankEndCheckXRaster)
|
|
_hblank = false;
|
|
if (_rasterX == _hblankStartCheckXRaster)
|
|
_hblank = true;
|
|
|
|
_renderEnabled = !_hblank && !_vblank;
|
|
_pixelCounter = 4;
|
|
while (--_pixelCounter >= 0)
|
|
{
|
|
#region PRE-RENDER BORDER
|
|
|
|
// 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;
|
|
|
|
#endregion
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#region POST-RENDER BORDER
|
|
|
|
// border doesn't work with the background buffer
|
|
_borderPixel = _pixBorderBuffer[_pixBufferBorderIndex];
|
|
_pixBorderBuffer[_pixBufferBorderIndex] = _borderColor;
|
|
#endregion
|
|
|
|
// 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;
|
|
_srActive <<= 1;
|
|
_srColorEnable <<= 1;
|
|
}
|
|
|
|
if (_pixBufferBorderIndex >= PixBorderBufferSize)
|
|
{
|
|
_pixBufferBorderIndex = 0;
|
|
}
|
|
|
|
if (_pixBufferIndex >= PixBufferSize)
|
|
{
|
|
_pixBufferIndex = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|