Better emulation of the starfield effect in Cosmic Ark and Stay Frosty.

The movement was already correct, but one of the missiles has weird
behaviour caused by 'confusing' the TIA.  This results in a four
colour-clock wide missile with the third pixel turned off.  I don't
know if this is entirely accurate, but I do know that the snow in
Stay Frosty now looks exactly the same in emulation as is does on a
real system, so I'm content to leave it for now.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1866 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2009-08-28 21:53:31 +00:00
parent bf83ffde53
commit 8f8095073b
3 changed files with 108 additions and 39 deletions

View File

@ -813,7 +813,7 @@ inline void TIA::updateFrameScanline(uInt32 clocksToUpdate, uInt32 hpos)
// Handle all other possible combinations
else
{
// Update masks (M0 and M1 are done in updateFrame)
// Update masks
myCurrentBLMask = &TIATables::BLMask[myPOSBL & 0x03]
[(myCTRLPF & 0x30) >> 4][160 - (myPOSBL & 0xFC)];
myCurrentP0Mask = &TIATables::PxMask[myPOSP0 & 0x03]
@ -829,20 +829,20 @@ inline void TIA::updateFrameScanline(uInt32 clocksToUpdate, uInt32 hpos)
// what's really going on here.
if(myHMM0mmr && myPOSM0 % 4 == 3)
{
// Stretch this missle so it's at least 2 pixels wide
// Stretch this missle so it's 4 pixels wide, with the 3rd pixel
// blanked out; this is indicated by using a size of '4'
myCurrentM0Mask = &TIATables::MxMask[myPOSM0 & 0x03]
[myNUSIZ0 & 0x07][((myNUSIZ0 & 0x30) >> 4) | 0x01]
[160 - (myPOSM0 & 0xFC)];
[myNUSIZ0 & 0x07][4][160 - (myPOSM0 & 0xFC)];
}
else
myCurrentM0Mask = &TIATables::MxMask[myPOSM0 & 0x03]
[myNUSIZ0 & 0x07][(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFC)];
if(myHMM1mmr && myPOSM1 % 4 == 3)
{
// Stretch this missle so it's at least 2 pixels wide
// Stretch this missle so it's 4 pixels wide, with the 3rd pixel
// blanked out; this is indicated by using a size of '4'
myCurrentM1Mask = &TIATables::MxMask[myPOSM1 & 0x03]
[myNUSIZ1 & 0x07][((myNUSIZ1 & 0x30) >> 4) | 0x01]
[160 - (myPOSM1 & 0xFC)];
[myNUSIZ1 & 0x07][4][160 - (myPOSM1 & 0xFC)];
}
else
myCurrentM1Mask = &TIATables::MxMask[myPOSM1 & 0x03]

View File

@ -208,7 +208,7 @@ void TIATables::buildPxMaskTable()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// [4][8][4][320]
// [4][8][5][320]
// [alignment][number][size][pixel]
void TIATables::buildMxMaskTable()
{
@ -217,68 +217,134 @@ void TIATables::buildMxMaskTable()
// Clear the missle table to start with
for(number = 0; number < 8; ++number)
for(size = 0; size < 4; ++size)
for(size = 0; size < 5; ++size)
for(x = 0; x < 160; ++x)
MxMask[0][number][size][x] = false;
for(number = 0; number < 8; ++number)
{
for(size = 0; size < 4; ++size)
for(size = 0; size < 5; ++size)
{
for(x = 0; x < 160 + 72; ++x)
{
// For the following, size index = 4 is almost exactly the same as
// index = 2; that is, 1 << 2, or 4 colour clocks wide
// To simulate the weirdness in the Cosmic Ark starfield effect,
// each group of 4 pixels has its 3rd pixel blanked
switch(number)
{
// Only one copy of the missle
case 0x00:
case 0x05:
case 0x07:
if((x >= 0) && (x < (1 << size)))
MxMask[0][number][size][x % 160] = true;
if(size != 4)
{
if((x >= 0) && (x < (1 << size)))
MxMask[0][number][size][x % 160] = true;
}
else
{
if((x >= 0) && (x < (1 << 2)))
MxMask[0][number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
}
break;
// Two copies - close
case 0x01:
if((x >= 0) && (x < (1 << size)))
MxMask[0][number][size][x % 160] = true;
else if(((x - 16) >= 0) && ((x - 16) < (1 << size)))
MxMask[0][number][size][x % 160] = true;
if(size != 4)
{
if((x >= 0) && (x < (1 << size)))
MxMask[0][number][size][x % 160] = true;
else if(((x - 16) >= 0) && ((x - 16) < (1 << size)))
MxMask[0][number][size][x % 160] = true;
}
else
{
if((x >= 0) && (x < (1 << 2)))
MxMask[0][number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
else if(((x - 16) >= 0) && ((x - 16) < (1 << 2)))
MxMask[0][number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
}
break;
// Two copies - medium
case 0x02:
if((x >= 0) && (x < (1 << size)))
MxMask[0][number][size][x % 160] = true;
else if(((x - 32) >= 0) && ((x - 32) < (1 << size)))
MxMask[0][number][size][x % 160] = true;
if(size != 4)
{
if((x >= 0) && (x < (1 << size)))
MxMask[0][number][size][x % 160] = true;
else if(((x - 32) >= 0) && ((x - 32) < (1 << size)))
MxMask[0][number][size][x % 160] = true;
}
else
{
if((x >= 0) && (x < (1 << 2)))
MxMask[0][number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
else if(((x - 32) >= 0) && ((x - 32) < (1 << 2)))
MxMask[0][number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
}
break;
// Three copies - close
case 0x03:
if((x >= 0) && (x < (1 << size)))
MxMask[0][number][size][x % 160] = true;
else if(((x - 16) >= 0) && ((x - 16) < (1 << size)))
MxMask[0][number][size][x % 160] = true;
else if(((x - 32) >= 0) && ((x - 32) < (1 << size)))
MxMask[0][number][size][x % 160] = true;
if(size != 4)
{
if((x >= 0) && (x < (1 << size)))
MxMask[0][number][size][x % 160] = true;
else if(((x - 16) >= 0) && ((x - 16) < (1 << size)))
MxMask[0][number][size][x % 160] = true;
else if(((x - 32) >= 0) && ((x - 32) < (1 << size)))
MxMask[0][number][size][x % 160] = true;
}
else
{
if((x >= 0) && (x < (1 << 2)))
MxMask[0][number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
else if(((x - 16) >= 0) && ((x - 16) < (1 << 2)))
MxMask[0][number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
else if(((x - 32) >= 0) && ((x - 32) < (1 << 2)))
MxMask[0][number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
}
break;
// Two copies - wide
case 0x04:
if((x >= 0) && (x < (1 << size)))
MxMask[0][number][size][x % 160] = true;
else if(((x - 64) >= 0) && ((x - 64) < (1 << size)))
MxMask[0][number][size][x % 160] = true;
if(size != 4)
{
if((x >= 0) && (x < (1 << size)))
MxMask[0][number][size][x % 160] = true;
else if(((x - 64) >= 0) && ((x - 64) < (1 << size)))
MxMask[0][number][size][x % 160] = true;
}
else
{
if((x >= 0) && (x < (1 << 2)))
MxMask[0][number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
else if(((x - 64) >= 0) && ((x - 64) < (1 << 2)))
MxMask[0][number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
}
break;
// Three copies - medium
case 0x06:
if((x >= 0) && (x < (1 << size)))
MxMask[0][number][size][x % 160] = true;
else if(((x - 32) >= 0) && ((x - 32) < (1 << size)))
MxMask[0][number][size][x % 160] = true;
else if(((x - 64) >= 0) && ((x - 64) < (1 << size)))
MxMask[0][number][size][x % 160] = true;
if(size != 4)
{
if((x >= 0) && (x < (1 << size)))
MxMask[0][number][size][x % 160] = true;
else if(((x - 32) >= 0) && ((x - 32) < (1 << size)))
MxMask[0][number][size][x % 160] = true;
else if(((x - 64) >= 0) && ((x - 64) < (1 << size)))
MxMask[0][number][size][x % 160] = true;
}
else
{
if((x >= 0) && (x < (1 << 2)))
MxMask[0][number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
else if(((x - 32) >= 0) && ((x - 32) < (1 << 2)))
MxMask[0][number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
else if(((x - 64) >= 0) && ((x - 64) < (1 << 2)))
MxMask[0][number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true);
}
break;
}
}
@ -295,7 +361,7 @@ void TIATables::buildMxMaskTable()
{
for(number = 0; number < 8; ++number)
{
for(size = 0; size < 4; ++size)
for(size = 0; size < 5; ++size)
{
for(x = 0; x < 320; ++x)
{
@ -556,7 +622,7 @@ const Int16 TIATables::PokeDelay[64] = {
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 TIATables::MxMask[4][8][4][320];
uInt8 TIATables::MxMask[4][8][5][320];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const bool TIATables::HMOVEBlankEnableCycles[76] = {

View File

@ -155,7 +155,10 @@ class TIATables
// Missle mask table (entries are true or false)
// [alignment][number][size][pixel]
static uInt8 MxMask[4][8][4][320];
// There are actually only 4 possible size combinations on a real system
// The fifth size is used for simulating the starfield effect in
// Cosmic Ark and Stay Frosty
static uInt8 MxMask[4][8][5][320];
// Ball mask table (entries are true or false)
// [alignment][size][pixel]