#include <cassert>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <mutex>
#include "Console.hxx"
#include "Control.hxx"
#include "M6502.hxx"
#include "System.hxx"
#include "TIA.hxx"
#include "Serializer.hxx"
#include "Deserializer.hxx"
#include "Settings.hxx"
#include "Sound.hxx"
using namespace std;
#define HBLANK 68
static std::once_flag tia_init_once;
TIA::TIA(const Console& console, Settings& settings)
: myConsole(console),
mySettings(settings),
mySound(NULL),
myColorLossEnabled(false),
myMaximumNumberOfScanlines(262),
myCOLUBK(myColor[0]),
myCOLUPF(myColor[1]),
myCOLUP0(myColor[2]),
myCOLUP1(myColor[3])
{
uInt32 i;
myCurrentFrameBuffer = new uInt8[160 * 300];
myPreviousFrameBuffer = new uInt8[160 * 300];
myFrameGreyed = false;
myPartialFrameFlag = false;
for(i = 0; i < 6; ++i)
myBitEnabled[i] = true;
for(uInt16 x = 0; x < 2; ++x)
{
for(uInt16 enabled = 0; enabled < 256; ++enabled)
{
if(enabled & PriorityBit)
{
uInt8 color = 0;
if((enabled & (myP1Bit | myM1Bit)) != 0)
color = 3;
if((enabled & (myP0Bit | myM0Bit)) != 0)
color = 2;
if((enabled & myBLBit) != 0)
color = 1;
if((enabled & myPFBit) != 0)
color = 1;
myPriorityEncoder[x][enabled] = color;
}
else
{
uInt8 color = 0;
if((enabled & myBLBit) != 0)
color = 1;
if((enabled & myPFBit) != 0)
color = (enabled & ScoreBit) ? ((x == 0) ? 2 : 3) : 1;
if((enabled & (myP1Bit | myM1Bit)) != 0)
color = (color != 2) ? 3 : 2;
if((enabled & (myP0Bit | myM0Bit)) != 0)
color = 2;
myPriorityEncoder[x][enabled] = color;
}
}
}
std::call_once(tia_init_once, []() {
computeBallMaskTable();
computeCollisionTable();
computeMissleMaskTable();
computePlayerMaskTable();
computePlayerPositionResetWhenTable();
computePlayerReflectTable();
computePlayfieldMaskTable();
});
myFrameCounter = 0;
myAUDV0 = myAUDV1 = myAUDF0 = myAUDF1 = myAUDC0 = myAUDC1 = 0;
fastUpdate = settings.getBool("fast_tia_update", false);
}
TIA::~TIA()
{
delete[] myCurrentFrameBuffer;
delete[] myPreviousFrameBuffer;
}
const char* TIA::name() const
{
return "TIA";
}
void TIA::reset()
{
mySound->reset();
myEnabledObjects = 0;
myVSYNC = 0;
myVBLANK = 0;
myNUSIZ0 = 0;
myNUSIZ1 = 0;
myCOLUP0 = 0;
myCOLUP1 = 0;
myCOLUPF = 0;
myPlayfieldPriorityAndScore = 0;
myCOLUBK = 0;
myCTRLPF = 0;
myREFP0 = false;
myREFP1 = false;
myPF = 0;
myGRP0 = 0;
myGRP1 = 0;
myDGRP0 = 0;
myDGRP1 = 0;
myENAM0 = false;
myENAM1 = false;
myENABL = false;
myDENABL = false;
myHMP0 = 0;
myHMP1 = 0;
myHMM0 = 0;
myHMM1 = 0;
myHMBL = 0;
myVDELP0 = false;
myVDELP1 = false;
myVDELBL = false;
myRESMP0 = false;
myRESMP1 = false;
myCollision = 0;
myPOSP0 = 0;
myPOSP1 = 0;
myPOSM0 = 0;
myPOSM1 = 0;
myPOSBL = 0;
myCurrentGRP0 = 0;
myCurrentGRP1 = 0;
myCurrentBLMask = ourBallMaskTable[0][0];
myCurrentM0Mask = ourMissleMaskTable[0][0][0];
myCurrentM1Mask = ourMissleMaskTable[0][0][0];
myCurrentP0Mask = ourPlayerMaskTable[0][0][0];
myCurrentP1Mask = ourPlayerMaskTable[0][0][0];
myCurrentPFMask = ourPlayfieldTable[0];
myLastHMOVEClock = 0;
myHMOVEBlankEnabled = false;
myM0CosmicArkMotionEnabled = false;
myM0CosmicArkCounter = 0;
enableBits(true);
myDumpEnabled = false;
myDumpDisabledCycle = 0;
myAllowHMOVEBlanks =
(myConsole.properties().get(Emulation_HmoveBlanks) == "YES");
if(myConsole.getFormat().compare(0, 3, "PAL") == 0)
{
myColorLossEnabled = true;
myMaximumNumberOfScanlines = 342;
}
else {
myColorLossEnabled = false;
myMaximumNumberOfScanlines = 290;
}
frameReset();
}
void TIA::frameReset()
{
clearBuffers();
myFramePointer = myCurrentFrameBuffer;
myYStart = atoi(myConsole.properties().get(Display_YStart).c_str());
myHeight = atoi(myConsole.properties().get(Display_Height).c_str());
myStartDisplayOffset = 228 * myYStart;
myStopDisplayOffset = myStartDisplayOffset + 228 * myHeight;
myClockWhenFrameStarted = mySystem->cycles() * 3;
myClockStartDisplay = myClockWhenFrameStarted + myStartDisplayOffset;
myClockStopDisplay = myClockWhenFrameStarted + myStopDisplayOffset;
myClockAtLastUpdate = myClockWhenFrameStarted;
myClocksToEndOfScanLine = 228;
myVSYNCFinishClock = 0x7FFFFFFF;
myScanlineCountForLastFrame = 0;
myCurrentScanline = 0;
myFrameXStart = 0; myFrameWidth = 160; myFrameYStart = atoi(myConsole.properties().get(Display_YStart).c_str());
myFrameHeight = atoi(myConsole.properties().get(Display_Height).c_str());
if(myFrameHeight < 200)
{
myFrameHeight = 200;
}
}
void TIA::systemCyclesReset()
{
uInt32 cycles = mySystem->cycles();
mySound->adjustCycleCounter(-1 * cycles);
myDumpDisabledCycle -= cycles;
uInt32 clocks = cycles * 3;
myClockWhenFrameStarted -= clocks;
myClockStartDisplay -= clocks;
myClockStopDisplay -= clocks;
myClockAtLastUpdate -= clocks;
myVSYNCFinishClock -= clocks;
myLastHMOVEClock -= clocks;
}
void TIA::install(System& system)
{
mySystem = &system;
uInt16 shift = mySystem->pageShift();
mySystem->resetCycles();
System::PageAccess access;
access.directPeekBase = 0;
access.directPokeBase = 0;
access.device = this;
for(uInt32 i = 0; i < 8192; i += (1 << shift))
{
if((i & 0x1080) == 0x0000)
{
mySystem->setPageAccess(i >> shift, access);
}
}
}
bool TIA::save(Serializer& out)
{
string device = name();
try
{
out.putString(device);
out.putInt(myClockWhenFrameStarted);
out.putInt(myClockStartDisplay);
out.putInt(myClockStopDisplay);
out.putInt(myClockAtLastUpdate);
out.putInt(myClocksToEndOfScanLine);
out.putInt(myScanlineCountForLastFrame);
out.putInt(myCurrentScanline);
out.putInt(myVSYNCFinishClock);
out.putInt(myEnabledObjects);
out.putInt(myVSYNC);
out.putInt(myVBLANK);
out.putInt(myNUSIZ0);
out.putInt(myNUSIZ1);
out.putInt(myCOLUP0);
out.putInt(myCOLUP1);
out.putInt(myCOLUPF);
out.putInt(myCOLUBK);
out.putInt(myCTRLPF);
out.putInt(myPlayfieldPriorityAndScore);
out.putBool(myREFP0);
out.putBool(myREFP1);
out.putInt(myPF);
out.putInt(myGRP0);
out.putInt(myGRP1);
out.putInt(myDGRP0);
out.putInt(myDGRP1);
out.putBool(myENAM0);
out.putBool(myENAM1);
out.putBool(myENABL);
out.putBool(myDENABL);
out.putInt(myHMP0);
out.putInt(myHMP1);
out.putInt(myHMM0);
out.putInt(myHMM1);
out.putInt(myHMBL);
out.putBool(myVDELP0);
out.putBool(myVDELP1);
out.putBool(myVDELBL);
out.putBool(myRESMP0);
out.putBool(myRESMP1);
out.putInt(myCollision);
out.putInt(myPOSP0);
out.putInt(myPOSP1);
out.putInt(myPOSM0);
out.putInt(myPOSM1);
out.putInt(myPOSBL);
out.putInt(myCurrentGRP0);
out.putInt(myCurrentGRP1);
out.putInt(myLastHMOVEClock);
out.putBool(myHMOVEBlankEnabled);
out.putBool(myM0CosmicArkMotionEnabled);
out.putInt(myM0CosmicArkCounter);
out.putBool(myDumpEnabled);
out.putInt(myDumpDisabledCycle);
mySound->save(out);
}
catch(char *msg)
{
ale::Logger::Error << msg << endl;
return false;
}
catch(...)
{
ale::Logger::Error << "Unknown error in save state for " << device << endl;
return false;
}
return true;
}
bool TIA::load(Deserializer& in)
{
string device = name();
try
{
if(in.getString() != device)
return false;
myClockWhenFrameStarted = (Int32) in.getInt();
myClockStartDisplay = (Int32) in.getInt();
myClockStopDisplay = (Int32) in.getInt();
myClockAtLastUpdate = (Int32) in.getInt();
myClocksToEndOfScanLine = (Int32) in.getInt();
myScanlineCountForLastFrame = (Int32) in.getInt();
myCurrentScanline = (Int32) in.getInt();
myVSYNCFinishClock = (Int32) in.getInt();
myEnabledObjects = (uInt8) in.getInt();
myVSYNC = (uInt8) in.getInt();
myVBLANK = (uInt8) in.getInt();
myNUSIZ0 = (uInt8) in.getInt();
myNUSIZ1 = (uInt8) in.getInt();
myCOLUP0 = (uInt32) in.getInt();
myCOLUP1 = (uInt32) in.getInt();
myCOLUPF = (uInt32) in.getInt();
myCOLUBK = (uInt32) in.getInt();
myCTRLPF = (uInt8) in.getInt();
myPlayfieldPriorityAndScore = (uInt8) in.getInt();
myREFP0 = in.getBool();
myREFP1 = in.getBool();
myPF = (uInt32) in.getInt();
myGRP0 = (uInt8) in.getInt();
myGRP1 = (uInt8) in.getInt();
myDGRP0 = (uInt8) in.getInt();
myDGRP1 = (uInt8) in.getInt();
myENAM0 = in.getBool();
myENAM1 = in.getBool();
myENABL = in.getBool();
myDENABL = in.getBool();
myHMP0 = (Int8) in.getInt();
myHMP1 = (Int8) in.getInt();
myHMM0 = (Int8) in.getInt();
myHMM1 = (Int8) in.getInt();
myHMBL = (Int8) in.getInt();
myVDELP0 = in.getBool();
myVDELP1 = in.getBool();
myVDELBL = in.getBool();
myRESMP0 = in.getBool();
myRESMP1 = in.getBool();
myCollision = (uInt16) in.getInt();
myPOSP0 = (Int16) in.getInt();
myPOSP1 = (Int16) in.getInt();
myPOSM0 = (Int16) in.getInt();
myPOSM1 = (Int16) in.getInt();
myPOSBL = (Int16) in.getInt();
myCurrentGRP0 = (uInt8) in.getInt();
myCurrentGRP1 = (uInt8) in.getInt();
myLastHMOVEClock = (Int32) in.getInt();
myHMOVEBlankEnabled = in.getBool();
myM0CosmicArkMotionEnabled = in.getBool();
myM0CosmicArkCounter = (uInt32) in.getInt();
myDumpEnabled = in.getBool();
myDumpDisabledCycle = (Int32) in.getInt();
mySound->load(in);
enableBits(true);
}
catch(char *msg)
{
ale::Logger::Error << msg << endl;
return false;
}
catch(...)
{
ale::Logger::Error << "Unknown error in load state for " << device << endl;
return false;
}
return true;
}
void TIA::update()
{
if(!myPartialFrameFlag)
startFrame();
myPartialFrameFlag = true;
mySystem->m6502().execute(25000);
uInt32 totalClocks = (mySystem->cycles() * 3) - myClockWhenFrameStarted;
myCurrentScanline = totalClocks / 228;
if(myPartialFrameFlag) {
if(!myFrameGreyed) greyOutFrame();
myFrameGreyed = true;
} else {
endFrame();
}
}
inline void TIA::startFrame()
{
uInt8* tmp = myCurrentFrameBuffer;
myCurrentFrameBuffer = myPreviousFrameBuffer;
myPreviousFrameBuffer = tmp;
uInt32 clocks = ((mySystem->cycles() * 3) - myClockWhenFrameStarted) % 228;
mySystem->resetCycles();
myClockWhenFrameStarted = -1 * clocks;
myClockStartDisplay = myClockWhenFrameStarted + myStartDisplayOffset;
myClockStopDisplay = myClockWhenFrameStarted + myStopDisplayOffset;
myClockAtLastUpdate = myClockStartDisplay;
myClocksToEndOfScanLine = 228;
myFramePointer = myCurrentFrameBuffer;
if(myColorLossEnabled)
{
if(myScanlineCountForLastFrame & 0x01)
{
myCOLUP0 |= 0x01010101;
myCOLUP1 |= 0x01010101;
myCOLUPF |= 0x01010101;
myCOLUBK |= 0x01010101;
}
else
{
myCOLUP0 &= 0xfefefefe;
myCOLUP1 &= 0xfefefefe;
myCOLUPF &= 0xfefefefe;
myCOLUBK &= 0xfefefefe;
}
}
myFrameGreyed = false;
}
inline void TIA::endFrame()
{
myScanlineCountForLastFrame = myCurrentScanline;
myFrameCounter++;
myFrameGreyed = false;
}
#ifdef DEBUGGER_SUPPORT
void TIA::updateScanline()
{
if(!myPartialFrameFlag) {
startFrame();
}
if(!myFrameGreyed) greyOutFrame();
myFrameGreyed = true;
myPartialFrameFlag = true;
int totalClocks = (mySystem->cycles() * 3) - myClockWhenFrameStarted;
int endClock = ((totalClocks + 228) / 228) * 228;
int clock;
do {
mySystem->m6502().execute(1);
clock = mySystem->cycles() * 3;
updateFrame(clock);
} while(clock < endClock);
totalClocks = (mySystem->cycles() * 3) - myClockWhenFrameStarted;
myCurrentScanline = totalClocks / 228;
if(!myPartialFrameFlag)
endFrame();
}
void TIA::updateScanlineByStep()
{
if(!myPartialFrameFlag) {
startFrame();
}
if(!myFrameGreyed) greyOutFrame();
myFrameGreyed = true;
myPartialFrameFlag = true;
int totalClocks = (mySystem->cycles() * 3) - myClockWhenFrameStarted;
mySystem->m6502().execute(1);
updateFrame(mySystem->cycles() * 3);
totalClocks = (mySystem->cycles() * 3) - myClockWhenFrameStarted;
myCurrentScanline = totalClocks / 228;
if(!myPartialFrameFlag)
endFrame();
}
void TIA::updateScanlineByTrace(int target)
{
if(!myPartialFrameFlag) {
startFrame();
}
if(!myFrameGreyed) greyOutFrame();
myFrameGreyed = true;
myPartialFrameFlag = true;
int totalClocks = (mySystem->cycles() * 3) - myClockWhenFrameStarted;
while(mySystem->m6502().getPC() != target)
{
mySystem->m6502().execute(1);
updateFrame(mySystem->cycles() * 3);
}
totalClocks = (mySystem->cycles() * 3) - myClockWhenFrameStarted;
myCurrentScanline = totalClocks / 228;
if(!myPartialFrameFlag)
endFrame();
}
#endif
uInt32 TIA::width() const
{
return myFrameWidth;
}
uInt32 TIA::height() const
{
return myFrameHeight;
}
uInt32 TIA::scanlines() const
{
uInt32 totalClocks = (mySystem->cycles() * 3) - myClockWhenFrameStarted;
return totalClocks/228;
}
uInt32 TIA::clocksThisLine() const
{
uInt32 totalClocks = (mySystem->cycles() * 3) - myClockWhenFrameStarted;
return totalClocks%228;
}
void TIA::setSound(Sound& sound)
{
mySound = &sound;
}
void TIA::computeBallMaskTable()
{
for(Int32 size = 0; size < 4; ++size)
{
Int32 x;
for(x = 0; x < 160; ++x)
{
ourBallMaskTable[0][size][x] = false;
}
for(x = 0; x < 160 + 8; ++x)
{
if((x >= 0) && (x < (1 << size)))
{
ourBallMaskTable[0][size][x % 160] = true;
}
}
for(x = 0; x < 160; ++x)
{
ourBallMaskTable[0][size][x + 160] = ourBallMaskTable[0][size][x];
}
}
for(uInt32 align = 1; align < 4; ++align)
{
for(uInt32 size = 0; size < 4; ++size)
{
for(uInt32 x = 0; x < 320; ++x)
{
ourBallMaskTable[align][size][x] =
ourBallMaskTable[0][size][(x + 320 - align) % 320];
}
}
}
}
void TIA::computeCollisionTable()
{
for(uInt8 i = 0; i < 64; ++i)
{
ourCollisionTable[i] = 0;
if((i & myM0Bit) && (i & myP1Bit)) ourCollisionTable[i] |= 0x0001;
if((i & myM0Bit) && (i & myP0Bit)) ourCollisionTable[i] |= 0x0002;
if((i & myM1Bit) && (i & myP0Bit)) ourCollisionTable[i] |= 0x0004;
if((i & myM1Bit) && (i & myP1Bit)) ourCollisionTable[i] |= 0x0008;
if((i & myP0Bit) && (i & myPFBit)) ourCollisionTable[i] |= 0x0010;
if((i & myP0Bit) && (i & myBLBit)) ourCollisionTable[i] |= 0x0020;
if((i & myP1Bit) && (i & myPFBit)) ourCollisionTable[i] |= 0x0040;
if((i & myP1Bit) && (i & myBLBit)) ourCollisionTable[i] |= 0x0080;
if((i & myM0Bit) && (i & myPFBit)) ourCollisionTable[i] |= 0x0100;
if((i & myM0Bit) && (i & myBLBit)) ourCollisionTable[i] |= 0x0200;
if((i & myM1Bit) && (i & myPFBit)) ourCollisionTable[i] |= 0x0400;
if((i & myM1Bit) && (i & myBLBit)) ourCollisionTable[i] |= 0x0800;
if((i & myBLBit) && (i & myPFBit)) ourCollisionTable[i] |= 0x1000;
if((i & myP0Bit) && (i & myP1Bit)) ourCollisionTable[i] |= 0x2000;
if((i & myM0Bit) && (i & myM1Bit)) ourCollisionTable[i] |= 0x4000;
}
}
void TIA::computeMissleMaskTable()
{
Int32 x, size, number;
for(number = 0; number < 8; ++number)
for(size = 0; size < 4; ++size)
for(x = 0; x < 160; ++x)
ourMissleMaskTable[0][number][size][x] = false;
for(number = 0; number < 8; ++number)
{
for(size = 0; size < 4; ++size)
{
for(x = 0; x < 160 + 72; ++x)
{
if((number == 0x00) || (number == 0x05) || (number == 0x07))
{
if((x >= 0) && (x < (1 << size)))
ourMissleMaskTable[0][number][size][x % 160] = true;
}
else if(number == 0x01)
{
if((x >= 0) && (x < (1 << size)))
ourMissleMaskTable[0][number][size][x % 160] = true;
else if(((x - 16) >= 0) && ((x - 16) < (1 << size)))
ourMissleMaskTable[0][number][size][x % 160] = true;
}
else if(number == 0x02)
{
if((x >= 0) && (x < (1 << size)))
ourMissleMaskTable[0][number][size][x % 160] = true;
else if(((x - 32) >= 0) && ((x - 32) < (1 << size)))
ourMissleMaskTable[0][number][size][x % 160] = true;
}
else if(number == 0x03)
{
if((x >= 0) && (x < (1 << size)))
ourMissleMaskTable[0][number][size][x % 160] = true;
else if(((x - 16) >= 0) && ((x - 16) < (1 << size)))
ourMissleMaskTable[0][number][size][x % 160] = true;
else if(((x - 32) >= 0) && ((x - 32) < (1 << size)))
ourMissleMaskTable[0][number][size][x % 160] = true;
}
else if(number == 0x04)
{
if((x >= 0) && (x < (1 << size)))
ourMissleMaskTable[0][number][size][x % 160] = true;
else if(((x - 64) >= 0) && ((x - 64) < (1 << size)))
ourMissleMaskTable[0][number][size][x % 160] = true;
}
else if(number == 0x06)
{
if((x >= 0) && (x < (1 << size)))
ourMissleMaskTable[0][number][size][x % 160] = true;
else if(((x - 32) >= 0) && ((x - 32) < (1 << size)))
ourMissleMaskTable[0][number][size][x % 160] = true;
else if(((x - 64) >= 0) && ((x - 64) < (1 << size)))
ourMissleMaskTable[0][number][size][x % 160] = true;
}
}
for(x = 0; x < 160; ++x)
ourMissleMaskTable[0][number][size][x + 160] =
ourMissleMaskTable[0][number][size][x];
}
}
for(uInt32 align = 1; align < 4; ++align)
{
for(number = 0; number < 8; ++number)
{
for(size = 0; size < 4; ++size)
{
for(x = 0; x < 320; ++x)
{
ourMissleMaskTable[align][number][size][x] =
ourMissleMaskTable[0][number][size][(x + 320 - align) % 320];
}
}
}
}
}
void TIA::computePlayerMaskTable()
{
Int32 x, enable, mode;
for(enable = 0; enable < 2; ++enable)
for(mode = 0; mode < 8; ++mode)
for(x = 0; x < 160; ++x)
ourPlayerMaskTable[0][enable][mode][x] = 0x00;
for(enable = 0; enable < 2; ++enable)
{
for(mode = 0; mode < 8; ++mode)
{
for(x = 0; x < 160 + 72; ++x)
{
if(mode == 0x00)
{
if((enable == 0) && (x >= 0) && (x < 8))
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> x;
}
else if(mode == 0x01)
{
if((enable == 0) && (x >= 0) && (x < 8))
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> x;
else if(((x - 16) >= 0) && ((x - 16) < 8))
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 16);
}
else if(mode == 0x02)
{
if((enable == 0) && (x >= 0) && (x < 8))
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> x;
else if(((x - 32) >= 0) && ((x - 32) < 8))
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 32);
}
else if(mode == 0x03)
{
if((enable == 0) && (x >= 0) && (x < 8))
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> x;
else if(((x - 16) >= 0) && ((x - 16) < 8))
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 16);
else if(((x - 32) >= 0) && ((x - 32) < 8))
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 32);
}
else if(mode == 0x04)
{
if((enable == 0) && (x >= 0) && (x < 8))
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> x;
else if(((x - 64) >= 0) && ((x - 64) < 8))
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 64);
}
else if(mode == 0x05)
{
if((enable == 0) && (x > 0) && (x <= 16))
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> ((x - 1)/2);
}
else if(mode == 0x06)
{
if((enable == 0) && (x >= 0) && (x < 8))
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> x;
else if(((x - 32) >= 0) && ((x - 32) < 8))
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 32);
else if(((x - 64) >= 0) && ((x - 64) < 8))
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 64);
}
else if(mode == 0x07)
{
if((enable == 0) && (x > 0) && (x <= 32))
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> ((x - 1)/4);
}
}
for(x = 0; x < 160; ++x)
{
ourPlayerMaskTable[0][enable][mode][x + 160] =
ourPlayerMaskTable[0][enable][mode][x];
}
}
}
for(uInt32 align = 1; align < 4; ++align)
{
for(enable = 0; enable < 2; ++enable)
{
for(mode = 0; mode < 8; ++mode)
{
for(x = 0; x < 320; ++x)
{
ourPlayerMaskTable[align][enable][mode][x] =
ourPlayerMaskTable[0][enable][mode][(x + 320 - align) % 320];
}
}
}
}
}
void TIA::computePlayerPositionResetWhenTable()
{
uInt32 mode, oldx, newx;
for(mode = 0; mode < 8; ++mode)
{
for(oldx = 0; oldx < 160; ++oldx)
{
for(newx = 0; newx < 160; ++newx)
{
ourPlayerPositionResetWhenTable[mode][oldx][newx] = 0;
}
for(newx = 0; newx < 160 + 72 + 5; ++newx)
{
if(mode == 0x00)
{
if((newx >= oldx) && (newx < (oldx + 4)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
}
else if(mode == 0x01)
{
if((newx >= oldx) && (newx < (oldx + 4)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
else if((newx >= (oldx + 16)) && (newx < (oldx + 16 + 4)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
else if((newx >= oldx + 16 + 4) && (newx < (oldx + 16 + 4 + 8)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
}
else if(mode == 0x02)
{
if((newx >= oldx) && (newx < (oldx + 4)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
else if((newx >= oldx + 32 + 4) && (newx < (oldx + 32 + 4 + 8)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
}
else if(mode == 0x03)
{
if((newx >= oldx) && (newx < (oldx + 4)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
else if((newx >= (oldx + 16)) && (newx < (oldx + 16 + 4)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
else if((newx >= oldx + 16 + 4) && (newx < (oldx + 16 + 4 + 8)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
else if((newx >= oldx + 32 + 4) && (newx < (oldx + 32 + 4 + 8)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
}
else if(mode == 0x04)
{
if((newx >= oldx) && (newx < (oldx + 4)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
else if((newx >= (oldx + 64)) && (newx < (oldx + 64 + 4)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
else if((newx >= oldx + 64 + 4) && (newx < (oldx + 64 + 4 + 8)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
}
else if(mode == 0x05)
{
if((newx >= oldx) && (newx < (oldx + 4)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
if((newx >= oldx + 4) && (newx < (oldx + 4 + 16)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
}
else if(mode == 0x06)
{
if((newx >= oldx) && (newx < (oldx + 4)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
else if((newx >= (oldx + 64)) && (newx < (oldx + 64 + 4)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
else if((newx >= oldx + 32 + 4) && (newx < (oldx + 32 + 4 + 8)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
else if((newx >= oldx + 64 + 4) && (newx < (oldx + 64 + 4 + 8)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
}
else if(mode == 0x07)
{
if((newx >= oldx) && (newx < (oldx + 4)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
if((newx >= oldx + 4) && (newx < (oldx + 4 + 32)))
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
}
}
uInt32 s1 = 0, s2 = 0;
for(newx = 0; newx < 160; ++newx)
{
if(ourPlayerPositionResetWhenTable[mode][oldx][newx] == -1)
++s1;
if(ourPlayerPositionResetWhenTable[mode][oldx][newx] == 1)
++s2;
}
assert((s1 % 4 == 0) && (s2 % 8 == 0));
}
}
}
void TIA::computePlayerReflectTable()
{
for(uInt16 i = 0; i < 256; ++i)
{
uInt8 r = 0;
for(uInt16 t = 1; t <= 128; t *= 2)
{
r = (r << 1) | ((i & t) ? 0x01 : 0x00);
}
ourPlayerReflectTable[i] = r;
}
}
void TIA::computePlayfieldMaskTable()
{
Int32 x;
for(x = 0; x < 160; ++x)
{
if(x < 16)
ourPlayfieldTable[0][x] = 0x00001 << (x / 4);
else if(x < 48)
ourPlayfieldTable[0][x] = 0x00800 >> ((x - 16) / 4);
else if(x < 80)
ourPlayfieldTable[0][x] = 0x01000 << ((x - 48) / 4);
else if(x < 96)
ourPlayfieldTable[0][x] = 0x00001 << ((x - 80) / 4);
else if(x < 128)
ourPlayfieldTable[0][x] = 0x00800 >> ((x - 96) / 4);
else if(x < 160)
ourPlayfieldTable[0][x] = 0x01000 << ((x - 128) / 4);
}
for(x = 0; x < 160; ++x)
{
if(x < 16)
ourPlayfieldTable[1][x] = 0x00001 << (x / 4);
else if(x < 48)
ourPlayfieldTable[1][x] = 0x00800 >> ((x - 16) / 4);
else if(x < 80)
ourPlayfieldTable[1][x] = 0x01000 << ((x - 48) / 4);
else if(x < 112)
ourPlayfieldTable[1][x] = 0x80000 >> ((x - 80) / 4);
else if(x < 144)
ourPlayfieldTable[1][x] = 0x00010 << ((x - 112) / 4);
else if(x < 160)
ourPlayfieldTable[1][x] = 0x00008 >> ((x - 144) / 4);
}
}
inline void TIA::updateFrameScanline(uInt32 clocksToUpdate, uInt32 hpos)
{
uInt8* ending = myFramePointer + clocksToUpdate;
if(myVBLANK & 0x02)
{
memset(myFramePointer, 0, clocksToUpdate);
}
else
{
switch(myEnabledObjects | myPlayfieldPriorityAndScore)
{
case 0x00:
case 0x00 | ScoreBit:
case 0x00 | PriorityBit:
case 0x00 | PriorityBit | ScoreBit:
{
memset(myFramePointer, myCOLUBK, clocksToUpdate);
break;
}
case myPFBit:
case myPFBit | PriorityBit:
{
const uInt32* mask = &myCurrentPFMask[hpos];
for(; ((uintptr_t)myFramePointer & 0x03) && (myFramePointer < ending);
++myFramePointer, ++mask)
{
*myFramePointer = (myPF & *mask) ? myCOLUPF : myCOLUBK;
}
for(; myFramePointer < ending; myFramePointer += 4, mask += 4)
{
*((uInt32*)myFramePointer) = (myPF & *mask) ? myCOLUPF : myCOLUBK;
}
break;
}
case myPFBit | ScoreBit:
case myPFBit | ScoreBit | PriorityBit:
{
const uInt32* mask = &myCurrentPFMask[hpos];
for(; ((uintptr_t)myFramePointer & 0x03) && (myFramePointer < ending);
++myFramePointer, ++mask, ++hpos)
{
*myFramePointer = (myPF & *mask) ?
(hpos < 80 ? myCOLUP0 : myCOLUP1) : myCOLUBK;
}
for(; myFramePointer < ending;
myFramePointer += 4, mask += 4, hpos += 4)
{
*((uInt32*)myFramePointer) = (myPF & *mask) ?
(hpos < 80 ? myCOLUP0 : myCOLUP1) : myCOLUBK;
}
break;
}
case myP0Bit:
case myP0Bit | ScoreBit:
case myP0Bit | PriorityBit:
case myP0Bit | ScoreBit | PriorityBit:
{
const uInt8* mP0 = &myCurrentP0Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP0)
{
*(uInt32*)myFramePointer = myCOLUBK;
mP0 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (myCurrentGRP0 & *mP0) ? myCOLUP0 : myCOLUBK;
++mP0; ++myFramePointer;
}
}
break;
}
case myP1Bit:
case myP1Bit | ScoreBit:
case myP1Bit | PriorityBit:
case myP1Bit | ScoreBit | PriorityBit:
{
const uInt8* mP1 = &myCurrentP1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP1)
{
*(uInt32*)myFramePointer = myCOLUBK;
mP1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (myCurrentGRP1 & *mP1) ? myCOLUP1 : myCOLUBK;
++mP1; ++myFramePointer;
}
}
break;
}
case myP0Bit | myP1Bit:
case myP0Bit | myP1Bit | ScoreBit:
case myP0Bit | myP1Bit | PriorityBit:
case myP0Bit | myP1Bit | ScoreBit | PriorityBit:
{
const uInt8* mP0 = &myCurrentP0Mask[hpos];
const uInt8* mP1 = &myCurrentP1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP0 &&
!*(uInt32*)mP1)
{
*(uInt32*)myFramePointer = myCOLUBK;
mP0 += 4; mP1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (myCurrentGRP0 & *mP0) ?
myCOLUP0 : ((myCurrentGRP1 & *mP1) ? myCOLUP1 : myCOLUBK);
if((myCurrentGRP0 & *mP0) && (myCurrentGRP1 & *mP1))
myCollision |= ourCollisionTable[myP0Bit | myP1Bit];
++mP0; ++mP1; ++myFramePointer;
}
}
break;
}
case myM0Bit:
case myM0Bit | ScoreBit:
case myM0Bit | PriorityBit:
case myM0Bit | ScoreBit | PriorityBit:
{
const uInt8* mM0 = &myCurrentM0Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mM0)
{
*(uInt32*)myFramePointer = myCOLUBK;
mM0 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = *mM0 ? myCOLUP0 : myCOLUBK;
++mM0; ++myFramePointer;
}
}
break;
}
case myM1Bit:
case myM1Bit | ScoreBit:
case myM1Bit | PriorityBit:
case myM1Bit | ScoreBit | PriorityBit:
{
const uInt8* mM1 = &myCurrentM1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mM1)
{
*(uInt32*)myFramePointer = myCOLUBK;
mM1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = *mM1 ? myCOLUP1 : myCOLUBK;
++mM1; ++myFramePointer;
}
}
break;
}
case myBLBit:
case myBLBit | ScoreBit:
case myBLBit | PriorityBit:
case myBLBit | ScoreBit | PriorityBit:
{
const uInt8* mBL = &myCurrentBLMask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL)
{
*(uInt32*)myFramePointer = myCOLUBK;
mBL += 4; myFramePointer += 4;
}
else
{
*myFramePointer = *mBL ? myCOLUPF : myCOLUBK;
++mBL; ++myFramePointer;
}
}
break;
}
case myM0Bit | myM1Bit:
case myM0Bit | myM1Bit | ScoreBit:
case myM0Bit | myM1Bit | PriorityBit:
case myM0Bit | myM1Bit | ScoreBit | PriorityBit:
{
const uInt8* mM0 = &myCurrentM0Mask[hpos];
const uInt8* mM1 = &myCurrentM1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mM0 && !*(uInt32*)mM1)
{
*(uInt32*)myFramePointer = myCOLUBK;
mM0 += 4; mM1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = *mM0 ? myCOLUP0 : (*mM1 ? myCOLUP1 : myCOLUBK);
if(*mM0 && *mM1)
myCollision |= ourCollisionTable[myM0Bit | myM1Bit];
++mM0; ++mM1; ++myFramePointer;
}
}
break;
}
case myBLBit | myM0Bit:
case myBLBit | myM0Bit | ScoreBit:
{
const uInt8* mBL = &myCurrentBLMask[hpos];
const uInt8* mM0 = &myCurrentM0Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL && !*(uInt32*)mM0)
{
*(uInt32*)myFramePointer = myCOLUBK;
mBL += 4; mM0 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (*mM0 ? myCOLUP0 : (*mBL ? myCOLUPF : myCOLUBK));
if(*mBL && *mM0)
myCollision |= ourCollisionTable[myBLBit | myM0Bit];
++mBL; ++mM0; ++myFramePointer;
}
}
break;
}
case myBLBit | myM0Bit | PriorityBit:
case myBLBit | myM0Bit | ScoreBit | PriorityBit:
{
const uInt8* mBL = &myCurrentBLMask[hpos];
const uInt8* mM0 = &myCurrentM0Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL && !*(uInt32*)mM0)
{
*(uInt32*)myFramePointer = myCOLUBK;
mBL += 4; mM0 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (*mBL ? myCOLUPF : (*mM0 ? myCOLUP0 : myCOLUBK));
if(*mBL && *mM0)
myCollision |= ourCollisionTable[myBLBit | myM0Bit];
++mBL; ++mM0; ++myFramePointer;
}
}
break;
}
case myBLBit | myM1Bit:
case myBLBit | myM1Bit | ScoreBit:
{
const uInt8* mBL = &myCurrentBLMask[hpos];
const uInt8* mM1 = &myCurrentM1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL &&
!*(uInt32*)mM1)
{
*(uInt32*)myFramePointer = myCOLUBK;
mBL += 4; mM1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (*mM1 ? myCOLUP1 : (*mBL ? myCOLUPF : myCOLUBK));
if(*mBL && *mM1)
myCollision |= ourCollisionTable[myBLBit | myM1Bit];
++mBL; ++mM1; ++myFramePointer;
}
}
break;
}
case myBLBit | myM1Bit | PriorityBit:
case myBLBit | myM1Bit | ScoreBit | PriorityBit:
{
const uInt8* mBL = &myCurrentBLMask[hpos];
const uInt8* mM1 = &myCurrentM1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL &&
!*(uInt32*)mM1)
{
*(uInt32*)myFramePointer = myCOLUBK;
mBL += 4; mM1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (*mBL ? myCOLUPF : (*mM1 ? myCOLUP1 : myCOLUBK));
if(*mBL && *mM1)
myCollision |= ourCollisionTable[myBLBit | myM1Bit];
++mBL; ++mM1; ++myFramePointer;
}
}
break;
}
case myBLBit | myP1Bit:
case myBLBit | myP1Bit | ScoreBit:
{
const uInt8* mBL = &myCurrentBLMask[hpos];
const uInt8* mP1 = &myCurrentP1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP1 && !*(uInt32*)mBL)
{
*(uInt32*)myFramePointer = myCOLUBK;
mBL += 4; mP1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (myCurrentGRP1 & *mP1) ? myCOLUP1 :
(*mBL ? myCOLUPF : myCOLUBK);
if(*mBL && (myCurrentGRP1 & *mP1))
myCollision |= ourCollisionTable[myBLBit | myP1Bit];
++mBL; ++mP1; ++myFramePointer;
}
}
break;
}
case myBLBit | myP1Bit | PriorityBit:
case myBLBit | myP1Bit | PriorityBit | ScoreBit:
{
const uInt8* mBL = &myCurrentBLMask[hpos];
const uInt8* mP1 = &myCurrentP1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP1 && !*(uInt32*)mBL)
{
*(uInt32*)myFramePointer = myCOLUBK;
mBL += 4; mP1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = *mBL ? myCOLUPF :
((myCurrentGRP1 & *mP1) ? myCOLUP1 : myCOLUBK);
if(*mBL && (myCurrentGRP1 & *mP1))
myCollision |= ourCollisionTable[myBLBit | myP1Bit];
++mBL; ++mP1; ++myFramePointer;
}
}
break;
}
case myPFBit | myP0Bit:
{
const uInt32* mPF = &myCurrentPFMask[hpos];
const uInt8* mP0 = &myCurrentP0Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP0)
{
*(uInt32*)myFramePointer = (myPF & *mPF) ? myCOLUPF : myCOLUBK;
mPF += 4; mP0 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (myCurrentGRP0 & *mP0) ?
myCOLUP0 : ((myPF & *mPF) ? myCOLUPF : myCOLUBK);
if((myPF & *mPF) && (myCurrentGRP0 & *mP0))
myCollision |= ourCollisionTable[myPFBit | myP0Bit];
++mPF; ++mP0; ++myFramePointer;
}
}
break;
}
case myPFBit | myP0Bit | PriorityBit:
{
const uInt32* mPF = &myCurrentPFMask[hpos];
const uInt8* mP0 = &myCurrentP0Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP0)
{
*(uInt32*)myFramePointer = (myPF & *mPF) ? myCOLUPF : myCOLUBK;
mPF += 4; mP0 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (myPF & *mPF) ? myCOLUPF :
((myCurrentGRP0 & *mP0) ? myCOLUP0 : myCOLUBK);
if((myPF & *mPF) && (myCurrentGRP0 & *mP0))
myCollision |= ourCollisionTable[myPFBit | myP0Bit];
++mPF; ++mP0; ++myFramePointer;
}
}
break;
}
case myPFBit | myP1Bit:
{
const uInt32* mPF = &myCurrentPFMask[hpos];
const uInt8* mP1 = &myCurrentP1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP1)
{
*(uInt32*)myFramePointer = (myPF & *mPF) ? myCOLUPF : myCOLUBK;
mPF += 4; mP1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (myCurrentGRP1 & *mP1) ?
myCOLUP1 : ((myPF & *mPF) ? myCOLUPF : myCOLUBK);
if((myPF & *mPF) && (myCurrentGRP1 & *mP1))
myCollision |= ourCollisionTable[myPFBit | myP1Bit];
++mPF; ++mP1; ++myFramePointer;
}
}
break;
}
case myPFBit | myP1Bit | PriorityBit:
{
const uInt32* mPF = &myCurrentPFMask[hpos];
const uInt8* mP1 = &myCurrentP1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP1)
{
*(uInt32*)myFramePointer = (myPF & *mPF) ? myCOLUPF : myCOLUBK;
mPF += 4; mP1 += 4; myFramePointer += 4;
}
else
{
*myFramePointer = (myPF & *mPF) ? myCOLUPF :
((myCurrentGRP1 & *mP1) ? myCOLUP1 : myCOLUBK);
if((myPF & *mPF) && (myCurrentGRP1 & *mP1))
myCollision |= ourCollisionTable[myPFBit | myP1Bit];
++mPF; ++mP1; ++myFramePointer;
}
}
break;
}
case myPFBit | myBLBit:
case myPFBit | myBLBit | PriorityBit:
{
const uInt32* mPF = &myCurrentPFMask[hpos];
const uInt8* mBL = &myCurrentBLMask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL)
{
*(uInt32*)myFramePointer = (myPF & *mPF) ? myCOLUPF : myCOLUBK;
mPF += 4; mBL += 4; myFramePointer += 4;
}
else
{
*myFramePointer = ((myPF & *mPF) || *mBL) ? myCOLUPF : myCOLUBK;
if((myPF & *mPF) && *mBL)
myCollision |= ourCollisionTable[myPFBit | myBLBit];
++mPF; ++mBL; ++myFramePointer;
}
}
break;
}
default:
{
for(; myFramePointer < ending; ++myFramePointer, ++hpos)
{
uInt8 enabled = (myPF & myCurrentPFMask[hpos]) ? myPFBit : 0;
if((myEnabledObjects & myBLBit) && myCurrentBLMask[hpos])
enabled |= myBLBit;
if(myCurrentGRP1 & myCurrentP1Mask[hpos])
enabled |= myP1Bit;
if((myEnabledObjects & myM1Bit) && myCurrentM1Mask[hpos])
enabled |= myM1Bit;
if(myCurrentGRP0 & myCurrentP0Mask[hpos])
enabled |= myP0Bit;
if((myEnabledObjects & myM0Bit) && myCurrentM0Mask[hpos])
enabled |= myM0Bit;
myCollision |= ourCollisionTable[enabled];
*myFramePointer = myColor[myPriorityEncoder[hpos < 80 ? 0 : 1]
[enabled | myPlayfieldPriorityAndScore]];
}
break;
}
}
}
myFramePointer = ending;
}
inline void TIA::updateFrame(Int32 clock)
{
if((clock < myClockStartDisplay) ||
(myClockAtLastUpdate >= myClockStopDisplay) ||
(myClockAtLastUpdate >= clock))
{
return;
}
if(clock > myClockStopDisplay)
{
clock = myClockStopDisplay;
}
do
{
Int32 clocksToUpdate = 0;
Int32 clocksFromStartOfScanLine = 228 - myClocksToEndOfScanLine;
if(clock > (myClockAtLastUpdate + myClocksToEndOfScanLine))
{
clocksToUpdate = myClocksToEndOfScanLine;
myClocksToEndOfScanLine = 228;
myClockAtLastUpdate += clocksToUpdate;
}
else
{
clocksToUpdate = clock - myClockAtLastUpdate;
myClocksToEndOfScanLine -= clocksToUpdate;
myClockAtLastUpdate = clock;
}
Int32 startOfScanLine = HBLANK + myFrameXStart;
if(clocksFromStartOfScanLine < startOfScanLine)
{
uInt32 tmp;
if((startOfScanLine - clocksFromStartOfScanLine) < clocksToUpdate)
tmp = startOfScanLine - clocksFromStartOfScanLine;
else
tmp = clocksToUpdate;
clocksFromStartOfScanLine += tmp;
clocksToUpdate -= tmp;
}
uInt8* oldFramePointer = myFramePointer;
if(clocksToUpdate != 0)
{
if (fastUpdate)
updateFrameScanlineFast(clocksToUpdate,
clocksFromStartOfScanLine - HBLANK);
else
updateFrameScanline(clocksToUpdate, clocksFromStartOfScanLine - HBLANK);
}
if(myHMOVEBlankEnabled && (startOfScanLine < HBLANK + 8) &&
(clocksFromStartOfScanLine < (HBLANK + 8)))
{
Int32 blanks = (HBLANK + 8) - clocksFromStartOfScanLine;
memset(oldFramePointer, 0, blanks);
if((clocksToUpdate + clocksFromStartOfScanLine) >= (HBLANK + 8))
{
myHMOVEBlankEnabled = false;
}
}
if(myClocksToEndOfScanLine == 228)
{
myFramePointer -= (160 - myFrameWidth - myFrameXStart);
myCurrentPFMask = ourPlayfieldTable[myCTRLPF & 0x01];
myCurrentP0Mask = &ourPlayerMaskTable[myPOSP0 & 0x03]
[0][myNUSIZ0 & 0x07][160 - (myPOSP0 & 0xFC)];
myCurrentP1Mask = &ourPlayerMaskTable[myPOSP1 & 0x03]
[0][myNUSIZ1 & 0x07][160 - (myPOSP1 & 0xFC)];
if(myM0CosmicArkMotionEnabled)
{
static uInt32 m[4] = {18, 33, 0, 17};
myM0CosmicArkCounter = (myM0CosmicArkCounter + 1) & 3;
myPOSM0 -= m[myM0CosmicArkCounter];
if(myPOSM0 >= 160)
myPOSM0 -= 160;
else if(myPOSM0 < 0)
myPOSM0 += 160;
if(myM0CosmicArkCounter == 1)
{
myCurrentM0Mask = &ourMissleMaskTable[myPOSM0 & 0x03]
[myNUSIZ0 & 0x07][((myNUSIZ0 & 0x30) >> 4) | 0x01]
[160 - (myPOSM0 & 0xFC)];
}
else if(myM0CosmicArkCounter == 2)
{
myCurrentM0Mask = &ourDisabledMaskTable[0];
}
else
{
myCurrentM0Mask = &ourMissleMaskTable[myPOSM0 & 0x03]
[myNUSIZ0 & 0x07][(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFC)];
}
}
}
}
while(myClockAtLastUpdate < clock);
}
inline void TIA::waitHorizontalSync()
{
uInt32 cyclesToEndOfLine = 76 - ((mySystem->cycles() -
(myClockWhenFrameStarted / 3)) % 76);
if(cyclesToEndOfLine < 76)
{
mySystem->incrementCycles(cyclesToEndOfLine);
}
}
void TIA::greyOutFrame()
{
unsigned int c = scanlines();
if(c < myYStart) c = myYStart;
for(unsigned int s = c; s < (myHeight + myYStart); s++)
for(unsigned int i = 0; i < 160; i++) {
uInt8 tmp = myCurrentFrameBuffer[ (s - myYStart) * 160 + i] & 0x0f;
tmp >>= 1;
myCurrentFrameBuffer[ (s - myYStart) * 160 + i] = tmp;
}
}
void TIA::clearBuffers()
{
for(uInt32 i = 0; i < 160 * 300; ++i)
{
myCurrentFrameBuffer[i] = myPreviousFrameBuffer[i] = 0;
}
}
uInt8 TIA::peek(uInt16 addr)
{
updateFrame(mySystem->cycles() * 3);
uInt8 noise = mySystem->getDataBusState() & 0x3F;
switch(addr & 0x000f)
{
case 0x00: return ((myCollision & 0x0001) ? 0x80 : 0x00) |
((myCollision & 0x0002) ? 0x40 : 0x00) | noise;
case 0x01: return ((myCollision & 0x0004) ? 0x80 : 0x00) |
((myCollision & 0x0008) ? 0x40 : 0x00) | noise;
case 0x02: return ((myCollision & 0x0010) ? 0x80 : 0x00) |
((myCollision & 0x0020) ? 0x40 : 0x00) | noise;
case 0x03: return ((myCollision & 0x0040) ? 0x80 : 0x00) |
((myCollision & 0x0080) ? 0x40 : 0x00) | noise;
case 0x04: return ((myCollision & 0x0100) ? 0x80 : 0x00) |
((myCollision & 0x0200) ? 0x40 : 0x00) | noise;
case 0x05: return ((myCollision & 0x0400) ? 0x80 : 0x00) |
((myCollision & 0x0800) ? 0x40 : 0x00) | noise;
case 0x06: return ((myCollision & 0x1000) ? 0x80 : 0x00) | noise;
case 0x07: return ((myCollision & 0x2000) ? 0x80 : 0x00) |
((myCollision & 0x4000) ? 0x40 : 0x00) | noise;
case 0x08: {
Int32 r = myConsole.controller(Controller::Left).read(Controller::Nine);
if(r == Controller::minimumResistance)
{
return 0x80 | noise;
}
else if((r == Controller::maximumResistance) || myDumpEnabled)
{
return noise;
}
else
{
double t = (1.6 * r * 0.01E-6);
uInt32 needed = (uInt32)(t * 1.19E6);
if(mySystem->cycles() > (myDumpDisabledCycle + needed))
{
return 0x80 | noise;
}
else
{
return noise;
}
}
}
case 0x09: {
Int32 r = myConsole.controller(Controller::Left).read(Controller::Five);
if(r == Controller::minimumResistance)
{
return 0x80 | noise;
}
else if((r == Controller::maximumResistance) || myDumpEnabled)
{
return noise;
}
else
{
double t = (1.6 * r * 0.01E-6);
uInt32 needed = (uInt32)(t * 1.19E6);
if(mySystem->cycles() > (myDumpDisabledCycle + needed))
{
return 0x80 | noise;
}
else
{
return noise;
}
}
}
case 0x0A: {
Int32 r = myConsole.controller(Controller::Right).read(Controller::Nine);
if(r == Controller::minimumResistance)
{
return 0x80 | noise;
}
else if((r == Controller::maximumResistance) || myDumpEnabled)
{
return noise;
}
else
{
double t = (1.6 * r * 0.01E-6);
uInt32 needed = (uInt32)(t * 1.19E6);
if(mySystem->cycles() > (myDumpDisabledCycle + needed))
{
return 0x80 | noise;
}
else
{
return noise;
}
}
}
case 0x0B: {
Int32 r = myConsole.controller(Controller::Right).read(Controller::Five);
if(r == Controller::minimumResistance)
{
return 0x80 | noise;
}
else if((r == Controller::maximumResistance) || myDumpEnabled)
{
return noise;
}
else
{
double t = (1.6 * r * 0.01E-6);
uInt32 needed = (uInt32)(t * 1.19E6);
if(mySystem->cycles() > (myDumpDisabledCycle + needed))
{
return 0x80 | noise;
}
else
{
return noise;
}
}
}
case 0x0C: return myConsole.controller(Controller::Left).read(Controller::Six) ?
(0x80 | noise) : noise;
case 0x0D: return myConsole.controller(Controller::Right).read(Controller::Six) ?
(0x80 | noise) : noise;
case 0x0e:
return noise;
default:
return noise;
}
}
void TIA::poke(uInt16 addr, uInt8 value)
{
addr = addr & 0x003f;
Int32 clock = mySystem->cycles() * 3;
Int16 delay = ourPokeDelayTable[addr];
if(delay == -1)
{
static uInt32 d[4] = {4, 5, 2, 3};
Int32 x = ((clock - myClockWhenFrameStarted) % 228);
delay = d[(x / 3) & 3];
}
updateFrame(clock + delay);
if(((clock - myClockWhenFrameStarted) / 228) > myMaximumNumberOfScanlines)
{
mySystem->m6502().stop();
myPartialFrameFlag = false;
}
switch(addr)
{
case 0x00: {
myVSYNC = value;
if(myVSYNC & 0x02)
{
myVSYNCFinishClock = clock + 228;
}
else if(!(myVSYNC & 0x02) && (clock >= myVSYNCFinishClock))
{
myVSYNCFinishClock = 0x7FFFFFFF;
mySystem->m6502().stop();
myPartialFrameFlag = false;
}
break;
}
case 0x01: {
if(!(myVBLANK & 0x80) && (value & 0x80))
{
myDumpEnabled = true;
}
if((myVBLANK & 0x80) && !(value & 0x80))
{
myDumpEnabled = false;
myDumpDisabledCycle = mySystem->cycles();
}
myVBLANK = value;
break;
}
case 0x02: {
if(mySystem->m6502().lastAccessWasRead())
{
waitHorizontalSync();
}
break;
}
case 0x03: {
break;
}
case 0x04: {
myNUSIZ0 = value;
myCurrentP0Mask = &ourPlayerMaskTable[myPOSP0 & 0x03]
[0][myNUSIZ0 & 0x07][160 - (myPOSP0 & 0xFC)];
myCurrentM0Mask = &ourMissleMaskTable[myPOSM0 & 0x03]
[myNUSIZ0 & 0x07][(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFC)];
break;
}
case 0x05: {
myNUSIZ1 = value;
myCurrentP1Mask = &ourPlayerMaskTable[myPOSP1 & 0x03]
[0][myNUSIZ1 & 0x07][160 - (myPOSP1 & 0xFC)];
myCurrentM1Mask = &ourMissleMaskTable[myPOSM1 & 0x03]
[myNUSIZ1 & 0x07][(myNUSIZ1 & 0x30) >> 4][160 - (myPOSM1 & 0xFC)];
break;
}
case 0x06: {
uInt32 color = (uInt32)(value & 0xfe);
if(myColorLossEnabled && (myScanlineCountForLastFrame & 0x01))
{
color |= 0x01;
}
myCOLUP0 = (((((color << 8) | color) << 8) | color) << 8) | color;
break;
}
case 0x07: {
uInt32 color = (uInt32)(value & 0xfe);
if(myColorLossEnabled && (myScanlineCountForLastFrame & 0x01))
{
color |= 0x01;
}
myCOLUP1 = (((((color << 8) | color) << 8) | color) << 8) | color;
break;
}
case 0x08: {
uInt32 color = (uInt32)(value & 0xfe);
if(myColorLossEnabled && (myScanlineCountForLastFrame & 0x01))
{
color |= 0x01;
}
myCOLUPF = (((((color << 8) | color) << 8) | color) << 8) | color;
break;
}
case 0x09: {
uInt32 color = (uInt32)(value & 0xfe);
if(myColorLossEnabled && (myScanlineCountForLastFrame & 0x01))
{
color |= 0x01;
}
myCOLUBK = (((((color << 8) | color) << 8) | color) << 8) | color;
break;
}
case 0x0A: {
myCTRLPF = value;
myPlayfieldPriorityAndScore = ((myCTRLPF & 0x06) << 5);
if(((clock - myClockWhenFrameStarted) % 228) < (68 + 79))
{
myCurrentPFMask = ourPlayfieldTable[myCTRLPF & 0x01];
}
myCurrentBLMask = &ourBallMaskTable[myPOSBL & 0x03]
[(myCTRLPF & 0x30) >> 4][160 - (myPOSBL & 0xFC)];
break;
}
case 0x0B: {
if(((value & 0x08) && !myREFP0) || (!(value & 0x08) && myREFP0))
{
myREFP0 = (value & 0x08);
myCurrentGRP0 = ourPlayerReflectTable[myCurrentGRP0];
}
break;
}
case 0x0C: {
if(((value & 0x08) && !myREFP1) || (!(value & 0x08) && myREFP1))
{
myREFP1 = (value & 0x08);
myCurrentGRP1 = ourPlayerReflectTable[myCurrentGRP1];
}
break;
}
case 0x0D: {
myPF = (myPF & 0x000FFFF0) | ((value >> 4) & 0x0F);
if(!myBitEnabled[TIA::PF] || myPF == 0)
myEnabledObjects &= ~myPFBit;
else
myEnabledObjects |= myPFBit;
break;
}
case 0x0E: {
myPF = (myPF & 0x000FF00F) | ((uInt32)value << 4);
if(!myBitEnabled[TIA::PF] || myPF == 0)
myEnabledObjects &= ~myPFBit;
else
myEnabledObjects |= myPFBit;
break;
}
case 0x0F: {
myPF = (myPF & 0x00000FFF) | ((uInt32)value << 12);
if(!myBitEnabled[TIA::PF] || myPF == 0)
myEnabledObjects &= ~myPFBit;
else
myEnabledObjects |= myPFBit;
break;
}
case 0x10: {
Int32 hpos = (clock - myClockWhenFrameStarted) % 228;
Int32 newx = hpos < HBLANK ? 3 : (((hpos - HBLANK) + 5) % 160);
Int8 when = ourPlayerPositionResetWhenTable[myNUSIZ0 & 7][myPOSP0][newx];
if(when == 1)
{
updateFrame(clock + 11);
myPOSP0 = newx;
myCurrentP0Mask = &ourPlayerMaskTable[myPOSP0 & 0x03]
[1][myNUSIZ0 & 0x07][160 - (myPOSP0 & 0xFC)];
}
else if(when == 0)
{
myPOSP0 = newx;
myCurrentP0Mask = &ourPlayerMaskTable[myPOSP0 & 0x03]
[1][myNUSIZ0 & 0x07][160 - (myPOSP0 & 0xFC)];
}
else if(when == -1)
{
myPOSP0 = newx;
myCurrentP0Mask = &ourPlayerMaskTable[myPOSP0 & 0x03]
[0][myNUSIZ0 & 0x07][160 - (myPOSP0 & 0xFC)];
}
break;
}
case 0x11: {
Int32 hpos = (clock - myClockWhenFrameStarted) % 228;
Int32 newx = hpos < HBLANK ? 3 : (((hpos - HBLANK) + 5) % 160);
Int8 when = ourPlayerPositionResetWhenTable[myNUSIZ1 & 7][myPOSP1][newx];
if(when == 1)
{
updateFrame(clock + 11);
myPOSP1 = newx;
myCurrentP1Mask = &ourPlayerMaskTable[myPOSP1 & 0x03]
[1][myNUSIZ1 & 0x07][160 - (myPOSP1 & 0xFC)];
}
else if(when == 0)
{
myPOSP1 = newx;
myCurrentP1Mask = &ourPlayerMaskTable[myPOSP1 & 0x03]
[1][myNUSIZ1 & 0x07][160 - (myPOSP1 & 0xFC)];
}
else if(when == -1)
{
myPOSP1 = newx;
myCurrentP1Mask = &ourPlayerMaskTable[myPOSP1 & 0x03]
[0][myNUSIZ1 & 0x07][160 - (myPOSP1 & 0xFC)];
}
break;
}
case 0x12: {
int hpos = (clock - myClockWhenFrameStarted) % 228;
myPOSM0 = hpos < HBLANK ? 2 : (((hpos - HBLANK) + 4) % 160);
if(((clock - myLastHMOVEClock) == (20 * 3)) && (hpos == 69))
{
myPOSM0 = 8;
}
myCurrentM0Mask = &ourMissleMaskTable[myPOSM0 & 0x03]
[myNUSIZ0 & 0x07][(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFC)];
break;
}
case 0x13: {
int hpos = (clock - myClockWhenFrameStarted) % 228;
myPOSM1 = hpos < HBLANK ? 2 : (((hpos - HBLANK) + 4) % 160);
if(((clock - myLastHMOVEClock) == (3 * 3)) && (hpos == 18))
{
myPOSM1 = 3;
}
myCurrentM1Mask = &ourMissleMaskTable[myPOSM1 & 0x03]
[myNUSIZ1 & 0x07][(myNUSIZ1 & 0x30) >> 4][160 - (myPOSM1 & 0xFC)];
break;
}
case 0x14: {
int hpos = (clock - myClockWhenFrameStarted) % 228 ;
myPOSBL = hpos < HBLANK ? 2 : (((hpos - HBLANK) + 4) % 160);
if(((clock - myLastHMOVEClock) == (18 * 3)) &&
((hpos == 60) || (hpos == 69)))
{
myPOSBL = 10;
}
else if(((clock - myLastHMOVEClock) == (3 * 3)) && (hpos == 18))
{
myPOSBL = 3;
}
else if(((clock - myLastHMOVEClock) == (7 * 3)) && (hpos == 30))
{
myPOSBL = 6;
}
else if(((clock - myLastHMOVEClock) == (6 * 3)) && (hpos == 27))
{
myPOSBL = 5;
}
myCurrentBLMask = &ourBallMaskTable[myPOSBL & 0x03]
[(myCTRLPF & 0x30) >> 4][160 - (myPOSBL & 0xFC)];
break;
}
case 0x15: {
myAUDC0 = value & 0x0f;
mySound->set(addr, value, mySystem->cycles());
break;
}
case 0x16: {
myAUDC1 = value & 0x0f;
mySound->set(addr, value, mySystem->cycles());
break;
}
case 0x17: {
myAUDF0 = value & 0x1f;
mySound->set(addr, value, mySystem->cycles());
break;
}
case 0x18: {
myAUDF1 = value & 0x1f;
mySound->set(addr, value, mySystem->cycles());
break;
}
case 0x19: {
myAUDV0 = value & 0x0f;
mySound->set(addr, value, mySystem->cycles());
break;
}
case 0x1A: {
myAUDV1 = value & 0x0f;
mySound->set(addr, value, mySystem->cycles());
break;
}
case 0x1B: {
myGRP0 = (myBitEnabled[TIA::P0] ? value : 0);
myDGRP1 = myGRP1;
uInt8 grp0 = myVDELP0 ? myDGRP0 : myGRP0;
myCurrentGRP0 = myREFP0 ? ourPlayerReflectTable[grp0] : grp0;
uInt8 grp1 = myVDELP1 ? myDGRP1 : myGRP1;
myCurrentGRP1 = myREFP1 ? ourPlayerReflectTable[grp1] : grp1;
if(myCurrentGRP0 != 0)
myEnabledObjects |= myP0Bit;
else
myEnabledObjects &= ~myP0Bit;
if(myCurrentGRP1 != 0)
myEnabledObjects |= myP1Bit;
else
myEnabledObjects &= ~myP1Bit;
break;
}
case 0x1C: {
myGRP1 = (myBitEnabled[TIA::P1] ? value : 0);
myDGRP0 = myGRP0;
myDENABL = myENABL;
uInt8 grp0 = myVDELP0 ? myDGRP0 : myGRP0;
myCurrentGRP0 = myREFP0 ? ourPlayerReflectTable[grp0] : grp0;
uInt8 grp1 = myVDELP1 ? myDGRP1 : myGRP1;
myCurrentGRP1 = myREFP1 ? ourPlayerReflectTable[grp1] : grp1;
if(myCurrentGRP0 != 0)
myEnabledObjects |= myP0Bit;
else
myEnabledObjects &= ~myP0Bit;
if(myCurrentGRP1 != 0)
myEnabledObjects |= myP1Bit;
else
myEnabledObjects &= ~myP1Bit;
if(myVDELBL ? myDENABL : myENABL)
myEnabledObjects |= myBLBit;
else
myEnabledObjects &= ~myBLBit;
break;
}
case 0x1D: {
myENAM0 = (myBitEnabled[TIA::M0] ? value & 0x02 : 0);
if(myENAM0 && !myRESMP0)
myEnabledObjects |= myM0Bit;
else
myEnabledObjects &= ~myM0Bit;
break;
}
case 0x1E: {
myENAM1 = (myBitEnabled[TIA::M1] ? value & 0x02 : 0);
if(myENAM1 && !myRESMP1)
myEnabledObjects |= myM1Bit;
else
myEnabledObjects &= ~myM1Bit;
break;
}
case 0x1F: {
myENABL = (myBitEnabled[TIA::BL] ? value & 0x02 : 0);
if(myVDELBL ? myDENABL : myENABL)
myEnabledObjects |= myBLBit;
else
myEnabledObjects &= ~myBLBit;
break;
}
case 0x20: {
myHMP0 = value >> 4;
break;
}
case 0x21: {
myHMP1 = value >> 4;
break;
}
case 0x22: {
Int8 tmp = value >> 4;
if((clock == (myLastHMOVEClock + 21 * 3)) && (myHMM0 == 7) && (tmp == 6))
{
myM0CosmicArkMotionEnabled = true;
myM0CosmicArkCounter = 0;
}
myHMM0 = tmp;
break;
}
case 0x23: {
myHMM1 = value >> 4;
break;
}
case 0x24: {
myHMBL = value >> 4;
break;
}
case 0x25: {
myVDELP0 = value & 0x01;
uInt8 grp0 = myVDELP0 ? myDGRP0 : myGRP0;
myCurrentGRP0 = myREFP0 ? ourPlayerReflectTable[grp0] : grp0;
if(myCurrentGRP0 != 0)
myEnabledObjects |= myP0Bit;
else
myEnabledObjects &= ~myP0Bit;
break;
}
case 0x26: {
myVDELP1 = value & 0x01;
uInt8 grp1 = myVDELP1 ? myDGRP1 : myGRP1;
myCurrentGRP1 = myREFP1 ? ourPlayerReflectTable[grp1] : grp1;
if(myCurrentGRP1 != 0)
myEnabledObjects |= myP1Bit;
else
myEnabledObjects &= ~myP1Bit;
break;
}
case 0x27: {
myVDELBL = value & 0x01;
if(myVDELBL ? myDENABL : myENABL)
myEnabledObjects |= myBLBit;
else
myEnabledObjects &= ~myBLBit;
break;
}
case 0x28: {
if(myRESMP0 && !(value & 0x02))
{
uInt16 middle;
if((myNUSIZ0 & 0x07) == 0x05)
middle = 8;
else if((myNUSIZ0 & 0x07) == 0x07)
middle = 16;
else
middle = 4;
myPOSM0 = (myPOSP0 + middle) % 160;
myCurrentM0Mask = &ourMissleMaskTable[myPOSM0 & 0x03]
[myNUSIZ0 & 0x07][(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFC)];
}
myRESMP0 = value & 0x02;
if(myENAM0 && !myRESMP0)
myEnabledObjects |= myM0Bit;
else
myEnabledObjects &= ~myM0Bit;
break;
}
case 0x29: {
if(myRESMP1 && !(value & 0x02))
{
uInt16 middle;
if((myNUSIZ1 & 0x07) == 0x05)
middle = 8;
else if((myNUSIZ1 & 0x07) == 0x07)
middle = 16;
else
middle = 4;
myPOSM1 = (myPOSP1 + middle) % 160;
myCurrentM1Mask = &ourMissleMaskTable[myPOSM1 & 0x03]
[myNUSIZ1 & 0x07][(myNUSIZ1 & 0x30) >> 4][160 - (myPOSM1 & 0xFC)];
}
myRESMP1 = value & 0x02;
if(myENAM1 && !myRESMP1)
myEnabledObjects |= myM1Bit;
else
myEnabledObjects &= ~myM1Bit;
break;
}
case 0x2A: {
Int32 x = ((clock - myClockWhenFrameStarted) % 228) / 3;
if(myAllowHMOVEBlanks && ourHMOVEBlankEnableCycles[x])
{
myHMOVEBlankEnabled = true;
}
myPOSP0 += ourCompleteMotionTable[x][myHMP0];
myPOSP1 += ourCompleteMotionTable[x][myHMP1];
myPOSM0 += ourCompleteMotionTable[x][myHMM0];
myPOSM1 += ourCompleteMotionTable[x][myHMM1];
myPOSBL += ourCompleteMotionTable[x][myHMBL];
if(myPOSP0 >= 160)
myPOSP0 -= 160;
else if(myPOSP0 < 0)
myPOSP0 += 160;
if(myPOSP1 >= 160)
myPOSP1 -= 160;
else if(myPOSP1 < 0)
myPOSP1 += 160;
if(myPOSM0 >= 160)
myPOSM0 -= 160;
else if(myPOSM0 < 0)
myPOSM0 += 160;
if(myPOSM1 >= 160)
myPOSM1 -= 160;
else if(myPOSM1 < 0)
myPOSM1 += 160;
if(myPOSBL >= 160)
myPOSBL -= 160;
else if(myPOSBL < 0)
myPOSBL += 160;
myCurrentBLMask = &ourBallMaskTable[myPOSBL & 0x03]
[(myCTRLPF & 0x30) >> 4][160 - (myPOSBL & 0xFC)];
myCurrentP0Mask = &ourPlayerMaskTable[myPOSP0 & 0x03]
[0][myNUSIZ0 & 0x07][160 - (myPOSP0 & 0xFC)];
myCurrentP1Mask = &ourPlayerMaskTable[myPOSP1 & 0x03]
[0][myNUSIZ1 & 0x07][160 - (myPOSP1 & 0xFC)];
myCurrentM0Mask = &ourMissleMaskTable[myPOSM0 & 0x03]
[myNUSIZ0 & 0x07][(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFC)];
myCurrentM1Mask = &ourMissleMaskTable[myPOSM1 & 0x03]
[myNUSIZ1 & 0x07][(myNUSIZ1 & 0x30) >> 4][160 - (myPOSM1 & 0xFC)];
myLastHMOVEClock = clock;
myM0CosmicArkMotionEnabled = false;
break;
}
case 0x2b: {
myHMP0 = 0;
myHMP1 = 0;
myHMM0 = 0;
myHMM1 = 0;
myHMBL = 0;
break;
}
case 0x2c: {
myCollision = 0;
break;
}
default:
{
#ifdef DEBUG_ACCESSES
ale::Logger::Info << "BAD TIA Poke: " << hex << addr << endl;
#endif
break;
}
}
}
uInt8 TIA::ourBallMaskTable[4][4][320];
uInt16 TIA::ourCollisionTable[64];
const uInt8 TIA::ourDisabledMaskTable[640] = {};
const Int16 TIA::ourPokeDelayTable[64] = {
0, 1, 0, 0, 8, 8, 0, 0, 0, 0, 0, 1, 1, -1, -1, -1,
0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
uInt8 TIA::ourMissleMaskTable[4][8][4][320];
const bool TIA::ourHMOVEBlankEnableCycles[76] = {
true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true };
const Int32 TIA::ourCompleteMotionTable[76][16] = {
{ 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, { 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, { 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, { 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, { 0, -1, -2, -3, -4, -5, -6, -6, 8, 7, 6, 5, 4, 3, 2, 1}, { 0, -1, -2, -3, -4, -5, -5, -5, 8, 7, 6, 5, 4, 3, 2, 1}, { 0, -1, -2, -3, -4, -5, -5, -5, 8, 7, 6, 5, 4, 3, 2, 1}, { 0, -1, -2, -3, -4, -4, -4, -4, 8, 7, 6, 5, 4, 3, 2, 1}, { 0, -1, -2, -3, -3, -3, -3, -3, 8, 7, 6, 5, 4, 3, 2, 1}, { 0, -1, -2, -2, -2, -2, -2, -2, 8, 7, 6, 5, 4, 3, 2, 1}, { 0, -1, -2, -2, -2, -2, -2, -2, 8, 7, 6, 5, 4, 3, 2, 1}, { 0, -1, -1, -1, -1, -1, -1, -1, 8, 7, 6, 5, 4, 3, 2, 1}, { 0, 0, 0, 0, 0, 0, 0, 0, 8, 7, 6, 5, 4, 3, 2, 1}, { 1, 1, 1, 1, 1, 1, 1, 1, 8, 7, 6, 5, 4, 3, 2, 1}, { 1, 1, 1, 1, 1, 1, 1, 1, 8, 7, 6, 5, 4, 3, 2, 1}, { 2, 2, 2, 2, 2, 2, 2, 2, 8, 7, 6, 5, 4, 3, 2, 2}, { 3, 3, 3, 3, 3, 3, 3, 3, 8, 7, 6, 5, 4, 3, 3, 3}, { 4, 4, 4, 4, 4, 4, 4, 4, 8, 7, 6, 5, 4, 4, 4, 4}, { 4, 4, 4, 4, 4, 4, 4, 4, 8, 7, 6, 5, 4, 4, 4, 4}, { 5, 5, 5, 5, 5, 5, 5, 5, 8, 7, 6, 5, 5, 5, 5, 5}, { 6, 6, 6, 6, 6, 6, 6, 6, 8, 7, 6, 6, 6, 6, 6, 6}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, -1, -2, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, -1, -2, -3, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, -1, -2, -3, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, -1, -2, -3, -4, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, -1, -2, -3, -4, -5, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, -1, -2, -3, -4, -5, -6, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, -1, -2, -3, -4, -5, -6, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, -1, -2, -3, -4, -5, -6, -7, 0, 0, 0, 0, 0, 0, 0, 0},
{-1, -2, -3, -4, -5, -6, -7, -8, 0, 0, 0, 0, 0, 0, 0, 0},
{-2, -3, -4, -5, -6, -7, -8, -9, 0, 0, 0, 0, 0, 0, 0, -1},
{-2, -3, -4, -5, -6, -7, -8, -9, 0, 0, 0, 0, 0, 0, 0, -1},
{-3, -4, -5, -6, -7, -8, -9,-10, 0, 0, 0, 0, 0, 0, -1, -2},
{-4, -5, -6, -7, -8, -9,-10,-11, 0, 0, 0, 0, 0, -1, -2, -3},
{-5, -6, -7, -8, -9,-10,-11,-12, 0, 0, 0, 0, -1, -2, -3, -4},
{-5, -6, -7, -8, -9,-10,-11,-12, 0, 0, 0, 0, -1, -2, -3, -4},
{-6, -7, -8, -9,-10,-11,-12,-13, 0, 0, 0, -1, -2, -3, -4, -5},
{-7, -8, -9,-10,-11,-12,-13,-14, 0, 0, -1, -2, -3, -4, -5, -6},
{-8, -9,-10,-11,-12,-13,-14,-15, 0, -1, -2, -3, -4, -5, -6, -7},
{-8, -9,-10,-11,-12,-13,-14,-15, 0, -1, -2, -3, -4, -5, -6, -7},
{ 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1} };
uInt8 TIA::ourPlayerMaskTable[4][2][8][320];
Int8 TIA::ourPlayerPositionResetWhenTable[8][160][160];
uInt8 TIA::ourPlayerReflectTable[256];
uInt32 TIA::ourPlayfieldTable[2][160];
TIA::TIA(const TIA& c)
: myConsole(c.myConsole),
mySettings(c.mySettings),
mySound(c.mySound),
myCOLUBK(myColor[0]),
myCOLUPF(myColor[1]),
myCOLUP0(myColor[2]),
myCOLUP1(myColor[3])
{
assert(false);
}
TIA& TIA::operator = (const TIA&)
{
assert(false);
return *this;
}
inline void TIA::updateFrameScanlineFast(uInt32 clocksToUpdate, uInt32 hpos)
{
uInt8* ending = myFramePointer + clocksToUpdate;
if(myVBLANK & 0x02)
{
}
else
{
switch(myEnabledObjects | myPlayfieldPriorityAndScore)
{
case 0x00:
case 0x00 | ScoreBit:
case 0x00 | PriorityBit:
case 0x00 | PriorityBit | ScoreBit:
break;
case myPFBit:
case myPFBit | PriorityBit:
break;
case myPFBit | ScoreBit:
case myPFBit | ScoreBit | PriorityBit:
break;
case myP0Bit:
case myP0Bit | ScoreBit:
case myP0Bit | PriorityBit:
case myP0Bit | ScoreBit | PriorityBit:
case myP1Bit:
case myP1Bit | ScoreBit:
case myP1Bit | PriorityBit:
case myP1Bit | ScoreBit | PriorityBit:
case myP0Bit | myP1Bit:
case myP0Bit | myP1Bit | ScoreBit:
case myP0Bit | myP1Bit | PriorityBit:
case myP0Bit | myP1Bit | ScoreBit | PriorityBit:
{
const uInt8* mP0 = &myCurrentP0Mask[hpos];
const uInt8* mP1 = &myCurrentP1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP0 &&
!*(uInt32*)mP1)
{
mP0 += 4; mP1 += 4; myFramePointer += 4;
}
else
{
if((myCurrentGRP0 & *mP0) && (myCurrentGRP1 & *mP1))
myCollision |= ourCollisionTable[myP0Bit | myP1Bit];
++mP0; ++mP1; ++myFramePointer;
}
}
break;
}
case myM0Bit:
case myM0Bit | ScoreBit:
case myM0Bit | PriorityBit:
case myM0Bit | ScoreBit | PriorityBit:
break;
case myM1Bit:
case myM1Bit | ScoreBit:
case myM1Bit | PriorityBit:
case myM1Bit | ScoreBit | PriorityBit:
break;
case myBLBit:
case myBLBit | ScoreBit:
case myBLBit | PriorityBit:
case myBLBit | ScoreBit | PriorityBit:
break;
case myM0Bit | myM1Bit:
case myM0Bit | myM1Bit | ScoreBit:
case myM0Bit | myM1Bit | PriorityBit:
case myM0Bit | myM1Bit | ScoreBit | PriorityBit:
{
const uInt8* mM0 = &myCurrentM0Mask[hpos];
const uInt8* mM1 = &myCurrentM1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mM0 && !*(uInt32*)mM1)
{
mM0 += 4; mM1 += 4; myFramePointer += 4;
}
else
{
if(*mM0 && *mM1)
myCollision |= ourCollisionTable[myM0Bit | myM1Bit];
++mM0; ++mM1; ++myFramePointer;
}
}
break;
}
case myBLBit | myM0Bit:
case myBLBit | myM0Bit | ScoreBit:
{
const uInt8* mBL = &myCurrentBLMask[hpos];
const uInt8* mM0 = &myCurrentM0Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL && !*(uInt32*)mM0)
{
mBL += 4; mM0 += 4; myFramePointer += 4;
}
else
{
if(*mBL && *mM0)
myCollision |= ourCollisionTable[myBLBit | myM0Bit];
++mBL; ++mM0; ++myFramePointer;
}
}
break;
}
case myBLBit | myM0Bit | PriorityBit:
case myBLBit | myM0Bit | ScoreBit | PriorityBit:
{
const uInt8* mBL = &myCurrentBLMask[hpos];
const uInt8* mM0 = &myCurrentM0Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL && !*(uInt32*)mM0)
{
mBL += 4; mM0 += 4; myFramePointer += 4;
}
else
{
if(*mBL && *mM0)
myCollision |= ourCollisionTable[myBLBit | myM0Bit];
++mBL; ++mM0; ++myFramePointer;
}
}
break;
}
case myBLBit | myM1Bit:
case myBLBit | myM1Bit | ScoreBit:
{
const uInt8* mBL = &myCurrentBLMask[hpos];
const uInt8* mM1 = &myCurrentM1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL &&
!*(uInt32*)mM1)
{
mBL += 4; mM1 += 4; myFramePointer += 4;
}
else
{
if(*mBL && *mM1)
myCollision |= ourCollisionTable[myBLBit | myM1Bit];
++mBL; ++mM1; ++myFramePointer;
}
}
break;
}
case myBLBit | myM1Bit | PriorityBit:
case myBLBit | myM1Bit | ScoreBit | PriorityBit:
{
const uInt8* mBL = &myCurrentBLMask[hpos];
const uInt8* mM1 = &myCurrentM1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL &&
!*(uInt32*)mM1)
{
mBL += 4; mM1 += 4; myFramePointer += 4;
}
else
{
if(*mBL && *mM1)
myCollision |= ourCollisionTable[myBLBit | myM1Bit];
++mBL; ++mM1; ++myFramePointer;
}
}
break;
}
case myBLBit | myP1Bit:
case myBLBit | myP1Bit | ScoreBit:
{
const uInt8* mBL = &myCurrentBLMask[hpos];
const uInt8* mP1 = &myCurrentP1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP1 && !*(uInt32*)mBL)
{
mBL += 4; mP1 += 4; myFramePointer += 4;
}
else
{
if(*mBL && (myCurrentGRP1 & *mP1))
myCollision |= ourCollisionTable[myBLBit | myP1Bit];
++mBL; ++mP1; ++myFramePointer;
}
}
break;
}
case myBLBit | myP1Bit | PriorityBit:
case myBLBit | myP1Bit | PriorityBit | ScoreBit:
{
const uInt8* mBL = &myCurrentBLMask[hpos];
const uInt8* mP1 = &myCurrentP1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP1 && !*(uInt32*)mBL)
{
mBL += 4; mP1 += 4; myFramePointer += 4;
}
else
{
if(*mBL && (myCurrentGRP1 & *mP1))
myCollision |= ourCollisionTable[myBLBit | myP1Bit];
++mBL; ++mP1; ++myFramePointer;
}
}
break;
}
case myPFBit | myP0Bit:
{
const uInt32* mPF = &myCurrentPFMask[hpos];
const uInt8* mP0 = &myCurrentP0Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP0)
{
mPF += 4; mP0 += 4; myFramePointer += 4;
}
else
{
if((myPF & *mPF) && (myCurrentGRP0 & *mP0))
myCollision |= ourCollisionTable[myPFBit | myP0Bit];
++mPF; ++mP0; ++myFramePointer;
}
}
break;
}
case myPFBit | myP0Bit | PriorityBit:
{
const uInt32* mPF = &myCurrentPFMask[hpos];
const uInt8* mP0 = &myCurrentP0Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP0)
{
mPF += 4; mP0 += 4; myFramePointer += 4;
}
else
{
if((myPF & *mPF) && (myCurrentGRP0 & *mP0))
myCollision |= ourCollisionTable[myPFBit | myP0Bit];
++mPF; ++mP0; ++myFramePointer;
}
}
break;
}
case myPFBit | myP1Bit:
{
const uInt32* mPF = &myCurrentPFMask[hpos];
const uInt8* mP1 = &myCurrentP1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP1)
{
mPF += 4; mP1 += 4; myFramePointer += 4;
}
else
{
if((myPF & *mPF) && (myCurrentGRP1 & *mP1))
myCollision |= ourCollisionTable[myPFBit | myP1Bit];
++mPF; ++mP1; ++myFramePointer;
}
}
break;
}
case myPFBit | myP1Bit | PriorityBit:
{
const uInt32* mPF = &myCurrentPFMask[hpos];
const uInt8* mP1 = &myCurrentP1Mask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP1)
{
mPF += 4; mP1 += 4; myFramePointer += 4;
}
else
{
if((myPF & *mPF) && (myCurrentGRP1 & *mP1))
myCollision |= ourCollisionTable[myPFBit | myP1Bit];
++mPF; ++mP1; ++myFramePointer;
}
}
break;
}
case myPFBit | myBLBit:
case myPFBit | myBLBit | PriorityBit:
{
const uInt32* mPF = &myCurrentPFMask[hpos];
const uInt8* mBL = &myCurrentBLMask[hpos];
while(myFramePointer < ending)
{
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL)
{
mPF += 4; mBL += 4; myFramePointer += 4;
}
else
{
if((myPF & *mPF) && *mBL)
myCollision |= ourCollisionTable[myPFBit | myBLBit];
++mPF; ++mBL; ++myFramePointer;
}
}
break;
}
default:
{
for(; myFramePointer < ending; ++myFramePointer, ++hpos)
{
uInt8 enabled = (myPF & myCurrentPFMask[hpos]) ? myPFBit : 0;
if((myEnabledObjects & myBLBit) && myCurrentBLMask[hpos])
enabled |= myBLBit;
if(myCurrentGRP1 & myCurrentP1Mask[hpos])
enabled |= myP1Bit;
if((myEnabledObjects & myM1Bit) && myCurrentM1Mask[hpos])
enabled |= myM1Bit;
if(myCurrentGRP0 & myCurrentP0Mask[hpos])
enabled |= myP0Bit;
if((myEnabledObjects & myM0Bit) && myCurrentM0Mask[hpos])
enabled |= myM0Bit;
myCollision |= ourCollisionTable[enabled];
}
break;
}
}
}
myFramePointer = ending;
}