Add players.

This commit is contained in:
Christian Speckner 2016-11-20 22:07:10 +01:00
parent 87b24a5bba
commit ac4520917e
6 changed files with 495 additions and 6 deletions

View File

@ -20,7 +20,7 @@
#include "Missile.hxx"
#include "DrawCounterDecodes.hxx"
enum Count {
enum Count : Int8 {
renderCounterOffset = -4
};

View File

@ -0,0 +1,258 @@
//============================================================================
//
// 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 "Player.hxx"
#include "DrawCounterDecodes.hxx"
enum Count : Int8 {
renderCounterOffset = -5
};
namespace TIA6502tsCore {
Player::Player(uInt32 collisionMask)
: myCollisionMask(collisionMask)
{
reset();
}
void Player::reset()
{
myDecodes = DrawCounterDecodes::get().playerDecodes()[0];
myHmmClocks = 0;
myCounter = 0;
myIsMoving = false;
myWidth = 1;
myIsRendering = false;
myRenderCounter = 0;
myPatternOld = 0;
myPatternNew = 0;
myPattern = 0;
myIsReflected = 0;
myIsDelaying = false;
}
void Player::grp(uInt8 pattern)
{
myPatternNew = pattern;
if (!myIsDelaying) updatePattern();
}
void Player::hmp(uInt8 value)
{
myHmmClocks = (value >> 4) ^ 0x8;
}
void Player::nusiz(uInt8 value)
{
const uInt8 masked = value & 0x07;
const uInt8 oldWidth = myWidth;
if (masked == 5) {
myWidth = 16;
} else if (masked == 7) {
myWidth = 32;
} else {
myWidth = 8;
}
myDecodes = DrawCounterDecodes::get().playerDecodes()[masked];
if (myIsRendering && myRenderCounter >= myWidth)
myIsRendering = false;
if (oldWidth != myWidth) updatePattern();
}
void Player::resp(bool hblank)
{
myCounter = hblank ? 159 : 157;
}
void Player::refp(uInt8 value)
{
const bool oldIsReflected = myIsReflected;
myIsReflected = (value & 0x08) > 0;
if (myIsReflected != oldIsReflected) updatePattern();
}
void Player::vdelp(uInt8 value)
{
const bool oldIsDelaying = myIsDelaying;
myIsDelaying = (value & 0x01) > 0;
if (myIsDelaying != oldIsDelaying) updatePattern();
}
void Player::setColor(uInt8 color)
{
myColor = color;
}
void Player::startMovement()
{
myIsMoving = true;
}
bool Player::movementTick(uInt32 clock, bool apply)
{
if (clock == myHmmClocks) {
myIsMoving = false;
}
if (myIsMoving && apply) {
render();
tick();
}
return myIsMoving;
}
void Player::render()
{
collision = (
myIsRendering &&
myRenderCounter >= 0 &&
(myPattern & (1 << (myWidth - myRenderCounter - 1)))
) ? 0 : myCollisionMask;
}
void Player::tick()
{
if (myDecodes[myCounter]) {
myIsRendering = true;
myRenderCounter = Count::renderCounterOffset;
} else if (myIsRendering && ++myRenderCounter >= myWidth) {
myIsRendering = false;
}
if (++myCounter >= 160) myCounter = 0;
}
uInt8 Player::getPixel(uInt8 colorIn) const
{
return collision ? colorIn : myColor;
}
void Player::shufflePatterns()
{
const uInt8 oldPatternOld = myPatternOld;
myPatternOld = myPatternNew;
if (myIsDelaying && oldPatternOld != myPatternOld) updatePattern();
}
uInt8 Player::getRespClock() const
{
switch (myWidth) {
case 8:
return myCounter - 3;
case 16:
return myCounter - 6;
case 32:
return myCounter - 10;
default:
throw runtime_error("invalid width");
}
}
void Player::updatePattern()
{
const uInt32 pattern = myIsDelaying ? myPatternOld : myPatternNew;
switch (myWidth) {
case 8:
if (myIsReflected) {
myPattern =
((pattern & 0x01) << 7) |
((pattern & 0x02) << 5) |
((pattern & 0x04) << 3) |
((pattern & 0x08) << 1) |
((pattern & 0x10) >> 1) |
((pattern & 0x20) >> 3) |
((pattern & 0x40) >> 5) |
((pattern & 0x80) >> 7);
} else {
myPattern = pattern;
}
break;
case 16:
if (myIsReflected) {
myPattern =
((3 * (pattern & 0x01)) << 14) |
((3 * (pattern & 0x02)) << 11) |
((3 * (pattern & 0x04)) << 8) |
((3 * (pattern & 0x08)) << 5) |
((3 * (pattern & 0x10)) << 2) |
((3 * (pattern & 0x20)) >> 1) |
((3 * (pattern & 0x40)) >> 4) |
((3 * (pattern & 0x80)) >> 7);
} else {
myPattern =
((3 * (pattern & 0x01))) |
((3 * (pattern & 0x02)) << 1) |
((3 * (pattern & 0x04)) << 2) |
((3 * (pattern & 0x08)) << 3) |
((3 * (pattern & 0x10)) << 4) |
((3 * (pattern & 0x20)) << 5) |
((3 * (pattern & 0x40)) << 6) |
((3 * (pattern & 0x80)) << 7);
}
break;
case 32:
if (myIsReflected) {
myPattern =
((0xF * (pattern & 0x01)) << 28) |
((0xF * (pattern & 0x02)) << 23) |
((0xF * (pattern & 0x04)) << 18) |
((0xF * (pattern & 0x08)) << 13) |
((0xF * (pattern & 0x10)) << 8) |
((0xF * (pattern & 0x20)) << 3) |
((0xF * (pattern & 0x40)) >> 2) |
((0xF * (pattern & 0x80)) >> 7);
} else {
myPattern =
((0xF * (pattern & 0x01))) |
((0xF * (pattern & 0x02)) << 3) |
((0xF * (pattern & 0x04)) << 6) |
((0xF * (pattern & 0x08)) << 9) |
((0xF * (pattern & 0x10)) << 12) |
((0xF * (pattern & 0x20)) << 15) |
((0xF * (pattern & 0x40)) << 18) |
((0xF * (pattern & 0x80)) << 21);
}
break;
}
}
} // namespace TIA6502tsCore

View File

@ -0,0 +1,107 @@
//============================================================================
//
// 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_PLAYER
#define TIA_6502TS_CORE_PLAYER
#include "bspf.hxx"
namespace TIA6502tsCore {
class Player {
public:
Player(uInt32 collisionMask);
public:
void reset();
void grp(uInt8 value);
void hmp(uInt8 value);
void nusiz(uInt8 value);
void resp(bool hblank);
void refp(uInt8 value);
void vdelp(uInt8 value);
void setColor(uInt8 color);
void startMovement();
bool movementTick(uInt32 clock, bool apply);
void render();
void tick();
uInt8 getPixel(uInt8 colorIn) const;
void shufflePatterns();
uInt8 getRespClock() const;
public:
uInt32 collision;
private:
void updatePattern();
private:
uInt32 myCollisionMask;
uInt8 myColor;
uInt8 myHmmClocks;
uInt8 myCounter;
bool myIsMoving;
uInt8 myWidth;
bool myIsRendering;
Int8 myRenderCounter;
const uInt8* myDecodes;
uInt8 myPatternOld;
uInt8 myPatternNew;
uInt32 myPattern;
bool myIsReflected;
bool myIsDelaying;
private:
Player(const Player&) = delete;
Player(Player&&) = delete;
Player& operator=(const Player&) = delete;
Player& operator=(Player&&) = delete;
};
} // namespace TIA6502tsCore
#endif // TIA_6502TS_CORE_PLAYER

View File

@ -41,6 +41,11 @@ enum Delay: uInt8 {
hmclr = 2
};
enum DummyRegisters: uInt8 {
shuffleP0 = 0xF0,
shuffleP1 = 0xF1
};
namespace TIA6502tsCore {
TIA::TIA(Console& console, Sound& sound, Settings& settings)
@ -50,7 +55,9 @@ TIA::TIA(Console& console, Sound& sound, Settings& settings)
myDelayQueue(10, 20),
myPlayfield(CollisionMask::playfield),
myMissile0(CollisionMask::missile0),
myMissile1(CollisionMask::missile1)
myMissile1(CollisionMask::missile1),
myPlayer0(CollisionMask::player0),
myPlayer1(CollisionMask::player1)
{
myFrameManager.setHandlers(
[this] () {
@ -87,6 +94,8 @@ void TIA::reset()
myPlayfield.reset();
myMissile0.reset();
myMissile1.reset();
myPlayer0.reset();
myPlayer1.reset();
mySound.reset();
myDelayQueue.reset();
@ -185,6 +194,7 @@ bool TIA::poke(uInt16 address, uInt8 value)
value &= 0xFE;
myPlayfield.setColorP0(value);
myMissile0.setColor(value);
myPlayer0.setColor(value);
break;
@ -193,6 +203,7 @@ bool TIA::poke(uInt16 address, uInt8 value)
value &= 0xFE;
myPlayfield.setColorP1(value);
myMissile1.setColor(value);
myPlayer1.setColor(value);
break;
@ -251,12 +262,14 @@ bool TIA::poke(uInt16 address, uInt8 value)
case NUSIZ0:
myLinesSinceChange = 0;
myMissile0.nusiz(value);
myPlayer0.nusiz(value);
break;
case NUSIZ1:
myLinesSinceChange = 0;
myMissile1.nusiz(value);
myPlayer1.nusiz(value);
break;
@ -273,6 +286,62 @@ bool TIA::poke(uInt16 address, uInt8 value)
case HMCLR:
myDelayQueue.push(HMCLR, value, Delay::hmclr);
case GRP0:
myDelayQueue.push(GRP0, value, Delay::grp);
myDelayQueue.push(DummyRegisters::shuffleP1, value, Delay::shufflePlayer);
break;
case GRP1:
myDelayQueue.push(GRP1, value, Delay::grp);
myDelayQueue.push(DummyRegisters::shuffleP0, value, Delay::shufflePlayer);
break;
case RESP0:
myLinesSinceChange = 0;
myPlayer0.resp(myHstate == HState::blank);
break;
case RESP1:
myLinesSinceChange = 0;
myPlayer1.resp(myHstate == HState::blank);
break;
case REFP0:
myLinesSinceChange = 0;
myPlayer0.refp(value);
break;
case REFP1:
myLinesSinceChange = 0;
myPlayer1.refp(value);
break;
case VDELP0:
myLinesSinceChange = 0;
myPlayer0.vdelp(value);
break;
case VDELP1:
myLinesSinceChange = 0;
myPlayer1.vdelp(value);
break;
case HMP0:
myDelayQueue.push(HMP0, value, Delay::hmp);
break;
case HMP1:
myDelayQueue.push(HMP1, value, Delay::hmp);
break;
}
@ -466,6 +535,8 @@ void TIA::tickMovement()
m = myMissile0.movementTick(myMovementClock, apply) || m;
m = myMissile1.movementTick(myMovementClock, apply) || m;
m = myPlayer0.movementTick(myMovementClock, apply) || m;
m = myPlayer1.movementTick(myMovementClock, apply) || m;
myMovementInProgress = m;
myCollisionUpdateRequired = m;
@ -497,7 +568,7 @@ void TIA::tickHframe()
myPlayfield.tick(x);
if (lineNotCached)
renderSprites(x);
renderSprites();
tickSprites();
@ -506,16 +577,21 @@ void TIA::tickHframe()
if (++myHctr >= 228) nextLine();
}
void TIA::renderSprites(uInt32 x)
void TIA::renderSprites()
{
myPlayer0.render();
myPlayer1.render();
myMissile0.render();
myMissile1.render();
}
void TIA::tickSprites()
{
myMissile0.tick();
myMissile1.tick();
myPlayer0.tick();
myPlayer1.tick();
}
void TIA::nextLine()
@ -543,10 +619,14 @@ void TIA::renderPixel(uInt32 x, uInt32 y, bool lineNotCached)
if (myPriority == Priority::normal) {
color = myPlayfield.getPixel(color);
color = myMissile1.getPixel(color);
color = myPlayer1.getPixel(color);
color = myMissile0.getPixel(color);
color = myPlayer0.getPixel(color);
} else {
color = myMissile1.getPixel(color);
color = myPlayer1.getPixel(color);
color = myMissile0.getPixel(color);
color = myPlayer0.getPixel(color);
color = myPlayfield.getPixel(color);
}
@ -579,6 +659,8 @@ void TIA::delayedWrite(uInt8 address, uInt8 value)
myMissile0.startMovement();
myMissile1.startMovement();
myPlayer0.startMovement();
myPlayer1.startMovement();
break;
@ -616,6 +698,44 @@ void TIA::delayedWrite(uInt8 address, uInt8 value)
myLinesSinceChange = 0;
myMissile0.hmm(0);
myMissile1.hmm(0);
myPlayer0.hmp(0);
myPlayer1.hmp(0);
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 HMP0:
myLinesSinceChange = 0;
myPlayer0.hmp(value);
break;
case HMP1:
myLinesSinceChange = 0;
myPlayer1.hmp(value);
break;
}

View File

@ -29,6 +29,7 @@
#include "FrameManager.hxx"
#include "Playfield.hxx"
#include "Missile.hxx"
#include "Player.hxx"
class Console;
@ -138,7 +139,7 @@ class TIA : public AbstractTIA {
void updateCollision();
void renderSprites(uInt32 x);
void renderSprites();
void tickSprites();
@ -190,6 +191,8 @@ class TIA : public AbstractTIA {
Playfield myPlayfield;
Missile myMissile0;
Missile myMissile1;
Player myPlayer0;
Player myPlayer1;
private:

View File

@ -7,7 +7,8 @@ MODULE_OBJS := \
src/emucore/tia/core_6502ts/FrameManager.o \
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/Missile.o \
src/emucore/tia/core_6502ts/Player.o
MODULE_DIRS += \