262 lines
5.7 KiB
C#
262 lines
5.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|
{
|
|
sealed public partial class Vic
|
|
{
|
|
private int delayC;
|
|
private int ecmPixel;
|
|
private int pixel;
|
|
private int pixelCounter;
|
|
private int pixelData;
|
|
private int pixelOwner;
|
|
private int sprData;
|
|
private int sprIndex;
|
|
private int sprPixel;
|
|
private int srC = 0;
|
|
private int srSync = 0;
|
|
private int videoMode;
|
|
|
|
private void Render()
|
|
{
|
|
if (hblankCheckEnableL)
|
|
{
|
|
if (rasterX == hblankEnd)
|
|
hblank = false;
|
|
}
|
|
else if (hblankCheckEnableR)
|
|
{
|
|
if (rasterX == hblankStart)
|
|
hblank = true;
|
|
}
|
|
|
|
renderEnabled = (!hblank && !vblank);
|
|
pixelCounter = -1;
|
|
while (pixelCounter++ < 3)
|
|
{
|
|
|
|
if (delayC > 0)
|
|
delayC--;
|
|
else
|
|
displayC = (srC >> 12) & 0xFFF;
|
|
|
|
|
|
#region PRE-RENDER BORDER
|
|
if (borderCheckLEnable && (rasterX == borderL))
|
|
{
|
|
if (rasterLine == borderB)
|
|
borderOnVertical = true;
|
|
if (rasterLine == borderT && displayEnable)
|
|
borderOnVertical = false;
|
|
if (!borderOnVertical)
|
|
borderOnMain = false;
|
|
}
|
|
#endregion
|
|
|
|
#region CHARACTER GRAPHICS
|
|
switch (videoMode)
|
|
{
|
|
case 0:
|
|
pixelData = sr & srMask2;
|
|
pixel = (pixelData != 0) ? (displayC >> 8) : backgroundColor0;
|
|
break;
|
|
case 1:
|
|
if ((displayC & 0x800) != 0)
|
|
{
|
|
// multicolor 001
|
|
if ((srSync & srMask2) != 0)
|
|
pixelData = sr & srMask3;
|
|
|
|
if (pixelData == 0)
|
|
pixel = backgroundColor0;
|
|
else if (pixelData == srMask1)
|
|
pixel = backgroundColor1;
|
|
else if (pixelData == srMask2)
|
|
pixel = backgroundColor2;
|
|
else
|
|
pixel = (displayC & 0x700) >> 8;
|
|
}
|
|
else
|
|
{
|
|
// standard 001
|
|
pixelData = sr & srMask2;
|
|
pixel = (pixelData != 0) ? (displayC >> 8) : backgroundColor0;
|
|
}
|
|
break;
|
|
case 2:
|
|
pixelData = sr & srMask2;
|
|
pixel = (pixelData != 0) ? (displayC >> 4) : (displayC);
|
|
break;
|
|
case 3:
|
|
if ((srSync & srMask2) != 0)
|
|
pixelData = sr & srMask3;
|
|
|
|
if (pixelData == 0)
|
|
pixel = backgroundColor0;
|
|
else if (pixelData == srMask1)
|
|
pixel = (displayC >> 4);
|
|
else if (pixelData == srMask2)
|
|
pixel = displayC;
|
|
else
|
|
pixel = (displayC >> 8);
|
|
break;
|
|
case 4:
|
|
pixelData = sr & srMask2;
|
|
if (pixelData != 0)
|
|
{
|
|
pixel = displayC >> 8;
|
|
}
|
|
else
|
|
{
|
|
ecmPixel = (displayC) & 0xC0;
|
|
if (ecmPixel == 0x00)
|
|
pixel = backgroundColor0;
|
|
else if (ecmPixel == 0x40)
|
|
pixel = backgroundColor1;
|
|
else if (ecmPixel == 0x80)
|
|
pixel = backgroundColor2;
|
|
else
|
|
pixel = backgroundColor3;
|
|
}
|
|
break;
|
|
default:
|
|
pixelData = 0;
|
|
pixel = 0;
|
|
break;
|
|
}
|
|
pixel &= 0xF;
|
|
sr <<= 1;
|
|
srSync <<= 1;
|
|
#endregion
|
|
|
|
#region SPRITES
|
|
// render sprites
|
|
pixelOwner = -1;
|
|
sprIndex = 0;
|
|
foreach (var spr in sprites)
|
|
{
|
|
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)
|
|
{
|
|
if (sprData == srSpriteMask1)
|
|
sprPixel = spriteMulticolor0;
|
|
else if (sprData == srSpriteMask2)
|
|
sprPixel = spr.color;
|
|
else if (sprData == srSpriteMask3)
|
|
sprPixel = spriteMulticolor1;
|
|
pixelOwner = sprIndex;
|
|
}
|
|
else
|
|
{
|
|
if (!borderOnVertical)
|
|
{
|
|
spr.collideSprite = true;
|
|
sprites[pixelOwner].collideSprite = true;
|
|
}
|
|
}
|
|
|
|
// sprite-data collision
|
|
if (!borderOnVertical && (pixelData >= srMask2))
|
|
{
|
|
spr.collideData = true;
|
|
}
|
|
|
|
// sprite priority logic
|
|
if (spr.priority)
|
|
{
|
|
pixel = (pixelData >= srMask2) ? pixel : sprPixel;
|
|
}
|
|
else
|
|
{
|
|
pixel = sprPixel;
|
|
}
|
|
}
|
|
}
|
|
|
|
sprIndex++;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region POST-RENDER BORDER
|
|
if (borderCheckREnable && (rasterX == borderR))
|
|
borderOnMain = true;
|
|
|
|
// border doesn't work with the background buffer
|
|
if (borderOnMain || borderOnVertical)
|
|
pixel = borderColor;
|
|
#endregion
|
|
|
|
// plot pixel if within viewing area
|
|
if (renderEnabled)
|
|
{
|
|
buf[bufOffset] = palette[pixBuffer[pixBufferIndex]];
|
|
bufOffset++;
|
|
if (bufOffset == bufLength)
|
|
bufOffset = 0;
|
|
}
|
|
|
|
pixBuffer[pixBufferIndex] = pixel;
|
|
pixBufferIndex++;
|
|
|
|
if (!rasterXHold)
|
|
rasterX++;
|
|
bitmapColumn++;
|
|
}
|
|
|
|
if (pixBufferIndex >= pixBufferSize)
|
|
pixBufferIndex = 0;
|
|
}
|
|
}
|
|
}
|