mirror of https://github.com/stella-emu/stella.git
Merge remote-tracking branch 'stella-emu/master'
This commit is contained in:
commit
3b0b6127cc
|
@ -306,7 +306,7 @@ int Debugger::step()
|
|||
int cyc = mySystem.cycles();
|
||||
|
||||
unlockBankswitchState();
|
||||
myOSystem.console().tia().updateScanlineByStep();
|
||||
myOSystem.console().tia().updateScanlineByStep().flushLineCache();
|
||||
lockBankswitchState();
|
||||
|
||||
return mySystem.cycles() - cyc;
|
||||
|
@ -335,7 +335,7 @@ int Debugger::trace()
|
|||
int targetPC = myCpuDebug->pc() + 3; // return address
|
||||
|
||||
unlockBankswitchState();
|
||||
myOSystem.console().tia().updateScanlineByTrace(targetPC);
|
||||
myOSystem.console().tia().updateScanlineByTrace(targetPC).flushLineCache();
|
||||
lockBankswitchState();
|
||||
|
||||
return mySystem.cycles() - cyc;
|
||||
|
@ -411,6 +411,8 @@ void Debugger::nextScanline(int lines)
|
|||
--lines;
|
||||
}
|
||||
lockBankswitchState();
|
||||
|
||||
myOSystem.console().tia().flushLineCache();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
//============================================================================
|
||||
|
||||
#include "Background.hxx"
|
||||
#include "TIA.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Background::Background()
|
||||
|
@ -33,6 +34,8 @@ void Background::reset()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Background::setColor(uInt8 color)
|
||||
{
|
||||
if (color != myObjectColor) myTIA->flushLineCache();
|
||||
|
||||
myObjectColor = color;
|
||||
applyColors();
|
||||
}
|
||||
|
@ -40,6 +43,7 @@ void Background::setColor(uInt8 color)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Background::setDebugColor(uInt8 color)
|
||||
{
|
||||
myTIA->flushLineCache();
|
||||
myDebugColor = color;
|
||||
applyColors();
|
||||
}
|
||||
|
@ -47,6 +51,7 @@ void Background::setDebugColor(uInt8 color)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Background::enableDebugColors(bool enabled)
|
||||
{
|
||||
myTIA->flushLineCache();
|
||||
myDebugEnabled = enabled;
|
||||
applyColors();
|
||||
}
|
||||
|
|
|
@ -21,12 +21,18 @@
|
|||
#include "Serializable.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
class TIA;
|
||||
|
||||
class Background : public Serializable
|
||||
{
|
||||
public:
|
||||
Background();
|
||||
|
||||
public:
|
||||
void setTIA(TIA* tia) {
|
||||
myTIA = tia;
|
||||
}
|
||||
|
||||
void reset();
|
||||
|
||||
void setColor(uInt8 color);
|
||||
|
@ -50,6 +56,8 @@ class Background : public Serializable
|
|||
uInt8 myObjectColor, myDebugColor;
|
||||
bool myDebugEnabled;
|
||||
|
||||
TIA* myTIA;
|
||||
|
||||
private:
|
||||
Background(const Background&) = delete;
|
||||
Background(Background&&) = delete;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
//============================================================================
|
||||
|
||||
#include "Ball.hxx"
|
||||
#include "TIA.hxx"
|
||||
|
||||
enum Count: Int8 {
|
||||
renderCounterOffset = -4
|
||||
|
@ -56,8 +57,14 @@ void Ball::reset()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Ball::enabl(uInt8 value)
|
||||
{
|
||||
const auto enabledNewOldValue = myIsEnabledNew;
|
||||
|
||||
myIsEnabledNew = (value & 0x02) > 0;
|
||||
updateEnabled();
|
||||
|
||||
if (myIsEnabledNew != enabledNewOldValue && !myIsDelaying) {
|
||||
myTIA->flushLineCache();
|
||||
updateEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -80,14 +87,25 @@ void Ball::ctrlpf(uInt8 value)
|
|||
{
|
||||
static constexpr uInt8 ourWidths[] = {1, 2, 4, 8};
|
||||
|
||||
myWidth = ourWidths[(value & 0x30) >> 4];
|
||||
const uInt8 newWidth = ourWidths[(value & 0x30) >> 4];
|
||||
|
||||
if (newWidth != myWidth) {
|
||||
myTIA->flushLineCache();
|
||||
myWidth = newWidth;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Ball::vdelbl(uInt8 value)
|
||||
{
|
||||
const auto oldIsDelaying = myIsDelaying;
|
||||
|
||||
myIsDelaying = (value & 0x01) > 0;
|
||||
updateEnabled();
|
||||
|
||||
if (oldIsDelaying != myIsDelaying) {
|
||||
myTIA->flushLineCache();
|
||||
updateEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -106,6 +124,8 @@ void Ball::toggleEnabled(bool enabled)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Ball::setColor(uInt8 color)
|
||||
{
|
||||
if (color != myObjectColor && myIsEnabled) myTIA->flushLineCache();
|
||||
|
||||
myObjectColor = color;
|
||||
applyColors();
|
||||
}
|
||||
|
@ -113,6 +133,8 @@ void Ball::setColor(uInt8 color)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Ball::setDebugColor(uInt8 color)
|
||||
{
|
||||
myTIA->flushLineCache();
|
||||
|
||||
myDebugColor = color;
|
||||
applyColors();
|
||||
}
|
||||
|
@ -120,6 +142,8 @@ void Ball::setDebugColor(uInt8 color)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Ball::enableDebugColors(bool enabled)
|
||||
{
|
||||
myTIA->flushLineCache();
|
||||
|
||||
myDebugEnabled = enabled;
|
||||
applyColors();
|
||||
}
|
||||
|
@ -137,25 +161,18 @@ bool Ball::movementTick(uInt32 clock, bool apply)
|
|||
|
||||
if (clock == myHmmClocks) myIsMoving = false;
|
||||
|
||||
if (myIsMoving && apply) {
|
||||
render();
|
||||
tick(false);
|
||||
}
|
||||
if (myIsMoving && apply) tick(false);
|
||||
|
||||
return myIsMoving;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Ball::render()
|
||||
void Ball::tick(bool isReceivingMclock)
|
||||
{
|
||||
collision = (myIsRendering && myRenderCounter >= 0 && myIsEnabled) ?
|
||||
myCollisionMaskEnabled :
|
||||
myCollisionMaskDisabled;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Ball::tick(bool isReceivingMclock)
|
||||
{
|
||||
bool starfieldEffect = myIsMoving && isReceivingMclock;
|
||||
|
||||
if (myCounter == 156) {
|
||||
|
@ -189,8 +206,14 @@ void Ball::tick(bool isReceivingMclock)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Ball::shuffleStatus()
|
||||
{
|
||||
const auto oldIsEnabledOld = myIsEnabledOld;
|
||||
|
||||
myIsEnabledOld = myIsEnabledNew;
|
||||
updateEnabled();
|
||||
|
||||
if (myIsEnabledOld != oldIsEnabledOld && myIsDelaying) {
|
||||
myTIA->flushLineCache();
|
||||
updateEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -209,13 +232,15 @@ void Ball::applyColors()
|
|||
uInt8 Ball::getPosition() const
|
||||
{
|
||||
// Mind the sign of renderCounterOffset: it's defined negative above
|
||||
return (316 - myCounter - Count::renderCounterOffset + myPlayfieldPositionProvider->getPosition()) % 160;
|
||||
return (316 - myCounter - Count::renderCounterOffset + myTIA->getPosition()) % 160;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Ball::setPosition(uInt8 newPosition)
|
||||
{
|
||||
myCounter = (316 - newPosition - Count::renderCounterOffset + myPlayfieldPositionProvider->getPosition()) % 160;
|
||||
myTIA->flushLineCache();
|
||||
|
||||
myCounter = (316 - newPosition - Count::renderCounterOffset + myTIA->getPosition()) % 160;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
|
||||
#include "Serializable.hxx"
|
||||
#include "bspf.hxx"
|
||||
#include "PlayfieldPositionProvider.hxx"
|
||||
|
||||
class TIA;
|
||||
|
||||
class Ball : public Serializable
|
||||
{
|
||||
|
@ -30,8 +31,8 @@ class Ball : public Serializable
|
|||
|
||||
public:
|
||||
|
||||
void setPlayfieldPositionProvider(PlayfieldPositionProvider* playfieldPositionProvider) {
|
||||
myPlayfieldPositionProvider = playfieldPositionProvider;
|
||||
void setTIA(TIA* tia) {
|
||||
myTIA = tia;
|
||||
}
|
||||
|
||||
void reset();
|
||||
|
@ -59,8 +60,6 @@ class Ball : public Serializable
|
|||
|
||||
bool movementTick(uInt32 clock, bool apply);
|
||||
|
||||
void render();
|
||||
|
||||
void tick(bool isReceivingMclock = true);
|
||||
|
||||
uInt8 getPixel(uInt8 colorIn) const {
|
||||
|
@ -113,7 +112,7 @@ class Ball : public Serializable
|
|||
bool myIsRendering;
|
||||
Int8 myRenderCounter;
|
||||
|
||||
PlayfieldPositionProvider* myPlayfieldPositionProvider;
|
||||
TIA* myTIA;
|
||||
|
||||
private:
|
||||
Ball() = delete;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "Missile.hxx"
|
||||
#include "DrawCounterDecodes.hxx"
|
||||
#include "TIA.hxx"
|
||||
|
||||
enum Count: Int8 {
|
||||
renderCounterOffset = -4
|
||||
|
@ -57,7 +58,12 @@ void Missile::reset()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Missile::enam(uInt8 value)
|
||||
{
|
||||
const auto oldEnam = myEnam;
|
||||
|
||||
myEnam = (value & 0x02) > 0;
|
||||
|
||||
if (oldEnam != myEnam) myTIA->flushLineCache();
|
||||
|
||||
updateEnabled();
|
||||
}
|
||||
|
||||
|
@ -109,8 +115,9 @@ void Missile::resmp(uInt8 value, const Player& player)
|
|||
{
|
||||
const uInt8 resmp = value & 0x02;
|
||||
|
||||
if (resmp == myResmp)
|
||||
return;
|
||||
if (resmp == myResmp) return;
|
||||
|
||||
myTIA->flushLineCache();
|
||||
|
||||
myResmp = resmp;
|
||||
|
||||
|
@ -159,28 +166,21 @@ bool Missile::movementTick(uInt8 clock, uInt8 hclock, bool apply)
|
|||
|
||||
if (clock == myHmmClocks) myIsMoving = false;
|
||||
|
||||
if (myIsMoving && apply) {
|
||||
render(hclock);
|
||||
tick(hclock);
|
||||
}
|
||||
if (myIsMoving && apply) tick(hclock);
|
||||
|
||||
return myIsMoving;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Missile::render(uInt8 hclock)
|
||||
void Missile::tick(uInt8 hclock)
|
||||
{
|
||||
bool render =
|
||||
const bool render =
|
||||
myIsRendering &&
|
||||
(myRenderCounter >= 0 || (myIsMoving && myRenderCounter == -1 && myWidth < 4 && ((hclock + 1) % 4 == 3))) &&
|
||||
myIsEnabled;
|
||||
|
||||
collision = render ? myCollisionMaskEnabled : myCollisionMaskDisabled;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Missile::tick(uInt8 hclock)
|
||||
{
|
||||
if (myDecodes[myCounter] && !myResmp) {
|
||||
myIsRendering = true;
|
||||
myRenderCounter = Count::renderCounterOffset;
|
||||
|
@ -213,6 +213,8 @@ void Missile::tick(uInt8 hclock)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Missile::setColor(uInt8 color)
|
||||
{
|
||||
if (color != myObjectColor && myIsEnabled) myTIA->flushLineCache();
|
||||
|
||||
myObjectColor = color;
|
||||
applyColors();
|
||||
}
|
||||
|
@ -220,6 +222,7 @@ void Missile::setColor(uInt8 color)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Missile::setDebugColor(uInt8 color)
|
||||
{
|
||||
myTIA->flushLineCache();
|
||||
myDebugColor = color;
|
||||
applyColors();
|
||||
}
|
||||
|
@ -247,13 +250,14 @@ void Missile::applyColors()
|
|||
uInt8 Missile::getPosition() const
|
||||
{
|
||||
// Mind the sign of renderCounterOffset: it's defined negative above
|
||||
return (316 - myCounter - Count::renderCounterOffset + myPlayfieldPositionProvider->getPosition()) % 160;
|
||||
return (316 - myCounter - Count::renderCounterOffset + myTIA->getPosition()) % 160;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Missile::setPosition(uInt8 newPosition)
|
||||
{
|
||||
myCounter = (316 - newPosition - Count::renderCounterOffset + myPlayfieldPositionProvider->getPosition()) % 160;
|
||||
myTIA->flushLineCache();
|
||||
myCounter = (316 - newPosition - Count::renderCounterOffset + myTIA->getPosition()) % 160;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
#include "Serializable.hxx"
|
||||
#include "bspf.hxx"
|
||||
#include "Player.hxx"
|
||||
#include "PlayfieldPositionProvider.hxx"
|
||||
|
||||
class TIA;
|
||||
|
||||
class Missile : public Serializable
|
||||
{
|
||||
|
@ -31,8 +32,8 @@ class Missile : public Serializable
|
|||
|
||||
public:
|
||||
|
||||
void setPlayfieldPositionProvider(PlayfieldPositionProvider* playfieldPositionProvider) {
|
||||
myPlayfieldPositionProvider = playfieldPositionProvider;
|
||||
void setTIA(TIA* tia) {
|
||||
myTIA = tia;
|
||||
}
|
||||
|
||||
void reset();
|
||||
|
@ -51,8 +52,6 @@ class Missile : public Serializable
|
|||
|
||||
bool movementTick(uInt8 clock, uInt8 hclock, bool apply);
|
||||
|
||||
void render(uInt8 hclock);
|
||||
|
||||
void tick(uInt8 hclock);
|
||||
|
||||
void setColor(uInt8 color);
|
||||
|
@ -114,7 +113,7 @@ class Missile : public Serializable
|
|||
uInt8 myObjectColor, myDebugColor;
|
||||
bool myDebugEnabled;
|
||||
|
||||
PlayfieldPositionProvider *myPlayfieldPositionProvider;
|
||||
TIA *myTIA;
|
||||
|
||||
private:
|
||||
Missile(const Missile&) = delete;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "Player.hxx"
|
||||
#include "DrawCounterDecodes.hxx"
|
||||
#include "TIA.hxx"
|
||||
|
||||
enum Count: Int8 {
|
||||
renderCounterOffset = -5,
|
||||
|
@ -63,7 +64,10 @@ void Player::grp(uInt8 pattern)
|
|||
|
||||
myPatternNew = pattern;
|
||||
|
||||
if (!myIsDelaying && myPatternNew != oldPatternNew) updatePattern();
|
||||
if (!myIsDelaying && myPatternNew != oldPatternNew) {
|
||||
myTIA->flushLineCache();
|
||||
updatePattern();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -179,7 +183,10 @@ void Player::refp(uInt8 value)
|
|||
|
||||
myIsReflected = (value & 0x08) > 0;
|
||||
|
||||
if (oldIsReflected != myIsReflected) updatePattern();
|
||||
if (oldIsReflected != myIsReflected) {
|
||||
myTIA->flushLineCache();
|
||||
updatePattern();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -189,7 +196,10 @@ void Player::vdelp(uInt8 value)
|
|||
|
||||
myIsDelaying = (value & 0x01) > 0;
|
||||
|
||||
if (oldIsDelaying != myIsDelaying) updatePattern();
|
||||
if (oldIsDelaying != myIsDelaying) {
|
||||
myTIA->flushLineCache();
|
||||
updatePattern();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -211,6 +221,8 @@ void Player::toggleCollisions(bool enabled)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Player::setColor(uInt8 color)
|
||||
{
|
||||
if (color != myObjectColor && myPattern) myTIA->flushLineCache();
|
||||
|
||||
myObjectColor = color;
|
||||
applyColors();
|
||||
}
|
||||
|
@ -218,6 +230,8 @@ void Player::setColor(uInt8 color)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Player::setDebugColor(uInt8 color)
|
||||
{
|
||||
myTIA->flushLineCache();
|
||||
|
||||
myDebugColor = color;
|
||||
applyColors();
|
||||
}
|
||||
|
@ -225,6 +239,8 @@ void Player::setDebugColor(uInt8 color)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Player::enableDebugColors(bool enabled)
|
||||
{
|
||||
myTIA->flushLineCache();
|
||||
|
||||
myDebugEnabled = enabled;
|
||||
applyColors();
|
||||
}
|
||||
|
@ -242,28 +258,19 @@ bool Player::movementTick(uInt32 clock, bool apply)
|
|||
myIsMoving = false;
|
||||
}
|
||||
|
||||
if (myIsMoving && apply) {
|
||||
render();
|
||||
tick();
|
||||
}
|
||||
if (myIsMoving && apply) tick();
|
||||
|
||||
return myIsMoving;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Player::render()
|
||||
{
|
||||
if (!myIsRendering || myRenderCounter < myRenderCounterTripPoint) {
|
||||
collision = myCollisionMaskDisabled;
|
||||
return;
|
||||
}
|
||||
|
||||
collision = (myPattern & (1 << mySampleCounter)) ? myCollisionMaskEnabled : myCollisionMaskDisabled;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Player::tick()
|
||||
{
|
||||
if (!myIsRendering || myRenderCounter < myRenderCounterTripPoint)
|
||||
collision = myCollisionMaskDisabled;
|
||||
else
|
||||
collision = (myPattern & (1 << mySampleCounter)) ? myCollisionMaskEnabled : myCollisionMaskDisabled;
|
||||
|
||||
if (myDecodes[myCounter]) {
|
||||
myIsRendering = true;
|
||||
mySampleCounter = 0;
|
||||
|
@ -304,7 +311,10 @@ void Player::shufflePatterns()
|
|||
|
||||
myPatternOld = myPatternNew;
|
||||
|
||||
if (myIsDelaying && myPatternOld != oldPatternOld) updatePattern();
|
||||
if (myIsDelaying && myPatternOld != oldPatternOld) {
|
||||
myTIA->flushLineCache();
|
||||
updatePattern();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -369,15 +379,17 @@ uInt8 Player::getPosition() const
|
|||
const uInt8 shift = myDivider == 1 ? 0 : 1;
|
||||
|
||||
// Mind the sign of renderCounterOffset: it's defined negative above
|
||||
return (316 - myCounter - Count::renderCounterOffset + shift + myPlayfieldPositionProvider->getPosition()) % 160;
|
||||
return (316 - myCounter - Count::renderCounterOffset + shift + myTIA->getPosition()) % 160;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Player::setPosition(uInt8 newPosition)
|
||||
{
|
||||
myTIA->flushLineCache();
|
||||
|
||||
const uInt8 shift = myDivider == 1 ? 0 : 1;
|
||||
|
||||
myCounter = (316 - newPosition - Count::renderCounterOffset + shift + myPlayfieldPositionProvider->getPosition()) % 160;
|
||||
myCounter = (316 - newPosition - Count::renderCounterOffset + shift + myTIA->getPosition()) % 160;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
|
||||
#include "bspf.hxx"
|
||||
#include "Serializable.hxx"
|
||||
#include "PlayfieldPositionProvider.hxx"
|
||||
|
||||
class TIA;
|
||||
|
||||
class Player : public Serializable
|
||||
{
|
||||
|
@ -29,8 +30,8 @@ class Player : public Serializable
|
|||
|
||||
public:
|
||||
|
||||
void setPlayfieldPositionProvider(PlayfieldPositionProvider* playfieldPositionProvider) {
|
||||
myPlayfieldPositionProvider = playfieldPositionProvider;
|
||||
void setTIA(TIA* tia) {
|
||||
myTIA = tia;
|
||||
}
|
||||
|
||||
void reset();
|
||||
|
@ -60,8 +61,6 @@ class Player : public Serializable
|
|||
|
||||
bool movementTick(uInt32 clock, bool apply);
|
||||
|
||||
void render();
|
||||
|
||||
void tick();
|
||||
uInt8 getClock() const { return myCounter; }
|
||||
|
||||
|
@ -126,7 +125,7 @@ class Player : public Serializable
|
|||
bool myIsReflected;
|
||||
bool myIsDelaying;
|
||||
|
||||
PlayfieldPositionProvider *myPlayfieldPositionProvider;
|
||||
TIA* myTIA;
|
||||
|
||||
private:
|
||||
Player(const Player&) = delete;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
//============================================================================
|
||||
|
||||
#include "Playfield.hxx"
|
||||
#include "TIA.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Playfield::Playfield(uInt32 collisionMask)
|
||||
|
@ -52,8 +53,12 @@ void Playfield::reset()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Playfield::pf0(uInt8 value)
|
||||
{
|
||||
if (myPf0 == value >> 4) return;
|
||||
|
||||
myTIA->flushLineCache();
|
||||
|
||||
myPattern = (myPattern & 0x000FFFF0) | (value >> 4);
|
||||
myPf0 = value;
|
||||
myPf0 = value >> 4;
|
||||
|
||||
updatePattern();
|
||||
}
|
||||
|
@ -61,6 +66,10 @@ void Playfield::pf0(uInt8 value)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Playfield::pf1(uInt8 value)
|
||||
{
|
||||
if (myPf1 == value) return;
|
||||
|
||||
myTIA->flushLineCache();
|
||||
|
||||
myPattern = (myPattern & 0x000FF00F)
|
||||
| ((value & 0x80) >> 3)
|
||||
| ((value & 0x40) >> 1)
|
||||
|
@ -78,6 +87,10 @@ void Playfield::pf1(uInt8 value)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Playfield::pf2(uInt8 value)
|
||||
{
|
||||
if (myPf2 == value) return;
|
||||
|
||||
myTIA->flushLineCache();
|
||||
|
||||
myPattern = (myPattern & 0x00000FFF) | (value << 12);
|
||||
myPf2 = value;
|
||||
|
||||
|
@ -87,8 +100,15 @@ void Playfield::pf2(uInt8 value)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Playfield::ctrlpf(uInt8 value)
|
||||
{
|
||||
myReflected = (value & 0x01) > 0;
|
||||
myColorMode = (value & 0x06) == 0x02 ? ColorMode::score : ColorMode::normal;
|
||||
const bool reflected = (value & 0x01) > 0;
|
||||
const ColorMode colorMode = (value & 0x06) == 0x02 ? ColorMode::score : ColorMode::normal;
|
||||
|
||||
if (myReflected == reflected && myColorMode == colorMode) return;
|
||||
|
||||
myTIA->flushLineCache();
|
||||
|
||||
myReflected = reflected;
|
||||
myColorMode = colorMode;
|
||||
applyColors();
|
||||
}
|
||||
|
||||
|
@ -109,6 +129,8 @@ void Playfield::toggleCollisions(bool enabled)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Playfield::setColor(uInt8 color)
|
||||
{
|
||||
if (color != myObjectColor && myColorMode == ColorMode::normal) myTIA->flushLineCache();
|
||||
|
||||
myObjectColor = color;
|
||||
applyColors();
|
||||
}
|
||||
|
@ -116,6 +138,8 @@ void Playfield::setColor(uInt8 color)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Playfield::setColorP0(uInt8 color)
|
||||
{
|
||||
if (color != myColorP0 && myColorMode == ColorMode::score) myTIA->flushLineCache();
|
||||
|
||||
myColorP0 = color;
|
||||
applyColors();
|
||||
}
|
||||
|
@ -123,6 +147,8 @@ void Playfield::setColorP0(uInt8 color)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Playfield::setColorP1(uInt8 color)
|
||||
{
|
||||
if (color != myColorP1 && myColorMode == ColorMode::score) myTIA->flushLineCache();
|
||||
|
||||
myColorP1 = color;
|
||||
applyColors();
|
||||
}
|
||||
|
@ -130,6 +156,7 @@ void Playfield::setColorP1(uInt8 color)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Playfield::setDebugColor(uInt8 color)
|
||||
{
|
||||
myTIA->flushLineCache();
|
||||
myDebugColor = color;
|
||||
applyColors();
|
||||
}
|
||||
|
@ -137,6 +164,7 @@ void Playfield::setDebugColor(uInt8 color)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Playfield::enableDebugColors(bool enabled)
|
||||
{
|
||||
myTIA->flushLineCache();
|
||||
myDebugEnabled = enabled;
|
||||
applyColors();
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "Serializable.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
class TIA;
|
||||
|
||||
class Playfield : public Serializable
|
||||
{
|
||||
public:
|
||||
|
@ -28,6 +30,10 @@ class Playfield : public Serializable
|
|||
|
||||
public:
|
||||
|
||||
void setTIA(TIA* tia) {
|
||||
myTIA = tia;
|
||||
}
|
||||
|
||||
void reset();
|
||||
|
||||
void pf0(uInt8 value);
|
||||
|
@ -105,6 +111,8 @@ class Playfield : public Serializable
|
|||
|
||||
uInt32 myX;
|
||||
|
||||
TIA* myTIA;
|
||||
|
||||
private:
|
||||
Playfield() = delete;
|
||||
Playfield(const Playfield&) = delete;
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef TIA_PLAYFIELD_PROVIDER
|
||||
#define TIA_PLAYFIELD_PROVIDER
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
||||
/**
|
||||
This is an abstract interface class that provides a subset of TIA
|
||||
functionality for sprite positioning while avoiding circular dependencies
|
||||
between TIA and sprites.
|
||||
|
||||
@author Christian Speckner (DirtyHairy) and Stephen Anthony
|
||||
*/
|
||||
class PlayfieldPositionProvider
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Get the current x value
|
||||
*/
|
||||
virtual uInt8 getPosition() const = 0;
|
||||
|
||||
protected:
|
||||
~PlayfieldPositionProvider() = default;
|
||||
|
||||
};
|
||||
|
||||
#endif // TIA_POSITIONING_PROVIDER
|
|
@ -95,11 +95,13 @@ TIA::TIA(Console& console, Sound& sound, Settings& settings)
|
|||
|
||||
myTIAPinsDriven = mySettings.getBool("tiadriven");
|
||||
|
||||
myPlayer0.setPlayfieldPositionProvider(this);
|
||||
myPlayer1.setPlayfieldPositionProvider(this);
|
||||
myMissile0.setPlayfieldPositionProvider(this);
|
||||
myMissile1.setPlayfieldPositionProvider(this);
|
||||
myBall.setPlayfieldPositionProvider(this);
|
||||
myBackground.setTIA(this);
|
||||
myPlayfield.setTIA(this);
|
||||
myPlayer0.setTIA(this);
|
||||
myPlayer1.setTIA(this);
|
||||
myMissile0.setTIA(this);
|
||||
myMissile1.setTIA(this);
|
||||
myBall.setTIA(this);
|
||||
|
||||
reset();
|
||||
}
|
||||
|
@ -114,7 +116,6 @@ void TIA::reset()
|
|||
myMovementClock = 0;
|
||||
myPriority = Priority::normal;
|
||||
myHstate = HState::blank;
|
||||
myIsFreshLine = true;
|
||||
myCollisionMask = 0;
|
||||
myLinesSinceChange = 0;
|
||||
myCollisionUpdateRequired = false;
|
||||
|
@ -223,7 +224,6 @@ bool TIA::save(Serializer& out) const
|
|||
out.putBool(myTIAPinsDriven);
|
||||
|
||||
out.putInt(int(myHstate));
|
||||
out.putBool(myIsFreshLine);
|
||||
|
||||
out.putInt(myHblankCtr);
|
||||
out.putInt(myHctr);
|
||||
|
@ -293,7 +293,6 @@ bool TIA::load(Serializer& in)
|
|||
myTIAPinsDriven = in.getBool();
|
||||
|
||||
myHstate = HState(in.getInt());
|
||||
myIsFreshLine = in.getBool();
|
||||
|
||||
myHblankCtr = in.getInt();
|
||||
myHctr = in.getInt();
|
||||
|
@ -443,6 +442,7 @@ bool TIA::poke(uInt16 address, uInt8 value)
|
|||
break;
|
||||
|
||||
case RSYNC:
|
||||
flushLineCache();
|
||||
applyRsync();
|
||||
myShadowRegisters[address] = value;
|
||||
break;
|
||||
|
@ -496,13 +496,11 @@ bool TIA::poke(uInt16 address, uInt8 value)
|
|||
break;
|
||||
|
||||
case COLUBK:
|
||||
myLinesSinceChange = 0;
|
||||
myBackground.setColor(value & 0xFE);
|
||||
myShadowRegisters[address] = value;
|
||||
break;
|
||||
|
||||
case COLUP0:
|
||||
myLinesSinceChange = 0;
|
||||
value &= 0xFE;
|
||||
myPlayfield.setColorP0(value);
|
||||
myMissile0.setColor(value);
|
||||
|
@ -511,7 +509,6 @@ bool TIA::poke(uInt16 address, uInt8 value)
|
|||
break;
|
||||
|
||||
case COLUP1:
|
||||
myLinesSinceChange = 0;
|
||||
value &= 0xFE;
|
||||
myPlayfield.setColorP1(value);
|
||||
myMissile1.setColor(value);
|
||||
|
@ -520,7 +517,7 @@ bool TIA::poke(uInt16 address, uInt8 value)
|
|||
break;
|
||||
|
||||
case CTRLPF:
|
||||
myLinesSinceChange = 0;
|
||||
flushLineCache();
|
||||
myPriority = (value & 0x04) ? Priority::pfp :
|
||||
(value & 0x02) ? Priority::score : Priority::normal;
|
||||
myPlayfield.ctrlpf(value);
|
||||
|
@ -529,7 +526,7 @@ bool TIA::poke(uInt16 address, uInt8 value)
|
|||
break;
|
||||
|
||||
case COLUPF:
|
||||
myLinesSinceChange = 0;
|
||||
flushLineCache();
|
||||
value &= 0xFE;
|
||||
myPlayfield.setColor(value);
|
||||
myBall.setColor(value);
|
||||
|
@ -578,38 +575,36 @@ bool TIA::poke(uInt16 address, uInt8 value)
|
|||
break;
|
||||
|
||||
case RESM0:
|
||||
myLinesSinceChange = 0;
|
||||
flushLineCache();
|
||||
myMissile0.resm(resxCounter(), myHstate == HState::blank);
|
||||
myShadowRegisters[address] = value;
|
||||
break;
|
||||
|
||||
case RESM1:
|
||||
myLinesSinceChange = 0;
|
||||
flushLineCache();
|
||||
myMissile1.resm(resxCounter(), myHstate == HState::blank);
|
||||
myShadowRegisters[address] = value;
|
||||
break;
|
||||
|
||||
case RESMP0:
|
||||
myLinesSinceChange = 0;
|
||||
myMissile0.resmp(value, myPlayer0);
|
||||
myShadowRegisters[address] = value;
|
||||
break;
|
||||
|
||||
case RESMP1:
|
||||
myLinesSinceChange = 0;
|
||||
myMissile1.resmp(value, myPlayer1);
|
||||
myShadowRegisters[address] = value;
|
||||
break;
|
||||
|
||||
case NUSIZ0:
|
||||
myLinesSinceChange = 0;
|
||||
flushLineCache();
|
||||
myMissile0.nusiz(value);
|
||||
myPlayer0.nusiz(value, myHstate == HState::blank);
|
||||
myShadowRegisters[address] = value;
|
||||
break;
|
||||
|
||||
case NUSIZ1:
|
||||
myLinesSinceChange = 0;
|
||||
flushLineCache();
|
||||
myMissile1.nusiz(value);
|
||||
myPlayer1.nusiz(value, myHstate == HState::blank);
|
||||
myShadowRegisters[address] = value;
|
||||
|
@ -653,13 +648,13 @@ bool TIA::poke(uInt16 address, uInt8 value)
|
|||
}
|
||||
|
||||
case RESP0:
|
||||
myLinesSinceChange = 0;
|
||||
flushLineCache();
|
||||
myPlayer0.resp(resxCounter());
|
||||
myShadowRegisters[address] = value;
|
||||
break;
|
||||
|
||||
case RESP1:
|
||||
myLinesSinceChange = 0;
|
||||
flushLineCache();
|
||||
myPlayer1.resp(resxCounter());
|
||||
myShadowRegisters[address] = value;
|
||||
break;
|
||||
|
@ -673,13 +668,11 @@ bool TIA::poke(uInt16 address, uInt8 value)
|
|||
break;
|
||||
|
||||
case VDELP0:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer0.vdelp(value);
|
||||
myShadowRegisters[address] = value;
|
||||
break;
|
||||
|
||||
case VDELP1:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer1.vdelp(value);
|
||||
myShadowRegisters[address] = value;
|
||||
break;
|
||||
|
@ -697,13 +690,12 @@ bool TIA::poke(uInt16 address, uInt8 value)
|
|||
break;
|
||||
|
||||
case RESBL:
|
||||
myLinesSinceChange = 0;
|
||||
flushLineCache();
|
||||
myBall.resbl(resxCounter());
|
||||
myShadowRegisters[address] = value;
|
||||
break;
|
||||
|
||||
case VDELBL:
|
||||
myLinesSinceChange = 0;
|
||||
myBall.vdelbl(value);
|
||||
myShadowRegisters[address] = value;
|
||||
break;
|
||||
|
@ -713,7 +705,7 @@ bool TIA::poke(uInt16 address, uInt8 value)
|
|||
break;
|
||||
|
||||
case CXCLR:
|
||||
myLinesSinceChange = 0;
|
||||
flushLineCache();
|
||||
myCollisionMask = 0;
|
||||
myShadowRegisters[address] = value;
|
||||
break;
|
||||
|
@ -913,27 +905,33 @@ void TIA::setJitterRecoveryFactor(Int32 f)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIA::updateScanline()
|
||||
TIA& TIA::updateScanline()
|
||||
{
|
||||
// Update frame by one scanline at a time
|
||||
uInt32 line = scanlines();
|
||||
while (line == scanlines())
|
||||
updateScanlineByStep();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIA::updateScanlineByStep()
|
||||
TIA& TIA::updateScanlineByStep()
|
||||
{
|
||||
// Update frame by one CPU instruction/color clock
|
||||
mySystem->m6502().execute(1);
|
||||
updateEmulation();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIA::updateScanlineByTrace(int target)
|
||||
TIA& TIA::updateScanlineByTrace(int target)
|
||||
{
|
||||
while (mySystem->m6502().getPC() != target)
|
||||
updateScanlineByStep();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1005,18 +1003,20 @@ void TIA::cycle(uInt32 colorClocks)
|
|||
|
||||
myCollisionUpdateRequired = false;
|
||||
|
||||
tickMovement();
|
||||
if (myLinesSinceChange < 2) {
|
||||
tickMovement();
|
||||
|
||||
if (myHstate == HState::blank)
|
||||
tickHblank();
|
||||
else
|
||||
tickHframe();
|
||||
if (myHstate == HState::blank)
|
||||
tickHblank();
|
||||
else
|
||||
tickHframe();
|
||||
|
||||
if (myCollisionUpdateRequired) updateCollision();
|
||||
}
|
||||
|
||||
if (++myHctr >= 228)
|
||||
nextLine();
|
||||
|
||||
if (myCollisionUpdateRequired) updateCollision();
|
||||
|
||||
myTimestamp++;
|
||||
}
|
||||
}
|
||||
|
@ -1027,8 +1027,6 @@ void TIA::tickMovement()
|
|||
if (!myMovementInProgress) return;
|
||||
|
||||
if ((myHctr & 0x03) == 0) {
|
||||
myLinesSinceChange = 0;
|
||||
|
||||
const bool apply = myHstate == HState::blank;
|
||||
bool m = false;
|
||||
uInt8 movementCounter = myMovementClock > 15 ? 0 : myMovementClock;
|
||||
|
@ -1049,9 +1047,8 @@ void TIA::tickMovement()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIA::tickHblank()
|
||||
{
|
||||
if (myIsFreshLine) {
|
||||
if (myHctr == 0) {
|
||||
myHblankCtr = 0;
|
||||
myIsFreshLine = false;
|
||||
}
|
||||
|
||||
if (++myHblankCtr >= 68) myHstate = HState::frame;
|
||||
|
@ -1061,23 +1058,11 @@ void TIA::tickHblank()
|
|||
void TIA::tickHframe()
|
||||
{
|
||||
const uInt32 y = myFrameManager.getY();
|
||||
const bool lineNotCached = myLinesSinceChange < 2 || y == 0;
|
||||
const uInt32 x = myHctr - 68 - myXDelta;
|
||||
|
||||
myCollisionUpdateRequired = lineNotCached;
|
||||
myCollisionUpdateRequired = true;
|
||||
|
||||
myPlayfield.tick(x);
|
||||
|
||||
// Render sprites
|
||||
if (lineNotCached) {
|
||||
myPlayer0.render();
|
||||
myPlayer1.render();
|
||||
myMissile0.render(myHctr);
|
||||
myMissile1.render(myHctr);
|
||||
myBall.render();
|
||||
}
|
||||
|
||||
// Tick sprites
|
||||
myMissile0.tick(myHctr);
|
||||
myMissile1.tick(myHctr);
|
||||
myPlayer0.tick();
|
||||
|
@ -1085,7 +1070,7 @@ void TIA::tickHframe()
|
|||
myBall.tick();
|
||||
|
||||
if (myFrameManager.isRendering())
|
||||
renderPixel(x, y, lineNotCached);
|
||||
renderPixel(x, y);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1097,22 +1082,39 @@ void TIA::applyRsync()
|
|||
if (myFrameManager.isRendering())
|
||||
memset(myCurrentFrameBuffer.get() + myFrameManager.getY() * 160 + x, 0, 160 - x);
|
||||
|
||||
myLinesSinceChange = 0;
|
||||
myHctr = 225;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIA::nextLine()
|
||||
{
|
||||
if (myLinesSinceChange >= 2) {
|
||||
cloneLastLine();
|
||||
}
|
||||
|
||||
myHctr = 0;
|
||||
myLinesSinceChange++;
|
||||
|
||||
if (!myMovementInProgress && myLinesSinceChange < 2) myLinesSinceChange++;
|
||||
|
||||
myHstate = HState::blank;
|
||||
myIsFreshLine = true;
|
||||
myExtendedHblank = false;
|
||||
myXDelta = 0;
|
||||
|
||||
myFrameManager.nextLine();
|
||||
|
||||
if (myFrameManager.isRendering() && myFrameManager.getY() == 0) flushLineCache();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIA::cloneLastLine()
|
||||
{
|
||||
const auto y = myFrameManager.getY();
|
||||
|
||||
if (!myFrameManager.isRendering() || y == 0) return;
|
||||
|
||||
uInt8* buffer = myCurrentFrameBuffer.get();
|
||||
|
||||
memcpy(buffer + y * 160, buffer + (y-1) * 160, 160);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1129,58 +1131,73 @@ void TIA::updateCollision()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIA::renderPixel(uInt32 x, uInt32 y, bool lineNotCached)
|
||||
void TIA::renderPixel(uInt32 x, uInt32 y)
|
||||
{
|
||||
if (x >= 160) return;
|
||||
|
||||
if (lineNotCached) {
|
||||
uInt8 color = myBackground.getColor();
|
||||
uInt8 color = myBackground.getColor();
|
||||
|
||||
switch (myPriority)
|
||||
{
|
||||
// Playfield has priority so ScoreBit isn't used
|
||||
// Priority from highest to lowest:
|
||||
// BL/PF => P0/M0 => P1/M1 => BK
|
||||
case Priority::pfp: // CTRLPF D2=1, D1=ignored
|
||||
color = myMissile1.getPixel(color);
|
||||
color = myPlayer1.getPixel(color);
|
||||
color = myMissile0.getPixel(color);
|
||||
color = myPlayer0.getPixel(color);
|
||||
color = myPlayfield.getPixel(color);
|
||||
color = myBall.getPixel(color);
|
||||
break;
|
||||
switch (myPriority)
|
||||
{
|
||||
// Playfield has priority so ScoreBit isn't used
|
||||
// Priority from highest to lowest:
|
||||
// BL/PF => P0/M0 => P1/M1 => BK
|
||||
case Priority::pfp: // CTRLPF D2=1, D1=ignored
|
||||
color = myMissile1.getPixel(color);
|
||||
color = myPlayer1.getPixel(color);
|
||||
color = myMissile0.getPixel(color);
|
||||
color = myPlayer0.getPixel(color);
|
||||
color = myPlayfield.getPixel(color);
|
||||
color = myBall.getPixel(color);
|
||||
break;
|
||||
|
||||
case Priority::score: // CTRLPF D2=0, D1=1
|
||||
// Formally we have (priority from highest to lowest)
|
||||
// PF/P0/M0 => P1/M1 => BL => BK
|
||||
// for the first half and
|
||||
// P0/M0 => PF/P1/M1 => BL => BK
|
||||
// for the second half. However, the first ordering is equivalent
|
||||
// to the second (PF has the same color as P0/M0), so we can just
|
||||
// write
|
||||
color = myBall.getPixel(color);
|
||||
color = myMissile1.getPixel(color);
|
||||
color = myPlayer1.getPixel(color);
|
||||
color = myPlayfield.getPixel(color);
|
||||
color = myMissile0.getPixel(color);
|
||||
color = myPlayer0.getPixel(color);
|
||||
break;
|
||||
case Priority::score: // CTRLPF D2=0, D1=1
|
||||
// Formally we have (priority from highest to lowest)
|
||||
// PF/P0/M0 => P1/M1 => BL => BK
|
||||
// for the first half and
|
||||
// P0/M0 => PF/P1/M1 => BL => BK
|
||||
// for the second half. However, the first ordering is equivalent
|
||||
// to the second (PF has the same color as P0/M0), so we can just
|
||||
// write
|
||||
color = myBall.getPixel(color);
|
||||
color = myMissile1.getPixel(color);
|
||||
color = myPlayer1.getPixel(color);
|
||||
color = myPlayfield.getPixel(color);
|
||||
color = myMissile0.getPixel(color);
|
||||
color = myPlayer0.getPixel(color);
|
||||
break;
|
||||
|
||||
// Priority from highest to lowest:
|
||||
// P0/M0 => P1/M1 => BL/PF => BK
|
||||
case Priority::normal: // CTRLPF D2=0, D1=0
|
||||
color = myPlayfield.getPixel(color);
|
||||
color = myBall.getPixel(color);
|
||||
color = myMissile1.getPixel(color);
|
||||
color = myPlayer1.getPixel(color);
|
||||
color = myMissile0.getPixel(color);
|
||||
color = myPlayer0.getPixel(color);
|
||||
break;
|
||||
// Priority from highest to lowest:
|
||||
// P0/M0 => P1/M1 => BL/PF => BK
|
||||
case Priority::normal: // CTRLPF D2=0, D1=0
|
||||
color = myPlayfield.getPixel(color);
|
||||
color = myBall.getPixel(color);
|
||||
color = myMissile1.getPixel(color);
|
||||
color = myPlayer1.getPixel(color);
|
||||
color = myMissile0.getPixel(color);
|
||||
color = myPlayer0.getPixel(color);
|
||||
break;
|
||||
}
|
||||
|
||||
myCurrentFrameBuffer.get()[y * 160 + x] = myFrameManager.vblank() ? 0 : color;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIA::flushLineCache()
|
||||
{
|
||||
const bool wasCaching = myLinesSinceChange >= 2;
|
||||
|
||||
myLinesSinceChange = 0;
|
||||
|
||||
if (wasCaching) {
|
||||
const auto rewindCycles = myHctr;
|
||||
|
||||
for (myHctr = 0; myHctr < rewindCycles; myHctr++) {
|
||||
if (myHstate == HState::blank)
|
||||
tickHblank();
|
||||
else
|
||||
tickHframe();
|
||||
}
|
||||
|
||||
myCurrentFrameBuffer.get()[y * 160 + x] = myFrameManager.vblank() ? 0 : color;
|
||||
} else {
|
||||
myCurrentFrameBuffer.get()[y * 160 + x] = myCurrentFrameBuffer.get()[(y-1) * 160 + x];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1201,12 +1218,12 @@ void TIA::delayedWrite(uInt8 address, uInt8 value)
|
|||
switch (address)
|
||||
{
|
||||
case VBLANK:
|
||||
myLinesSinceChange = 0;
|
||||
flushLineCache();
|
||||
myFrameManager.setVblank(value & 0x02);
|
||||
break;
|
||||
|
||||
case HMOVE:
|
||||
myLinesSinceChange = 0;
|
||||
flushLineCache();
|
||||
|
||||
myMovementClock = 0;
|
||||
myMovementInProgress = true;
|
||||
|
@ -1225,32 +1242,26 @@ void TIA::delayedWrite(uInt8 address, uInt8 value)
|
|||
break;
|
||||
|
||||
case PF0:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayfield.pf0(value);
|
||||
break;
|
||||
|
||||
case PF1:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayfield.pf1(value);
|
||||
break;
|
||||
|
||||
case PF2:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayfield.pf2(value);
|
||||
break;
|
||||
|
||||
case HMM0:
|
||||
myLinesSinceChange = 0;
|
||||
myMissile0.hmm(value);
|
||||
break;
|
||||
|
||||
case HMM1:
|
||||
myLinesSinceChange = 0;
|
||||
myMissile1.hmm(value);
|
||||
break;
|
||||
|
||||
case HMCLR:
|
||||
myLinesSinceChange = 0;
|
||||
myMissile0.hmm(0);
|
||||
myMissile1.hmm(0);
|
||||
myPlayer0.hmp(0);
|
||||
|
@ -1259,67 +1270,54 @@ void TIA::delayedWrite(uInt8 address, uInt8 value)
|
|||
break;
|
||||
|
||||
case GRP0:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer0.grp(value);
|
||||
break;
|
||||
|
||||
case GRP1:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer1.grp(value);
|
||||
break;
|
||||
|
||||
case DummyRegisters::shuffleP0:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer0.shufflePatterns();
|
||||
break;
|
||||
|
||||
case DummyRegisters::shuffleP1:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer1.shufflePatterns();
|
||||
break;
|
||||
|
||||
case DummyRegisters::shuffleBL:
|
||||
myLinesSinceChange = 0;
|
||||
myBall.shuffleStatus();
|
||||
break;
|
||||
|
||||
case HMP0:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer0.hmp(value);
|
||||
break;
|
||||
|
||||
case HMP1:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer1.hmp(value);
|
||||
break;
|
||||
|
||||
case HMBL:
|
||||
myLinesSinceChange = 0;
|
||||
myBall.hmbl(value);
|
||||
break;
|
||||
|
||||
case REFP0:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer0.refp(value);
|
||||
break;
|
||||
|
||||
case REFP1:
|
||||
myLinesSinceChange = 0;
|
||||
myPlayer1.refp(value);
|
||||
break;
|
||||
|
||||
case ENABL:
|
||||
myLinesSinceChange = 0;
|
||||
myBall.enabl(value);
|
||||
break;
|
||||
|
||||
case ENAM0:
|
||||
myLinesSinceChange = 0;
|
||||
myMissile0.enam(value);
|
||||
break;
|
||||
|
||||
case ENAM1:
|
||||
myLinesSinceChange = 0;
|
||||
myMissile1.enam(value);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include "Ball.hxx"
|
||||
#include "LatchedInput.hxx"
|
||||
#include "PaddleReader.hxx"
|
||||
#include "PlayfieldPositionProvider.hxx"
|
||||
|
||||
/**
|
||||
This class is a device that emulates the Television Interface Adaptor
|
||||
|
@ -50,7 +49,7 @@
|
|||
|
||||
@author Christian Speckner (DirtyHairy) and Stephen Anthony
|
||||
*/
|
||||
class TIA : public Device, public PlayfieldPositionProvider
|
||||
class TIA : public Device
|
||||
{
|
||||
public:
|
||||
friend class TIADebug;
|
||||
|
@ -295,19 +294,19 @@ class TIA : public Device, public PlayfieldPositionProvider
|
|||
/**
|
||||
This method should be called to update the TIA with a new scanline.
|
||||
*/
|
||||
void updateScanline();
|
||||
TIA& updateScanline();
|
||||
|
||||
/**
|
||||
This method should be called to update the TIA with a new partial
|
||||
scanline by stepping one CPU instruction.
|
||||
*/
|
||||
void updateScanlineByStep();
|
||||
TIA& updateScanlineByStep();
|
||||
|
||||
/**
|
||||
This method should be called to update the TIA with a new partial
|
||||
scanline by tracing to target address.
|
||||
*/
|
||||
void updateScanlineByTrace(int target);
|
||||
TIA& updateScanlineByTrace(int target);
|
||||
|
||||
/**
|
||||
Retrieve the last value written to a certain register
|
||||
|
@ -317,10 +316,16 @@ class TIA : public Device, public PlayfieldPositionProvider
|
|||
/**
|
||||
Get the current x value
|
||||
*/
|
||||
uInt8 getPosition() const override {
|
||||
uInt8 getPosition() const {
|
||||
return (myHctr < 68) ? 0 : (myHctr - 68 - myXDelta);
|
||||
}
|
||||
|
||||
/**
|
||||
Flush the line cache after an externally triggered state change
|
||||
(e.g. a register write)
|
||||
*/
|
||||
void flushLineCache();
|
||||
|
||||
/**
|
||||
Save the current state of this device to the given Serializer.
|
||||
|
||||
|
@ -388,12 +393,14 @@ class TIA : public Device, public PlayfieldPositionProvider
|
|||
|
||||
void updateCollision();
|
||||
|
||||
void renderPixel(uInt32 x, uInt32 y, bool lineNotCached);
|
||||
void renderPixel(uInt32 x, uInt32 y);
|
||||
|
||||
void clearHmoveComb();
|
||||
|
||||
void nextLine();
|
||||
|
||||
void cloneLastLine();
|
||||
|
||||
void delayedWrite(uInt8 address, uInt8 value);
|
||||
|
||||
void updatePaddle(uInt8 idx);
|
||||
|
@ -442,7 +449,6 @@ class TIA : public Device, public PlayfieldPositionProvider
|
|||
bool myTIAPinsDriven;
|
||||
|
||||
HState myHstate;
|
||||
bool myIsFreshLine;
|
||||
|
||||
Int32 myHblankCtr;
|
||||
Int32 myHctr;
|
||||
|
|
Loading…
Reference in New Issue