1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-24 12:29:06 +00:00

Sprites are still a pixel off but better; made some attempt to move things outside of the loop.

This commit is contained in:
Thomas Harte 2016-05-25 21:43:19 -04:00
parent 40c2c0bd2d
commit 106ddae907
2 changed files with 88 additions and 47 deletions

View File

@ -27,6 +27,7 @@ Machine::Machine() :
{ {
memset(_collisions, 0xff, sizeof(_collisions)); memset(_collisions, 0xff, sizeof(_collisions));
set_reset_line(true); set_reset_line(true);
setup_reported_collisions();
} }
void Machine::setup_output(float aspect_ratio) void Machine::setup_output(float aspect_ratio)
@ -79,9 +80,9 @@ Machine::~Machine()
void Machine::update_timers(int mask) void Machine::update_timers(int mask)
{ {
unsigned int upcomingPointerPlus1 = (_upcomingEventsPointer + 1)%number_of_upcoming_events;
unsigned int upcomingPointerPlus2 = (_upcomingEventsPointer + 2)%number_of_upcoming_events;
unsigned int upcomingPointerPlus4 = (_upcomingEventsPointer + 4)%number_of_upcoming_events; unsigned int upcomingPointerPlus4 = (_upcomingEventsPointer + 4)%number_of_upcoming_events;
unsigned int upcomingPointerPlus5 = (_upcomingEventsPointer + 5)%number_of_upcoming_events;
unsigned int upcomingPointerPlus6 = (_upcomingEventsPointer + 6)%number_of_upcoming_events;
// grab the background now, for application in four clocks // grab the background now, for application in four clocks
if(mask & (1 << 5) && !(_horizontalTimer&3)) if(mask & (1 << 5) && !(_horizontalTimer&3))
@ -95,7 +96,7 @@ void Machine::update_timers(int mask)
{ {
// the ball becomes visible whenever it hits zero, regardless of whether its status // the ball becomes visible whenever it hits zero, regardless of whether its status
// is the result of a counter rollover or a programmatic reset // is the result of a counter rollover or a programmatic reset
if(!_objectCounter[4].count) _upcomingEvents[upcomingPointerPlus4].pixelCounterResetMask &= ~(1 << 4); if(!_objectCounter[4].count) _objectCounter[4].pixel = 0;
} }
// check for player and missle triggers // check for player and missle triggers
@ -107,7 +108,7 @@ void Machine::update_timers(int mask)
// 1/2 clocks ahead from 159 // 1/2 clocks ahead from 159
if(_objectCounter[c].count == 159) if(_objectCounter[c].count == 159)
{ {
unsigned int actionSlot = (c < 2) ? upcomingPointerPlus6 : upcomingPointerPlus5; unsigned int actionSlot = (c < 2) ? upcomingPointerPlus2 : upcomingPointerPlus1;
_upcomingEvents[actionSlot].pixelCounterResetMask &= ~(1 << c); _upcomingEvents[actionSlot].pixelCounterResetMask &= ~(1 << c);
} }
else else
@ -121,8 +122,14 @@ void Machine::update_timers(int mask)
( _objectCounter[c].count == 64 && ((repeatMask == 4) || (repeatMask == 6)) ) ( _objectCounter[c].count == 64 && ((repeatMask == 4) || (repeatMask == 6)) )
) )
{ {
unsigned int actionSlot = (c < 2) ? upcomingPointerPlus5 : upcomingPointerPlus4; if(c < 2)
_upcomingEvents[actionSlot].pixelCounterResetMask &= ~(1 << c); {
_upcomingEvents[upcomingPointerPlus1].pixelCounterResetMask &= ~(1 << c);
}
else
{
_objectCounter[c].pixel = 0;
}
} }
} }
} }
@ -131,6 +138,7 @@ void Machine::update_timers(int mask)
// update the pixel counters // update the pixel counters
for(int c = 0; c < 2; c++) for(int c = 0; c < 2; c++)
{ {
_upcomingEvents[upcomingPointerPlus4].pixelCounters[c] = _objectCounter[c].pixel;
if(mask&(1 << c)) if(mask&(1 << c))
{ {
_objectCounter[c].broad_pixel++; _objectCounter[c].broad_pixel++;
@ -148,6 +156,7 @@ void Machine::update_timers(int mask)
for(int c = 2; c < 5; c++) for(int c = 2; c < 5; c++)
{ {
_upcomingEvents[upcomingPointerPlus4].pixelCounters[c] = _objectCounter[c].pixel;
if(mask&(1 << c)) if(mask&(1 << c))
{ {
_objectCounter[c].count = (_objectCounter[c].count + 1)%160; _objectCounter[c].count = (_objectCounter[c].count + 1)%160;
@ -164,9 +173,8 @@ uint8_t Machine::get_output_pixel()
uint8_t playfieldColour = ((_playfieldControl&6) == 2) ? _playerColour[offset / 80] : _playfieldColour; uint8_t playfieldColour = ((_playfieldControl&6) == 2) ? _playerColour[offset / 80] : _playfieldColour;
uint8_t ballPixel = 0; uint8_t ballPixel = 0;
if(_objectCounter[4].pixel < 8 && _ballGraphicsEnable[_ballGraphicsSelector]&2) { if(_upcomingEvents[_upcomingEventsPointer].pixelCounters[4] < _ballSize) {
int ballSize = 1 << ((_playfieldControl >> 4)&3); ballPixel = _ballGraphicsEnable[_ballGraphicsSelector];
ballPixel = (_objectCounter[4].pixel < ballSize) ? 1 : 0;
} }
// determine the pixel masks // determine the pixel masks
@ -174,37 +182,25 @@ uint8_t Machine::get_output_pixel()
uint8_t missilePixels[2] = { 0, 0 }; uint8_t missilePixels[2] = { 0, 0 };
for(int c = 0; c < 2; c++) for(int c = 0; c < 2; c++)
{ {
if(_playerGraphics[c] && _objectCounter[c].pixel < 8) { if(_playerGraphics[c] && _upcomingEvents[_upcomingEventsPointer].pixelCounters[c] < 8) {
int flipMask = (_playerReflection[c]&0x8) ? 0 : 7; playerPixels[c] = (_playerGraphics[_playerGraphicsSelector[c]][c] >> (_upcomingEvents[_upcomingEventsPointer].pixelCounters[c] ^ _playerReflectionMask[c])) & 1;
playerPixels[c] = (_playerGraphics[_playerGraphicsSelector[c]][c] >> (_objectCounter[c].pixel ^ flipMask)) & 1;
} }
if(_objectCounter[c+2].pixel < 8 && (_missileGraphicsEnable[c]&2) && !_missileGraphicsReset[c]) { if(_upcomingEvents[_upcomingEventsPointer].pixelCounters[c+2] < _missileSize[c] && !_missileGraphicsReset[c]) {
int missileSize = 1 << ((_playerAndMissileSize[c] >> 4)&3); missilePixels[c] = _missileGraphicsEnable[c];
missilePixels[c] = (_objectCounter[c+2].pixel < missileSize) ? 1 : 0;
} }
} }
// accumulate collisions // accumulate collisions
if(playerPixels[0] | playerPixels[1]) { int pixel_mask = playerPixels[0] | (playerPixels[1] << 1) | (missilePixels[0] << 2) | (missilePixels[1] << 3) | (ballPixel << 4) | (_playfieldOutput << 5);
_collisions[0] |= ((missilePixels[0] & playerPixels[1]) << 7) | ((missilePixels[0] & playerPixels[0]) << 6); _collisions[0] |= _reportedCollisions[pixel_mask][0];
_collisions[1] |= ((missilePixels[1] & playerPixels[0]) << 7) | ((missilePixels[1] & playerPixels[1]) << 6); _collisions[1] |= _reportedCollisions[pixel_mask][1];
_collisions[2] |= _reportedCollisions[pixel_mask][2];
_collisions[2] |= ((_playfieldOutput & playerPixels[0]) << 7) | ((ballPixel & playerPixels[0]) << 6); _collisions[3] |= _reportedCollisions[pixel_mask][3];
_collisions[3] |= ((_playfieldOutput & playerPixels[1]) << 7) | ((ballPixel & playerPixels[1]) << 6); _collisions[4] |= _reportedCollisions[pixel_mask][4];
_collisions[5] |= _reportedCollisions[pixel_mask][5];
_collisions[7] |= ((playerPixels[0] & playerPixels[1]) << 7); _collisions[6] |= _reportedCollisions[pixel_mask][6];
} _collisions[7] |= _reportedCollisions[pixel_mask][7];
if(_playfieldOutput | ballPixel) {
_collisions[4] |= ((_playfieldOutput & missilePixels[0]) << 7) | ((ballPixel & missilePixels[0]) << 6);
_collisions[5] |= ((_playfieldOutput & missilePixels[1]) << 7) | ((ballPixel & missilePixels[1]) << 6);
_collisions[6] |= ((_playfieldOutput & ballPixel) << 7);
}
if(missilePixels[0] & missilePixels[1])
_collisions[7] |= (1 << 6);
// apply appropriate priority to pick a colour // apply appropriate priority to pick a colour
uint8_t playfieldPixel = _playfieldOutput | ballPixel; uint8_t playfieldPixel = _playfieldOutput | ballPixel;
@ -219,6 +215,40 @@ uint8_t Machine::get_output_pixel()
return outputColour; return outputColour;
} }
void Machine::setup_reported_collisions()
{
for(int c = 0; c < 32; c++)
{
memset(_reportedCollisions[c], 0, 8);
int playerPixels[2] = { c&1, (c >> 1)&1 };
int missilePixels[2] = { (c >> 2)&1, (c >> 3)&1 };
int ballPixel = (c >> 4)&1;
int playfieldPixel = (c >> 5)&1;
if(playerPixels[0] | playerPixels[1]) {
_reportedCollisions[c][0] |= ((missilePixels[0] & playerPixels[1]) << 7) | ((missilePixels[0] & playerPixels[0]) << 6);
_reportedCollisions[c][1] |= ((missilePixels[1] & playerPixels[0]) << 7) | ((missilePixels[1] & playerPixels[1]) << 6);
_reportedCollisions[c][2] |= ((playfieldPixel & playerPixels[0]) << 7) | ((ballPixel & playerPixels[0]) << 6);
_reportedCollisions[c][3] |= ((playfieldPixel & playerPixels[1]) << 7) | ((ballPixel & playerPixels[1]) << 6);
_reportedCollisions[c][7] |= ((playerPixels[0] & playerPixels[1]) << 7);
}
if(_playfieldOutput | ballPixel) {
_reportedCollisions[c][4] |= ((playfieldPixel & missilePixels[0]) << 7) | ((ballPixel & missilePixels[0]) << 6);
_reportedCollisions[c][5] |= ((playfieldPixel & missilePixels[1]) << 7) | ((ballPixel & missilePixels[1]) << 6);
_reportedCollisions[c][6] |= ((playfieldPixel & ballPixel) << 7);
}
if(missilePixels[0] & missilePixels[1])
_reportedCollisions[c][7] |= (1 << 6);
}
}
// in imputing the knowledge that all we're dealing with is the rollover from 159 to 0, // in imputing the knowledge that all we're dealing with is the rollover from 159 to 0,
// this is faster than the straightforward +1)%160 per profiling // this is faster than the straightforward +1)%160 per profiling
//#define increment_object_counter(c) _objectCounter[c] = (_objectCounter[c]+1)&~((158-_objectCounter[c]) >> 8) //#define increment_object_counter(c) _objectCounter[c] = (_objectCounter[c]+1)&~((158-_objectCounter[c]) >> 8)
@ -246,7 +276,6 @@ void Machine::output_pixels(unsigned int count)
if(state == OutputState::Pixel) if(state == OutputState::Pixel)
{ {
update_timers(~0); update_timers(~0);
_upcomingEvents[(_upcomingEventsPointer+4)%number_of_upcoming_events].updates |= Event::Action::ClockPixels;
} }
// if vsync is enabled, output the opposite of the automatic hsync output // if vsync is enabled, output the opposite of the automatic hsync output
@ -299,9 +328,9 @@ void Machine::output_pixels(unsigned int count)
update_timers(_hMoveFlags); update_timers(_hMoveFlags);
} }
if(_upcomingEvents[_upcomingEventsPointer].updates & Event::Action::ClockPixels) // if(_upcomingEvents[_upcomingEventsPointer].updates & Event::Action::ClockPixels)
{ // {
} // }
// apply any resets // apply any resets
_objectCounter[0].pixel *= (_upcomingEvents[_upcomingEventsPointer].pixelCounterResetMask >> 0) & 1; _objectCounter[0].pixel *= (_upcomingEvents[_upcomingEventsPointer].pixelCounterResetMask >> 0) & 1;
@ -476,7 +505,10 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
break; break;
case 0x04: case 0x04:
case 0x05: _playerAndMissileSize[decodedAddress - 0x04] = *value; break; case 0x05:
_playerAndMissileSize[decodedAddress - 0x04] = *value;
_missileSize[decodedAddress - 0x04] = 1 << ((*value >> 4)&3);
break;
case 0x06: case 0x06:
case 0x07: _playerColour[decodedAddress - 0x06] = *value; break; case 0x07: _playerColour[decodedAddress - 0x06] = *value; break;
@ -486,6 +518,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
case 0x0a: { case 0x0a: {
uint8_t old_playfield_control = _playfieldControl; uint8_t old_playfield_control = _playfieldControl;
_playfieldControl = *value; _playfieldControl = *value;
_ballSize = 1 << ((_playfieldControl >> 4)&3);
// did the mirroring bit change? // did the mirroring bit change?
if((_playfieldControl^old_playfield_control)&1) { if((_playfieldControl^old_playfield_control)&1) {
@ -497,7 +530,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
} }
} break; } break;
case 0x0b: case 0x0b:
case 0x0c: _playerReflection[decodedAddress - 0x0b] = *value; break; case 0x0c: _playerReflectionMask[decodedAddress - 0x0b] = (*value)&8 ? 0 : 7; break;
case 0x0d: case 0x0d:
_playfield[0] = ((*value) >> 4)&1; _playfield[0] = ((*value) >> 4)&1;
@ -556,10 +589,10 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
_playerGraphics[0][index] = *value; _playerGraphics[0][index] = *value;
_playerGraphics[1][index^1] = _playerGraphics[0][index^1]; _playerGraphics[1][index^1] = _playerGraphics[0][index^1];
} break; } break;
case 0x1d: _missileGraphicsEnable[0] = *value; break; case 0x1d:
case 0x1e: _missileGraphicsEnable[1] = *value; break; case 0x1e: _missileGraphicsEnable[decodedAddress - 0x1d] = ((*value) >> 1)&1; break;
case 0x1f: case 0x1f:
_ballGraphicsEnable[0] = *value; _ballGraphicsEnable[0] = ((*value) >> 1)&1;
break; break;
case 0x20: case 0x20:
@ -593,7 +626,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
_objectCounter[index + 2].count = (_objectCounter[index + 2].count + extra_offset)%160; _objectCounter[index + 2].count = (_objectCounter[index + 2].count + extra_offset)%160;
} }
_missileGraphicsReset[index] = (*value) & 0x02; _missileGraphicsReset[index] = !!((*value) & 0x02);
} }
break; break;

View File

@ -16,7 +16,7 @@
namespace Atari2600 { namespace Atari2600 {
const unsigned int number_of_upcoming_events = 7; const unsigned int number_of_upcoming_events = 6;
class Machine: public CPU6502::Processor<Machine> { class Machine: public CPU6502::Processor<Machine> {
@ -50,6 +50,9 @@ class Machine: public CPU6502::Processor<Machine> {
uint8_t _backgroundColour; uint8_t _backgroundColour;
uint8_t _playfield[40]; uint8_t _playfield[40];
// ... and derivatives
int _ballSize, _missileSize[2];
// delayed clock events // delayed clock events
enum OutputState { enum OutputState {
Sync, Sync,
@ -83,7 +86,7 @@ class Machine: public CPU6502::Processor<Machine> {
// player registers // player registers
uint8_t _playerColour[2]; uint8_t _playerColour[2];
uint8_t _playerReflection[2]; uint8_t _playerReflectionMask[2];
uint8_t _playerGraphics[2][2]; uint8_t _playerGraphics[2][2];
uint8_t _playerGraphicsSelector[2]; uint8_t _playerGraphicsSelector[2];
bool _playerStart[2]; bool _playerStart[2];
@ -92,7 +95,8 @@ class Machine: public CPU6502::Processor<Machine> {
uint8_t _playerAndMissileSize[2]; uint8_t _playerAndMissileSize[2];
// missile registers // missile registers
uint8_t _missileGraphicsEnable[2], _missileGraphicsReset[2]; uint8_t _missileGraphicsEnable[2];
bool _missileGraphicsReset[2];
// ball registers // ball registers
uint8_t _ballGraphicsEnable[2]; uint8_t _ballGraphicsEnable[2];
@ -132,6 +136,10 @@ class Machine: public CPU6502::Processor<Machine> {
unsigned int _lastOutputStateDuration; unsigned int _lastOutputStateDuration;
OutputState _lastOutputState; OutputState _lastOutputState;
uint8_t *_outputBuffer; uint8_t *_outputBuffer;
// lookup table for collision reporting
uint8_t _reportedCollisions[32][8];
void setup_reported_collisions();
}; };
} }