Added TIA support for a '7-color' register model. This means we can see

all graphical objects in different colors in fixed debug colors mode,
even those that normally share a color register (ie, P0/M0, P1/M1, etc).

Removed TIA::updateFrameScanline, an unwieldy 600+ line function.  It
was useful as an optimization measure when Stella was first written,
but at this point I think it's more trouble than it's worth.  Removing
the code not only makes the TIA class much smaller and easier to
understand, it also fixes some graphical bugs in fixed debug colors
mode (bugs that probably wouldn't have been found otherwise).  Next on
the chopping block are the various 'masks', or at least the alignments
(which cause the arrays to be 4 times larger than they need to be).


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1871 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2009-09-08 22:44:09 +00:00
parent ea0e137a27
commit 42f3052fbf
2 changed files with 120 additions and 656 deletions

View File

@ -60,31 +60,43 @@ TIA::TIA(Console& console, Sound& sound, Settings& settings)
{
if(enabled & PriorityBit)
{
uInt8 color = 0;
// Priority from highest to lowest:
// PF/BL => P0/M0 => P1/M1 => BK
uInt8 color = _BK;
if((enabled & (P1Bit | M1Bit)) != 0)
color = 3;
if((enabled & (P0Bit | M0Bit)) != 0)
color = 2;
if((enabled & M1Bit) != 0)
color = _M1;
if((enabled & P1Bit) != 0)
color = _P1;
if((enabled & M0Bit) != 0)
color = _M0;
if((enabled & P0Bit) != 0)
color = _P0;
if((enabled & BLBit) != 0)
color = 1;
color = _BL;
if((enabled & PFBit) != 0)
color = 1; // NOTE: Playfield has priority so ScoreBit isn't used
color = _PF; // NOTE: Playfield has priority so ScoreBit isn't used
myPriorityEncoder[x][enabled] = color;
}
else
{
uInt8 color = 0;
// Priority from highest to lowest:
// P0/M0 => P1/M1 => PF/BL => BK
uInt8 color = _BK;
if((enabled & BLBit) != 0)
color = 1;
color = _BL;
if((enabled & PFBit) != 0)
color = (enabled & ScoreBit) ? ((x == 0) ? 2 : 3) : 1;
if((enabled & (P1Bit | M1Bit)) != 0)
color = (color != 2) ? 3 : 2;
if((enabled & (P0Bit | M0Bit)) != 0)
color = 2;
color = (enabled & ScoreBit) ? ((x == 0) ? _P0 : _P1) : _PF;
if((enabled & M1Bit) != 0)
color = _M1;
if((enabled & P1Bit) != 0)
color = _P1;
if((enabled & M0Bit) != 0)
color = _M0;
if((enabled & P0Bit) != 0)
color = _P0;
myPriorityEncoder[x][enabled] = color;
}
@ -120,7 +132,6 @@ void TIA::reset()
myVSYNC = myVBLANK = 0;
myNUSIZ0 = myNUSIZ1 = 0;
myColor[_P0] = myColor[_P1] = myColor[_PF] = myColor[_BK] = 0;
// TODO - add support for drawing M0/M1/BL in separate colors
myColor[_M0] = myColor[_M1] = myColor[_BL] = myColor[_HBLANK] = 0;
myPlayfieldPriorityAndScore = 0;
@ -167,6 +178,9 @@ void TIA::reset()
{
myFixedColor[_P0] = 0x30303030;
myFixedColor[_P1] = 0x16161616;
myFixedColor[_M0] = 0x38383838;
myFixedColor[_M1] = 0x12121212;
myFixedColor[_BL] = 0x7e7e7e7e;
myFixedColor[_PF] = 0x76767676;
myFixedColor[_BK] = 0x0a0a0a0a;
myFixedColor[_HBLANK] = 0x0e0e0e0e;
@ -177,6 +191,9 @@ void TIA::reset()
{
myFixedColor[_P0] = 0x62626262;
myFixedColor[_P1] = 0x26262626;
myFixedColor[_M0] = 0x68686868;
myFixedColor[_M1] = 0x2e2e2e2e;
myFixedColor[_BL] = 0xdededede;
myFixedColor[_PF] = 0xd8d8d8d8;
myFixedColor[_BK] = 0x1c1c1c1c;
myFixedColor[_HBLANK] = 0x0e0e0e0e;
@ -611,6 +628,9 @@ inline void TIA::startFrame()
myColor[_P1] |= 0x01010101;
myColor[_PF] |= 0x01010101;
myColor[_BK] |= 0x01010101;
myColor[_M0] |= 0x01010101;
myColor[_M1] |= 0x01010101;
myColor[_BL] |= 0x01010101;
}
else
{
@ -618,6 +638,9 @@ inline void TIA::startFrame()
myColor[_P1] &= 0xfefefefe;
myColor[_PF] &= 0xfefefefe;
myColor[_BK] &= 0xfefefefe;
myColor[_M0] &= 0xfefefefe;
myColor[_M1] &= 0xfefefefe;
myColor[_BL] &= 0xfefefefe;
}
}
myStartScanline = 0x7FFFFFFF;
@ -711,11 +734,11 @@ bool TIA::toggleBit(TIABit b, uInt8 mode)
{
// If mode is 0 or 1, use it as a boolean (off or on)
// Otherwise, flip the state
bool state = (mode == 0 || mode == 1) ? bool(mode) : !(myDisabledObjects & b);
if(state) myDisabledObjects |= b;
else myDisabledObjects &= ~b;
bool on = (mode == 0 || mode == 1) ? bool(mode) : !(myDisabledObjects & b);
if(on) myDisabledObjects |= b;
else myDisabledObjects &= ~b;
return state;
return on;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -723,12 +746,12 @@ bool TIA::toggleFixedColors(uInt8 mode)
{
// If mode is 0 or 1, use it as a boolean (off or on)
// Otherwise, flip the state
bool state = (mode == 0 || mode == 1) ? bool(mode) :
(myColorPtr == myColor ? true : false);
if(state) myColorPtr = myFixedColor;
else myColorPtr = myColor;
bool on = (mode == 0 || mode == 1) ? bool(mode) :
(myColorPtr == myColor ? true : false);
if(on) myColorPtr = myFixedColor;
else myColorPtr = myColor;
return state;
return on;
}
#ifdef DEBUGGER_SUPPORT
@ -798,628 +821,6 @@ void TIA::updateScanlineByTrace(int target)
}
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void TIA::updateFrameScanline(uInt32 clocksToUpdate, uInt32 hpos)
{
// Calculate the ending frame pointer value
uInt8* ending = myFramePointer + clocksToUpdate;
myFramePointerClocks += clocksToUpdate;
// See if we're in the vertical blank region
if(myVBLANK & 0x02)
{
memset(myFramePointer, 0, clocksToUpdate);
}
// Handle all other possible combinations
else
{
// Update masks
myCurrentBLMask = &TIATables::BLMask[myPOSBL & 0x03]
[(myCTRLPF & 0x30) >> 4][160 - (myPOSBL & 0xFC)];
myCurrentP0Mask = &TIATables::PxMask[myPOSP0 & 0x03]
[mySuppressP0][myNUSIZ0 & 0x07][160 - (myPOSP0 & 0xFC)];
myCurrentP1Mask = &TIATables::PxMask[myPOSP1 & 0x03]
[mySuppressP1][myNUSIZ1 & 0x07][160 - (myPOSP1 & 0xFC)];
// TODO - 08-27-2009: Simulate the weird effects of Cosmic Ark and
// Stay Frosty. The movement itself is well understood, but there
// also seems to be some widening and blanking occurring as well.
// This doesn't properly emulate the effect, but it does give a
// fair approximation. More testing is required to figure out
// what's really going on here.
if(myHMM0mmr && myPOSM0 % 4 == 3)
{
// 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][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 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][4][160 - (myPOSM1 & 0xFC)];
}
else
myCurrentM1Mask = &TIATables::MxMask[myPOSM1 & 0x03]
[myNUSIZ1 & 0x07][(myNUSIZ1 & 0x30) >> 4][160 - (myPOSM1 & 0xFC)];
switch(myEnabledObjects | myPlayfieldPriorityAndScore)
{
// Background
case 0x00:
case 0x00 | ScoreBit:
case 0x00 | PriorityBit:
case 0x00 | PriorityBit | ScoreBit:
{
memset(myFramePointer, myColorPtr[_BK], clocksToUpdate);
break;
}
// Playfield is enabled and the priority bit is set (score bit is overridden)
case PFBit:
case PFBit | PriorityBit:
case PFBit | PriorityBit | ScoreBit:
{
uInt32* mask = &myCurrentPFMask[hpos];
// Update a uInt8 at a time until reaching a uInt32 boundary
for(; ((uintptr_t)myFramePointer & 0x03) && (myFramePointer < ending);
++myFramePointer, ++mask)
{
*myFramePointer = (myPF & *mask) ? myColorPtr[_PF] : myColorPtr[_BK];
}
// Now, update a uInt32 at a time
for(; myFramePointer < ending; myFramePointer += 4, mask += 4)
{
*((uInt32*)myFramePointer) = (myPF & *mask) ? myColorPtr[_PF] : myColorPtr[_BK];
}
break;
}
// Playfield is enabled and the score bit is set (without priority bit)
case PFBit | ScoreBit:
{
uInt32* mask = &myCurrentPFMask[hpos];
// Update a uInt8 at a time until reaching a uInt32 boundary
for(; ((uintptr_t)myFramePointer & 0x03) && (myFramePointer < ending);
++myFramePointer, ++mask, ++hpos)
{
*myFramePointer = (myPF & *mask) ?
(hpos < 80 ? myColorPtr[_P0] : myColorPtr[_P1]) : myColorPtr[_BK];
}
// Now, update a uInt32 at a time
for(; myFramePointer < ending;
myFramePointer += 4, mask += 4, hpos += 4)
{
*((uInt32*)myFramePointer) = (myPF & *mask) ?
(hpos < 80 ? myColorPtr[_P0] : myColorPtr[_P1]) : myColorPtr[_BK];
}
break;
}
// Player 0 is enabled
case P0Bit:
case P0Bit | ScoreBit:
case P0Bit | PriorityBit:
case P0Bit | ScoreBit | PriorityBit:
{
uInt8* mP0 = &myCurrentP0Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP0)
{
*(uInt32*)myFramePointer = myColorPtr[_BK];
mP0 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (myCurrentGRP0 & *mP0) ? myColorPtr[_P0] : myColorPtr[_BK];
++mP0; ++myFramePointer;
}
}
break;
}
// Player 1 is enabled
case P1Bit:
case P1Bit | ScoreBit:
case P1Bit | PriorityBit:
case P1Bit | ScoreBit | PriorityBit:
{
uInt8* mP1 = &myCurrentP1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP1)
{
*(uInt32*)myFramePointer = myColorPtr[_BK];
mP1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (myCurrentGRP1 & *mP1) ? myColorPtr[_P1] : myColorPtr[_BK];
++mP1; ++myFramePointer;
}
}
break;
}
// Player 0 and 1 are enabled
case P0Bit | P1Bit:
case P0Bit | P1Bit | ScoreBit:
case P0Bit | P1Bit | PriorityBit:
case P0Bit | P1Bit | ScoreBit | PriorityBit:
{
uInt8* mP0 = &myCurrentP0Mask[hpos];
uInt8* mP1 = &myCurrentP1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP0 &&
!*(uInt32*)mP1)
{
*(uInt32*)myFramePointer = myColorPtr[_BK];
mP0 += 4; mP1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (myCurrentGRP0 & *mP0) ?
myColorPtr[_P0] : ((myCurrentGRP1 & *mP1) ? myColorPtr[_P1] : myColorPtr[_BK]);
if((myCurrentGRP0 & *mP0) && (myCurrentGRP1 & *mP1))
myCollision |= TIATables::CollisionMask[P0Bit | P1Bit];
++mP0; ++mP1; ++myFramePointer;
}
}
break;
}
// Missle 0 is enabled
case M0Bit:
case M0Bit | ScoreBit:
case M0Bit | PriorityBit:
case M0Bit | ScoreBit | PriorityBit:
{
uInt8* mM0 = &myCurrentM0Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mM0)
{
*(uInt32*)myFramePointer = myColorPtr[_BK];
mM0 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = *mM0 ? myColorPtr[_P0] : myColorPtr[_BK];
++mM0; ++myFramePointer;
}
}
break;
}
// Missle 1 is enabled
case M1Bit:
case M1Bit | ScoreBit:
case M1Bit | PriorityBit:
case M1Bit | ScoreBit | PriorityBit:
{
uInt8* mM1 = &myCurrentM1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mM1)
{
*(uInt32*)myFramePointer = myColorPtr[_BK];
mM1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = *mM1 ? myColorPtr[_P1] : myColorPtr[_BK];
++mM1; ++myFramePointer;
}
}
break;
}
// Ball is enabled
case BLBit:
case BLBit | ScoreBit:
case BLBit | PriorityBit:
case BLBit | ScoreBit | PriorityBit:
{
uInt8* mBL = &myCurrentBLMask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL)
{
*(uInt32*)myFramePointer = myColorPtr[_BK];
mBL += 4; myFramePointer += 4;
}
else
{
*myFramePointer = *mBL ? myColorPtr[_PF] : myColorPtr[_BK];
++mBL; ++myFramePointer;
}
}
break;
}
// Missle 0 and 1 are enabled
case M0Bit | M1Bit:
case M0Bit | M1Bit | ScoreBit:
case M0Bit | M1Bit | PriorityBit:
case M0Bit | M1Bit | ScoreBit | PriorityBit:
{
uInt8* mM0 = &myCurrentM0Mask[hpos];
uInt8* mM1 = &myCurrentM1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mM0 && !*(uInt32*)mM1)
{
*(uInt32*)myFramePointer = myColorPtr[_BK];
mM0 += 4; mM1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = *mM0 ? myColorPtr[_P0] : (*mM1 ? myColorPtr[_P1] : myColorPtr[_BK]);
if(*mM0 && *mM1)
myCollision |= TIATables::CollisionMask[M0Bit | M1Bit];
++mM0; ++mM1; ++myFramePointer;
}
}
break;
}
// Ball and Missle 0 are enabled and playfield priority is not set
case BLBit | M0Bit:
case BLBit | M0Bit | ScoreBit:
{
uInt8* mBL = &myCurrentBLMask[hpos];
uInt8* mM0 = &myCurrentM0Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL && !*(uInt32*)mM0)
{
*(uInt32*)myFramePointer = myColorPtr[_BK];
mBL += 4; mM0 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (*mM0 ? myColorPtr[_P0] : (*mBL ? myColorPtr[_PF] : myColorPtr[_BK]));
if(*mBL && *mM0)
myCollision |= TIATables::CollisionMask[BLBit | M0Bit];
++mBL; ++mM0; ++myFramePointer;
}
}
break;
}
// Ball and Missle 0 are enabled and playfield priority is set
case BLBit | M0Bit | PriorityBit:
case BLBit | M0Bit | ScoreBit | PriorityBit:
{
uInt8* mBL = &myCurrentBLMask[hpos];
uInt8* mM0 = &myCurrentM0Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL && !*(uInt32*)mM0)
{
*(uInt32*)myFramePointer = myColorPtr[_BK];
mBL += 4; mM0 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (*mBL ? myColorPtr[_PF] : (*mM0 ? myColorPtr[_P0] : myColorPtr[_BK]));
if(*mBL && *mM0)
myCollision |= TIATables::CollisionMask[BLBit | M0Bit];
++mBL; ++mM0; ++myFramePointer;
}
}
break;
}
// Ball and Missle 1 are enabled and playfield priority is not set
case BLBit | M1Bit:
case BLBit | M1Bit | ScoreBit:
{
uInt8* mBL = &myCurrentBLMask[hpos];
uInt8* mM1 = &myCurrentM1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL &&
!*(uInt32*)mM1)
{
*(uInt32*)myFramePointer = myColorPtr[_BK];
mBL += 4; mM1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (*mM1 ? myColorPtr[_P1] : (*mBL ? myColorPtr[_PF] : myColorPtr[_BK]));
if(*mBL && *mM1)
myCollision |= TIATables::CollisionMask[BLBit | M1Bit];
++mBL; ++mM1; ++myFramePointer;
}
}
break;
}
// Ball and Missle 1 are enabled and playfield priority is set
case BLBit | M1Bit | PriorityBit:
case BLBit | M1Bit | ScoreBit | PriorityBit:
{
uInt8* mBL = &myCurrentBLMask[hpos];
uInt8* mM1 = &myCurrentM1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL &&
!*(uInt32*)mM1)
{
*(uInt32*)myFramePointer = myColorPtr[_BK];
mBL += 4; mM1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (*mBL ? myColorPtr[_PF] : (*mM1 ? myColorPtr[_P1] : myColorPtr[_BK]));
if(*mBL && *mM1)
myCollision |= TIATables::CollisionMask[BLBit | M1Bit];
++mBL; ++mM1; ++myFramePointer;
}
}
break;
}
// Ball and Player 1 are enabled and playfield priority is not set
case BLBit | P1Bit:
case BLBit | P1Bit | ScoreBit:
{
uInt8* mBL = &myCurrentBLMask[hpos];
uInt8* mP1 = &myCurrentP1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP1 && !*(uInt32*)mBL)
{
*(uInt32*)myFramePointer = myColorPtr[_BK];
mBL += 4; mP1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (myCurrentGRP1 & *mP1) ? myColorPtr[_P1] :
(*mBL ? myColorPtr[_PF] : myColorPtr[_BK]);
if(*mBL && (myCurrentGRP1 & *mP1))
myCollision |= TIATables::CollisionMask[BLBit | P1Bit];
++mBL; ++mP1; ++myFramePointer;
}
}
break;
}
// Ball and Player 1 are enabled and playfield priority is set
case BLBit | P1Bit | PriorityBit:
case BLBit | P1Bit | PriorityBit | ScoreBit:
{
uInt8* mBL = &myCurrentBLMask[hpos];
uInt8* mP1 = &myCurrentP1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP1 && !*(uInt32*)mBL)
{
*(uInt32*)myFramePointer = myColorPtr[_BK];
mBL += 4; mP1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = *mBL ? myColorPtr[_PF] :
((myCurrentGRP1 & *mP1) ? myColorPtr[_P1] : myColorPtr[_BK]);
if(*mBL && (myCurrentGRP1 & *mP1))
myCollision |= TIATables::CollisionMask[BLBit | P1Bit];
++mBL; ++mP1; ++myFramePointer;
}
}
break;
}
// Playfield and Player 0 are enabled and playfield priority is not set
case PFBit | P0Bit:
{
uInt32* mPF = &myCurrentPFMask[hpos];
uInt8* mP0 = &myCurrentP0Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP0)
{
*(uInt32*)myFramePointer = (myPF & *mPF) ? myColorPtr[_PF] : myColorPtr[_BK];
mPF += 4; mP0 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (myCurrentGRP0 & *mP0) ?
myColorPtr[_P0] : ((myPF & *mPF) ? myColorPtr[_PF] : myColorPtr[_BK]);
if((myPF & *mPF) && (myCurrentGRP0 & *mP0))
myCollision |= TIATables::CollisionMask[PFBit | P0Bit];
++mPF; ++mP0; ++myFramePointer;
}
}
break;
}
// Playfield and Player 0 are enabled and playfield priority is set
case PFBit | P0Bit | PriorityBit:
{
uInt32* mPF = &myCurrentPFMask[hpos];
uInt8* mP0 = &myCurrentP0Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP0)
{
*(uInt32*)myFramePointer = (myPF & *mPF) ? myColorPtr[_PF] : myColorPtr[_BK];
mPF += 4; mP0 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (myPF & *mPF) ? myColorPtr[_PF] :
((myCurrentGRP0 & *mP0) ? myColorPtr[_P0] : myColorPtr[_BK]);
if((myPF & *mPF) && (myCurrentGRP0 & *mP0))
myCollision |= TIATables::CollisionMask[PFBit | P0Bit];
++mPF; ++mP0; ++myFramePointer;
}
}
break;
}
// Playfield and Player 1 are enabled and playfield priority is not set
case PFBit | P1Bit:
{
uInt32* mPF = &myCurrentPFMask[hpos];
uInt8* mP1 = &myCurrentP1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP1)
{
*(uInt32*)myFramePointer = (myPF & *mPF) ? myColorPtr[_PF] : myColorPtr[_BK];
mPF += 4; mP1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (myCurrentGRP1 & *mP1) ?
myColorPtr[_P1] : ((myPF & *mPF) ? myColorPtr[_PF] : myColorPtr[_BK]);
if((myPF & *mPF) && (myCurrentGRP1 & *mP1))
myCollision |= TIATables::CollisionMask[PFBit | P1Bit];
++mPF; ++mP1; ++myFramePointer;
}
}
break;
}
// Playfield and Player 1 are enabled and playfield priority is set
case PFBit | P1Bit | PriorityBit:
{
uInt32* mPF = &myCurrentPFMask[hpos];
uInt8* mP1 = &myCurrentP1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP1)
{
*(uInt32*)myFramePointer = (myPF & *mPF) ? myColorPtr[_PF] : myColorPtr[_BK];
mPF += 4; mP1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (myPF & *mPF) ? myColorPtr[_PF] :
((myCurrentGRP1 & *mP1) ? myColorPtr[_P1] : myColorPtr[_BK]);
if((myPF & *mPF) && (myCurrentGRP1 & *mP1))
myCollision |= TIATables::CollisionMask[PFBit | P1Bit];
++mPF; ++mP1; ++myFramePointer;
}
}
break;
}
// Playfield and Ball are enabled
case PFBit | BLBit:
case PFBit | BLBit | PriorityBit:
{
uInt32* mPF = &myCurrentPFMask[hpos];
uInt8* mBL = &myCurrentBLMask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL)
{
*(uInt32*)myFramePointer = (myPF & *mPF) ? myColorPtr[_PF] : myColorPtr[_BK];
mPF += 4; mBL += 4; myFramePointer += 4;
}
else
{
*myFramePointer = ((myPF & *mPF) || *mBL) ? myColorPtr[_PF] : myColorPtr[_BK];
if((myPF & *mPF) && *mBL)
myCollision |= TIATables::CollisionMask[PFBit | BLBit];
++mPF; ++mBL; ++myFramePointer;
}
}
break;
}
// Handle all of the other cases
default:
{
for(; myFramePointer < ending; ++myFramePointer, ++hpos)
{
uInt8 enabled = ((myEnabledObjects & PFBit) &&
(myPF & myCurrentPFMask[hpos])) ? PFBit : 0;
if((myEnabledObjects & BLBit) && myCurrentBLMask[hpos])
enabled |= BLBit;
if((myEnabledObjects & P1Bit) && (myCurrentGRP1 & myCurrentP1Mask[hpos]))
enabled |= P1Bit;
if((myEnabledObjects & M1Bit) && myCurrentM1Mask[hpos])
enabled |= M1Bit;
if((myEnabledObjects & P0Bit) && (myCurrentGRP0 & myCurrentP0Mask[hpos]))
enabled |= P0Bit;
if((myEnabledObjects & M0Bit) && myCurrentM0Mask[hpos])
enabled |= M0Bit;
myCollision |= TIATables::CollisionMask[enabled];
*myFramePointer = myColorPtr[myPriorityEncoder[hpos < 80 ? 0 : 1]
[enabled | myPlayfieldPriorityAndScore]];
}
break;
}
}
}
myFramePointer = ending;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIA::updateFrame(Int32 clock)
{
@ -1433,8 +834,6 @@ void TIA::updateFrame(Int32 clock)
if(clock > myClockStopDisplay)
clock = myClockStopDisplay;
//cerr << "updateFrame: " << clock << endl;
// Determine how many scanlines to process
// It's easier to think about this in scanlines rather than color clocks
uInt32 startLine = (myClockAtLastUpdate - myClockWhenFrameStarted) / 228;
@ -1531,13 +930,81 @@ void TIA::updateFrame(Int32 clock)
// Update as much of the scanline as we can
if(clocksToUpdate != 0)
{
// Selectively disable all bits we don't wish to draw
uInt8 oldEnabled = myEnabledObjects;
myEnabledObjects &= myDisabledObjects;
// Calculate the ending frame pointer value
uInt8* ending = myFramePointer + clocksToUpdate;
myFramePointerClocks += clocksToUpdate;
updateFrameScanline(clocksToUpdate, clocksFromStartOfScanLine - HBLANK);
// See if we're in the vertical blank region
if(myVBLANK & 0x02)
{
memset(myFramePointer, 0, clocksToUpdate);
}
// Handle all other possible combinations
else
{
// Update masks
myCurrentBLMask = &TIATables::BLMask[myPOSBL & 0x03]
[(myCTRLPF & 0x30) >> 4][160 - (myPOSBL & 0xFC)];
myCurrentP0Mask = &TIATables::PxMask[myPOSP0 & 0x03]
[mySuppressP0][myNUSIZ0 & 0x07][160 - (myPOSP0 & 0xFC)];
myCurrentP1Mask = &TIATables::PxMask[myPOSP1 & 0x03]
[mySuppressP1][myNUSIZ1 & 0x07][160 - (myPOSP1 & 0xFC)];
myEnabledObjects = oldEnabled;
// TODO - 08-27-2009: Simulate the weird effects of Cosmic Ark and
// Stay Frosty. The movement itself is well understood, but there
// also seems to be some widening and blanking occurring as well.
// This doesn't properly emulate the effect, but it does give a
// fair approximation. More testing is required to figure out
// what's really going on here.
if(myHMM0mmr && myPOSM0 % 4 == 3)
{
// 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][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 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][4][160 - (myPOSM1 & 0xFC)];
}
else
myCurrentM1Mask = &TIATables::MxMask[myPOSM1 & 0x03]
[myNUSIZ1 & 0x07][(myNUSIZ1 & 0x30) >> 4][160 - (myPOSM1 & 0xFC)];
uInt8 enabledObjects = myEnabledObjects & myDisabledObjects;
uInt32 hpos = clocksFromStartOfScanLine - HBLANK;
for(; myFramePointer < ending; ++myFramePointer, ++hpos)
{
uInt8 enabled = ((enabledObjects & PFBit) &&
(myPF & myCurrentPFMask[hpos])) ? PFBit : 0;
if((enabledObjects & BLBit) && myCurrentBLMask[hpos])
enabled |= BLBit;
if((enabledObjects & P1Bit) && (myCurrentGRP1 & myCurrentP1Mask[hpos]))
enabled |= P1Bit;
if((enabledObjects & M1Bit) && myCurrentM1Mask[hpos])
enabled |= M1Bit;
if((enabledObjects & P0Bit) && (myCurrentGRP0 & myCurrentP0Mask[hpos]))
enabled |= P0Bit;
if((enabledObjects & M0Bit) && myCurrentM0Mask[hpos])
enabled |= M0Bit;
myCollision |= TIATables::CollisionMask[enabled];
*myFramePointer = myColorPtr[myPriorityEncoder[hpos < 80 ? 0 : 1]
[enabled | myPlayfieldPriorityAndScore]];
}
}
myFramePointer = ending;
}
// Handle HMOVE blanks if they are enabled

View File

@ -295,9 +295,6 @@ class TIA : public Device
#endif
private:
// Update the current frame buffer up to one scanline
void updateFrameScanline(uInt32 clocksToUpdate, uInt32 hpos);
// Update the current frame buffer to the specified color clock
void updateFrame(Int32 clock);