diff --git a/src/emucore/tia/core_6502ts/Ball.cxx b/src/emucore/tia/core_6502ts/Ball.cxx new file mode 100644 index 000000000..b59d2c721 --- /dev/null +++ b/src/emucore/tia/core_6502ts/Ball.cxx @@ -0,0 +1,153 @@ +// +// 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-2016 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. +// +// $Id$ +//============================================================================ + +#include "Ball.hxx" + +enum Count: Int8 { + renderCounterOffset = -4 +}; + +namespace TIA6502tsCore { + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Ball::Ball(uInt32 collisionMask) + : myCollisionMask(collisionMask) +{ + reset(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Ball::reset() +{ + myColor = 0; + collision = myCollisionMask; + myEnabledOld = false; + myEnabledNew = false; + myEnabled = false; + myHmmClocks = 0; + myCounter = 0; + myIsMoving = false; + myWidth = 1; + myIsRendering = false; + myRenderCounter = 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Ball::enabl(uInt8 value) +{ + myEnabledNew = (value & 0x02) > 0; + updateEnabled(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Ball::hmbl(uInt8 value) +{ + myHmmClocks = (value >> 4) ^ 0x08; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Ball::resbl(bool hblank) +{ + myCounter = hblank ? 159 : 157; + + if (!hblank) { + myIsRendering = true; + myRenderCounter = Count::renderCounterOffset; + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Ball::ctrlpf(uInt8 value) +{ + static constexpr uInt8 ourWidths[] = {1, 2, 4, 8}; + + myWidth = ourWidths[(value & 0x30) >> 4]; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Ball::vdelbl(uInt8 value) +{ + myIsDelaying = (value & 0x01) > 0; + updateEnabled(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Ball::setColor(uInt8 color) +{ + myColor = color; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Ball::startMovement() +{ + myIsMoving = true; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool Ball::movementTick(uInt32 clock, bool apply) +{ + if (clock == myHmmClocks) myIsMoving = false; + + if (myIsMoving && apply) { + render(); + tick(); + } + + return myIsMoving; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Ball::render() +{ + collision = (myIsRendering && myRenderCounter >= 0 && myEnabled) ? 0 : myCollisionMask; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Ball::tick() +{ + if (myCounter == 156) { + myIsRendering = true; + myRenderCounter = Count::renderCounterOffset; + } + else if (myIsRendering && ++myRenderCounter >= myWidth) + myIsRendering = false; + + if (++myCounter >= 160) + myCounter = 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +uInt8 Ball::getPixel(uInt8 colorIn) const +{ + return collision > 0 ? colorIn : myColor; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Ball::shuffleStatus() +{ + myEnabledOld = myEnabledNew; + updateEnabled(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Ball::updateEnabled() +{ + myEnabled = myIsDelaying ? myEnabledOld : myEnabledNew; +} + +} // namespace TIA6502tsCore \ No newline at end of file diff --git a/src/emucore/tia/core_6502ts/Ball.hxx b/src/emucore/tia/core_6502ts/Ball.hxx new file mode 100644 index 000000000..d7ac4eb2d --- /dev/null +++ b/src/emucore/tia/core_6502ts/Ball.hxx @@ -0,0 +1,99 @@ +//============================================================================ +// +// 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-2016 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. +// +// $Id$ +//============================================================================ + +#ifndef TIA_6502TS_CORE_BALL +#define TIA_6502TS_CORE_BALL + +#include "bspf.hxx" + +namespace TIA6502tsCore { + +class Ball +{ + public: + + Ball(uInt32 collisionMask); + + public: + + void reset(); + + void enabl(uInt8 value); + + void hmbl(uInt8 value); + + void resbl(bool hblank); + + void ctrlpf(uInt8 value); + + void vdelbl(uInt8 value); + + void setColor(uInt8 color); + + void startMovement(); + + bool movementTick(uInt32 clock, bool apply); + + void render(); + + void tick(); + + uInt8 getPixel(uInt8 colorIn) const; + + void shuffleStatus(); + + public: + + uInt32 collision; + + private: + + void updateEnabled(); + + private: + + uInt32 myCollisionMask; + + uInt8 myColor; + + bool myEnabledOld; + bool myEnabledNew; + bool myEnabled; + bool myIsDelaying; + + uInt8 myHmmClocks; + uInt8 myCounter; + bool myIsMoving; + uInt8 myWidth; + + bool myIsRendering; + Int8 myRenderCounter; + + private: + + Ball() = delete; + Ball(const Ball&) = delete; + Ball(Ball&&) = delete; + Ball& operator=(const Ball&) = delete; + Ball& operator=(Ball&&); +}; + +} // namespace TIA6502tsCore + +#endif // TIA_6502TS_CORE_BALL \ No newline at end of file diff --git a/src/emucore/tia/core_6502ts/Missile.cxx b/src/emucore/tia/core_6502ts/Missile.cxx index cba92a5da..ddeb89106 100644 --- a/src/emucore/tia/core_6502ts/Missile.cxx +++ b/src/emucore/tia/core_6502ts/Missile.cxx @@ -47,6 +47,7 @@ void Missile::reset() myIsRendering = false; myRenderCounter = 0; myColor = 0; + collision = myCollisionMask; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/tia/core_6502ts/Player.cxx b/src/emucore/tia/core_6502ts/Player.cxx index bcf1c55aa..aa19b8a15 100644 --- a/src/emucore/tia/core_6502ts/Player.cxx +++ b/src/emucore/tia/core_6502ts/Player.cxx @@ -48,6 +48,7 @@ void Player::reset() myPattern = 0; myIsReflected = 0; myIsDelaying = false; + collision = myCollisionMask; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/tia/core_6502ts/TIA.cxx b/src/emucore/tia/core_6502ts/TIA.cxx index c8b0786b3..4d7ae7597 100644 --- a/src/emucore/tia/core_6502ts/TIA.cxx +++ b/src/emucore/tia/core_6502ts/TIA.cxx @@ -58,7 +58,8 @@ TIA::TIA(Console& console, Sound& sound, Settings& settings) myMissile0(CollisionMask::missile0), myMissile1(CollisionMask::missile1), myPlayer0(CollisionMask::player0), - myPlayer1(CollisionMask::player1) + myPlayer1(CollisionMask::player1), + myBall(CollisionMask::ball) { myFrameManager.setHandlers( [this] () { @@ -98,6 +99,7 @@ void TIA::reset() myMissile1.reset(); myPlayer0.reset(); myPlayer1.reset(); + myBall.reset(); mySound.reset(); myDelayQueue.reset(); @@ -217,11 +219,14 @@ bool TIA::poke(uInt16 address, uInt8 value) myLinesSinceChange = 0; myPriority = (value & 0x04) ? Priority::inverted : Priority::normal; myPlayfield.ctrlpf(value); + myBall.ctrlpf(value); break; case COLUPF: myLinesSinceChange = 0; - myPlayfield.setColor(value & 0xFE); + value &= 0xFE; + myPlayfield.setColor(value); + myBall.setColor(value); break; case PF0: @@ -286,8 +291,10 @@ bool TIA::poke(uInt16 address, uInt8 value) break; case GRP1: + myLinesSinceChange = 0; myDelayQueue.push(GRP1, value, Delay::grp); myDelayQueue.push(DummyRegisters::shuffleP0, 0, Delay::shufflePlayer); + myBall.shuffleStatus(); break; case RESP0: @@ -327,6 +334,25 @@ bool TIA::poke(uInt16 address, uInt8 value) case HMP1: myDelayQueue.push(HMP1, value, Delay::hmp); break; + + case ENABL: + myLinesSinceChange = 0; + myBall.enabl(value); + break; + + case RESBL: + myLinesSinceChange = 0; + myBall.resbl(myHstate == HState::blank); + break; + + case VDELBL: + myLinesSinceChange = 0; + myBall.vdelbl(value); + break; + + case HMBL: + myDelayQueue.push(HMBL, value, Delay::hmbl); + break; } return true; @@ -556,6 +582,7 @@ void TIA::tickMovement() m = myMissile1.movementTick(myMovementClock, apply) || m; m = myPlayer0.movementTick(myMovementClock, apply) || m; m = myPlayer1.movementTick(myMovementClock, apply) || m; + m = myBall.movementTick(myMovementClock, apply) || m; myMovementInProgress = m; myCollisionUpdateRequired = m; @@ -605,7 +632,7 @@ void TIA::renderSprites() myPlayer1.render(); myMissile0.render(); myMissile1.render(); - + myBall.render(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -615,6 +642,7 @@ void TIA::tickSprites() myMissile1.tick(); myPlayer0.tick(); myPlayer1.tick(); + myBall.tick(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -644,6 +672,7 @@ void TIA::renderPixel(uInt32 x, uInt32 y, bool lineNotCached) if (myPriority == Priority::normal) { color = myPlayfield.getPixel(color); + color = myBall.getPixel(color); color = myMissile1.getPixel(color); color = myPlayer1.getPixel(color); color = myMissile0.getPixel(color); @@ -654,6 +683,7 @@ void TIA::renderPixel(uInt32 x, uInt32 y, bool lineNotCached) color = myMissile0.getPixel(color); color = myPlayer0.getPixel(color); color = myPlayfield.getPixel(color); + color = myBall.getPixel(color); } myCurrentFrameBuffer.get()[y * 160 + x] = myFrameManager.vblank() ? 0 : color; @@ -690,6 +720,7 @@ void TIA::delayedWrite(uInt8 address, uInt8 value) myMissile1.startMovement(); myPlayer0.startMovement(); myPlayer1.startMovement(); + myBall.startMovement(); break; case PF0: @@ -723,6 +754,7 @@ void TIA::delayedWrite(uInt8 address, uInt8 value) myMissile1.hmm(0); myPlayer0.hmp(0); myPlayer1.hmp(0); + myBall.hmbl(0); break; case GRP0: @@ -754,6 +786,11 @@ void TIA::delayedWrite(uInt8 address, uInt8 value) myLinesSinceChange = 0; myPlayer1.hmp(value); break; + + case HMBL: + myLinesSinceChange = 0; + myBall.hmbl(value); + break; } } diff --git a/src/emucore/tia/core_6502ts/TIA.hxx b/src/emucore/tia/core_6502ts/TIA.hxx index fd5d4f9a4..53eea1921 100644 --- a/src/emucore/tia/core_6502ts/TIA.hxx +++ b/src/emucore/tia/core_6502ts/TIA.hxx @@ -30,6 +30,7 @@ #include "Playfield.hxx" #include "Missile.hxx" #include "Player.hxx" +#include "Ball.hxx" class Console; @@ -192,6 +193,7 @@ class TIA : public AbstractTIA Missile myMissile1; Player myPlayer0; Player myPlayer1; + Ball myBall; private: TIA() = delete; diff --git a/src/emucore/tia/core_6502ts/module.mk b/src/emucore/tia/core_6502ts/module.mk index 95d07cc83..46f04145b 100644 --- a/src/emucore/tia/core_6502ts/module.mk +++ b/src/emucore/tia/core_6502ts/module.mk @@ -8,8 +8,8 @@ MODULE_OBJS := \ src/emucore/tia/core_6502ts/Playfield.o \ src/emucore/tia/core_6502ts/DrawCounterDecodes.o \ src/emucore/tia/core_6502ts/Missile.o \ - src/emucore/tia/core_6502ts/Player.o - + src/emucore/tia/core_6502ts/Player.o \ + src/emucore/tia/core_6502ts/Ball.o MODULE_DIRS += \ src/emucore/tia/core_6502ts