BizHawk/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Vic.Render.cs

309 lines
7.9 KiB
C#
Raw Normal View History

2016-02-22 23:50:11 +00:00
namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
{
2016-02-22 23:50:11 +00:00
public sealed partial class Vic
2013-11-12 19:22:09 +00:00
{
2017-04-24 13:35:05 +00:00
[SaveState.DoNotSave] private int _borderPixel;
[SaveState.DoNotSave] private int _bufferPixel;
[SaveState.DoNotSave] private int _ecmPixel;
2016-02-22 23:50:11 +00:00
[SaveState.DoNotSave] private int _pixel;
[SaveState.DoNotSave] private int _pixelCounter;
[SaveState.DoNotSave] private int _pixelData;
[SaveState.DoNotSave] private int _pixelOwner;
[SaveState.DoNotSave] private int _sprData;
[SaveState.DoNotSave] private int _sprIndex;
[SaveState.DoNotSave] private int _sprPixel;
2017-04-24 13:35:05 +00:00
private int _srSync;
private int _srColorSync;
private int _srColorIndexLatch;
2016-02-22 23:50:11 +00:00
private int _videoMode;
2017-04-24 13:35:05 +00:00
private int _borderOnShiftReg;
2016-02-22 23:50:11 +00:00
2017-04-24 13:35:05 +00:00
[SaveState.DoNotSave] private const int VideoMode000 = 0;
[SaveState.DoNotSave] private const int VideoMode001 = 1;
[SaveState.DoNotSave] private const int VideoMode010 = 2;
[SaveState.DoNotSave] private const int VideoMode011 = 3;
[SaveState.DoNotSave] private const int VideoMode100 = 4;
[SaveState.DoNotSave] private const int VideoModeInvalid = -1;
2013-11-12 19:22:09 +00:00
2017-04-24 13:35:05 +00:00
[SaveState.DoNotSave] private const int SrMask1 = 0x20000;
2016-02-22 23:50:11 +00:00
[SaveState.DoNotSave] private const int SrMask2 = SrMask1 << 1;
[SaveState.DoNotSave] private const int SrMask3 = SrMask1 | SrMask2;
2017-04-24 13:35:05 +00:00
[SaveState.DoNotSave] private const int SrColorMask = 0x8000;
[SaveState.DoNotSave] private const int SrSpriteMask = SrSpriteMask2;
[SaveState.DoNotSave] private const int SrSpriteMask1 = 0x400000;
2016-02-22 23:50:11 +00:00
[SaveState.DoNotSave] private const int SrSpriteMask2 = SrSpriteMask1 << 1;
[SaveState.DoNotSave] private const int SrSpriteMask3 = SrSpriteMask1 | SrSpriteMask2;
2017-04-24 13:35:05 +00:00
[SaveState.DoNotSave] private const int SrSpriteMaskMc = SrSpriteMask3;
2016-02-22 23:50:11 +00:00
2017-04-24 13:35:05 +00:00
private void Render()
2013-11-12 19:22:09 +00:00
{
2017-04-24 13:35:05 +00:00
if (_rasterX == _hblankEndCheckXRaster)
_hblank = false;
if (_rasterX == _hblankStartCheckXRaster)
_hblank = true;
2013-11-12 19:22:09 +00:00
2017-04-24 13:35:05 +00:00
_renderEnabled = !_hblank && !_vblank;
2016-02-22 23:50:11 +00:00
_pixelCounter = -1;
while (_pixelCounter++ < 3)
2013-11-12 19:22:09 +00:00
{
2017-04-24 13:35:05 +00:00
if ((_srColorSync & SrColorMask) != 0)
{
_displayC = _bufferC[_srColorIndexLatch];
_srColorIndexLatch = (_srColorIndexLatch + 1) & 0x3F;
}
2013-11-12 19:22:09 +00:00
2017-04-24 13:35:05 +00:00
#region PRE-RENDER BORDER
2013-11-12 19:22:09 +00:00
2017-04-24 13:35:05 +00:00
// check left border
if (_borderCheckLEnable && (_rasterX == _borderL))
2013-11-12 19:22:09 +00:00
{
2016-02-22 23:50:11 +00:00
if (_rasterLine == _borderB)
_borderOnVertical = true;
if (_cycle == _totalCycles && _rasterLine == _borderT && _displayEnable)
_borderOnVertical = false;
if (!_borderOnVertical)
_borderOnMain = false;
2013-11-12 19:22:09 +00:00
}
2017-04-24 13:35:05 +00:00
// check right border
if (_borderCheckREnable && (_rasterX == _borderR))
_borderOnMain = true;
2016-02-22 23:50:11 +00:00
2017-04-24 13:35:05 +00:00
#endregion
2016-02-22 23:50:11 +00:00
2017-04-24 13:35:05 +00:00
#region CHARACTER GRAPHICS
switch (_videoMode)
2013-11-12 19:22:09 +00:00
{
2016-02-22 23:50:11 +00:00
case VideoMode000:
_pixelData = _sr & SrMask2;
_pixel = _pixelData != 0 ? _displayC >> 8 : _backgroundColor0;
2013-11-12 19:22:09 +00:00
break;
2016-02-22 23:50:11 +00:00
case VideoMode001:
if ((_displayC & 0x800) != 0)
2013-11-12 19:22:09 +00:00
{
2017-04-24 13:35:05 +00:00
// multicolor 001
2016-02-22 23:50:11 +00:00
if ((_srSync & SrMask2) != 0)
_pixelData = _sr & SrMask3;
2013-11-12 19:22:09 +00:00
2017-04-24 13:35:05 +00:00
switch (_pixelData)
{
case 0:
_pixel = _backgroundColor0;
break;
case SrMask1:
_pixel = _backgroundColor1;
break;
case SrMask2:
_pixel = _backgroundColor2;
break;
default:
_pixel = (_displayC & 0x700) >> 8;
break;
}
2013-11-12 19:22:09 +00:00
}
else
{
// standard 001
2016-02-22 23:50:11 +00:00
_pixelData = _sr & SrMask2;
_pixel = _pixelData != 0 ? _displayC >> 8 : _backgroundColor0;
2013-11-12 19:22:09 +00:00
}
break;
2016-02-22 23:50:11 +00:00
case VideoMode010:
_pixelData = _sr & SrMask2;
_pixel = _pixelData != 0 ? _displayC >> 4 : _displayC;
2013-11-12 19:22:09 +00:00
break;
2016-02-22 23:50:11 +00:00
case VideoMode011:
if ((_srSync & SrMask2) != 0)
_pixelData = _sr & SrMask3;
2013-11-12 19:22:09 +00:00
2016-02-22 23:50:11 +00:00
switch (_pixelData)
{
2017-04-24 13:35:05 +00:00
case 0:
_pixel = _backgroundColor0;
break;
case SrMask1:
_pixel = _displayC >> 4;
break;
case SrMask2:
_pixel = _displayC;
break;
default:
_pixel = _displayC >> 8;
break;
2016-02-22 23:50:11 +00:00
}
2013-11-12 19:22:09 +00:00
break;
2016-02-22 23:50:11 +00:00
case VideoMode100:
_pixelData = _sr & SrMask2;
if (_pixelData != 0)
2013-11-12 19:22:09 +00:00
{
2016-02-22 23:50:11 +00:00
_pixel = _displayC >> 8;
2013-11-12 19:22:09 +00:00
}
else
{
2017-04-24 13:35:05 +00:00
_ecmPixel = (_displayC & 0xC0) >> 6;
switch (_ecmPixel)
{
case 0:
_pixel = _backgroundColor0;
break;
case 1:
_pixel = _backgroundColor1;
break;
case 2:
_pixel = _backgroundColor2;
break;
default:
_pixel = _backgroundColor3;
break;
}
2013-11-12 19:22:09 +00:00
}
2017-04-24 13:35:05 +00:00
break;
2013-11-12 19:22:09 +00:00
default:
2016-02-22 23:50:11 +00:00
_pixelData = 0;
_pixel = 0;
2013-11-12 19:22:09 +00:00
break;
}
2016-02-22 23:50:11 +00:00
_pixel &= 0xF;
_sr <<= 1;
_srSync <<= 1;
2017-04-24 13:35:05 +00:00
_srColorSync <<= 1;
#endregion
2013-11-12 19:22:09 +00:00
2017-04-24 13:35:05 +00:00
#region SPRITES
// render sprites
_pixelOwner = -1;
2016-02-22 23:50:11 +00:00
_sprIndex = 0;
foreach (var spr in _sprites)
2013-11-12 19:22:09 +00:00
{
2016-02-22 23:50:11 +00:00
_sprData = 0;
_sprPixel = _pixel;
2013-11-12 19:22:09 +00:00
2016-02-22 23:50:11 +00:00
if (spr.X == _rasterX)
{
2016-02-22 23:50:11 +00:00
spr.ShiftEnable = spr.Display;
spr.XCrunch = !spr.XExpand;
spr.MulticolorCrunch = false;
}
else
{
2016-02-22 23:50:11 +00:00
spr.XCrunch |= !spr.XExpand;
}
2013-11-12 19:22:09 +00:00
2016-02-22 23:50:11 +00:00
if (spr.ShiftEnable) // sprite rule 6
2013-11-12 19:22:09 +00:00
{
2016-02-22 23:50:11 +00:00
if (spr.Multicolor)
2013-11-12 19:22:09 +00:00
{
2016-02-22 23:50:11 +00:00
_sprData = spr.Sr & SrSpriteMaskMc;
if (spr.MulticolorCrunch && spr.XCrunch && !_rasterXHold)
{
2016-02-22 23:50:11 +00:00
if (spr.Loaded == 0)
{
2016-02-22 23:50:11 +00:00
spr.ShiftEnable = false;
}
2016-02-22 23:50:11 +00:00
spr.Sr <<= 2;
spr.Loaded >>= 2;
}
2016-02-22 23:50:11 +00:00
spr.MulticolorCrunch ^= spr.XCrunch;
2013-11-12 19:22:09 +00:00
}
else
{
2016-02-22 23:50:11 +00:00
_sprData = spr.Sr & SrSpriteMask;
if (spr.XCrunch && !_rasterXHold)
{
2016-02-22 23:50:11 +00:00
if (spr.Loaded == 0)
{
2016-02-22 23:50:11 +00:00
spr.ShiftEnable = false;
}
2016-02-22 23:50:11 +00:00
spr.Sr <<= 1;
spr.Loaded >>= 1;
}
2013-11-12 19:22:09 +00:00
}
2016-02-22 23:50:11 +00:00
spr.XCrunch ^= spr.XExpand;
2013-11-12 19:22:09 +00:00
2016-02-22 23:50:11 +00:00
if (_sprData != 0)
2013-11-12 19:22:09 +00:00
{
// sprite-sprite collision
2016-02-22 23:50:11 +00:00
if (_pixelOwner < 0)
2013-11-12 19:22:09 +00:00
{
2017-04-24 13:35:05 +00:00
switch (_sprData)
{
case SrSpriteMask1:
_sprPixel = _spriteMulticolor0;
break;
case SrSpriteMask2:
_sprPixel = spr.Color;
break;
case SrSpriteMask3:
_sprPixel = _spriteMulticolor1;
break;
}
_pixelOwner = _sprIndex;
2013-11-12 19:22:09 +00:00
}
else
{
2016-02-22 23:50:11 +00:00
if (!_borderOnVertical)
2013-11-12 19:22:09 +00:00
{
2016-02-22 23:50:11 +00:00
spr.CollideSprite = true;
_sprites[_pixelOwner].CollideSprite = true;
2013-11-12 19:22:09 +00:00
}
}
// sprite-data collision
2016-02-22 23:50:11 +00:00
if (!_borderOnVertical && (_pixelData >= SrMask2))
2013-11-12 19:22:09 +00:00
{
2016-02-22 23:50:11 +00:00
spr.CollideData = true;
2013-11-12 19:22:09 +00:00
}
// sprite priority logic
2016-02-22 23:50:11 +00:00
if (spr.Priority)
{
2016-02-22 23:50:11 +00:00
_pixel = _pixelData >= SrMask2 ? _pixel : _sprPixel;
}
else
{
2016-02-22 23:50:11 +00:00
_pixel = _sprPixel;
}
}
2013-11-12 19:22:09 +00:00
}
2016-02-22 23:50:11 +00:00
_sprIndex++;
2013-11-12 19:22:09 +00:00
}
2017-04-24 13:35:05 +00:00
#endregion
2017-04-24 13:35:05 +00:00
#region POST-RENDER BORDER
2013-11-12 19:22:09 +00:00
2017-04-24 13:35:05 +00:00
// border doesn't work with the background buffer
_borderPixel = _pixBorderBuffer[_pixBufferBorderIndex];
_pixBorderBuffer[_pixBufferBorderIndex] = _borderColor;
#endregion
2013-11-12 19:22:09 +00:00
// plot pixel if within viewing area
2016-02-22 23:50:11 +00:00
if (_renderEnabled)
2013-11-12 19:22:09 +00:00
{
2017-04-24 13:35:05 +00:00
_bufferPixel = (_borderOnShiftReg & 0x80000) != 0 ? _borderPixel : _pixBuffer[_pixBufferIndex];
_buf[_bufOffset] = Palette[_bufferPixel];
2016-02-22 23:50:11 +00:00
_bufOffset++;
if (_bufOffset == _bufLength)
_bufOffset = 0;
2013-11-12 19:22:09 +00:00
}
2017-04-24 13:35:05 +00:00
_borderOnShiftReg <<= 1;
_borderOnShiftReg |= (_borderOnVertical || _borderOnMain) ? 1 : 0;
_pixBuffer[_pixBufferIndex] = _pixel;
2016-02-22 23:50:11 +00:00
_pixBufferIndex++;
2017-04-24 13:35:05 +00:00
_pixBufferBorderIndex++;
2013-11-12 19:22:09 +00:00
2017-04-24 13:35:05 +00:00
if (!_rasterXHold)
2016-02-22 23:50:11 +00:00
_rasterX++;
2013-11-12 19:22:09 +00:00
}
2017-04-24 13:35:05 +00:00
if (_pixBufferBorderIndex >= PixBorderBufferSize)
_pixBufferBorderIndex = 0;
if (_pixBufferIndex >= PixBufferSize)
2016-02-22 23:50:11 +00:00
_pixBufferIndex = 0;
2013-11-12 19:22:09 +00:00
}
}
}