Added ability to dynamically toggle TIA collisions for the 6 graphical

objects.  These actions are tied to the same keys as for toggling the
objects themselves, with the addition of the 'Shift' key.  For example,
toggling the P0 object is 'Alt z', and toggling P0 collisions is
'Shift-Alt z'.  Note that disabling an object will obviously disable
its collisions as well.  Still TODO is work out how these keys map on
OSX; the Shift key is already being used for something else.

Reverted Cosmic Ark 'starfield effect' to match the descriptions
given in the 'Stella 3.0 released' thread on AtariAge.  It seems the
system I tested this on has an Svideo mod board that changes the
output from a normal console.

Bumped state file format header, since the TIA internals have changed
again.  As well, bumped version # to 3.1_svn.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1884 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2009-09-14 19:22:34 +00:00
parent 5cad3ee0af
commit 2fa8b1ee70
8 changed files with 240 additions and 42 deletions

View File

@ -1887,6 +1887,42 @@
<td>Shift-Cmd + n</td> <td>Shift-Cmd + n</td>
</tr> </tr>
<tr>
<td>Toggle TIA Player0 collisions</td>
<td>Shift-Alt + z</td>
<td>TODO</td>
</tr>
<tr>
<td>Toggle TIA Player1 collisions</td>
<td>Shift-Alt + x</td>
<td>TODO</td>
</tr>
<tr>
<td>Toggle TIA Missile0 collisions</td>
<td>Shift-Alt + c</td>
<td>TODO</td>
</tr>
<tr>
<td>Toggle TIA Missile1 collisions</td>
<td>Shift-Alt + v</td>
<td>TODO</td>
</tr>
<tr>
<td>Toggle TIA Ball collisions</td>
<td>Shift-Alt + b</td>
<td>TODO</td>
</tr>
<tr>
<td>Toggle TIA Playfield collisions</td>
<td>Shift-Alt + n</td>
<td>TODO</td>
</tr>
<tr> <tr>
<td>Toggle TIA HMOVE blanks</td> <td>Toggle TIA HMOVE blanks</td>
<td>Alt + m</td> <td>Alt + m</td>
@ -1910,6 +1946,18 @@
<td>Alt + /</td> <td>Alt + /</td>
<td>Shift-Cmd + /</td> <td>Shift-Cmd + /</td>
</tr> </tr>
<tr>
<td>Turn all TIA collisions off</td>
<td>Shift-Alt + .</td>
<td>TODO</td>
</tr>
<tr>
<td>Turn all TIA collisions on</td>
<td>Shift-Alt + /</td>
<td>TODO</td>
</tr>
</table> </table>
<p><b>Other Keys (cannot be remapped, except those marked with '*')</b></p> <p><b>Other Keys (cannot be remapped, except those marked with '*')</b></p>

View File

@ -19,7 +19,7 @@
#ifndef VERSION_HXX #ifndef VERSION_HXX
#define VERSION_HXX #define VERSION_HXX
#define STELLA_BASE_VERSION "3.0" #define STELLA_BASE_VERSION "3.1_svn"
#ifdef NIGHTLY_BUILD #ifdef NIGHTLY_BUILD
#define STELLA_VERSION STELLA_BASE_VERSION "pre-" NIGHTLY_BUILD #define STELLA_VERSION STELLA_BASE_VERSION "pre-" NIGHTLY_BUILD

View File

@ -794,6 +794,14 @@ void Console::toggleTIABit(TIABit bit, const string& bitname, bool show) const
myOSystem->frameBuffer().showMessage(message); myOSystem->frameBuffer().showMessage(message);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::toggleTIACollision(TIABit bit, const string& bitname, bool show) const
{
bool result = myTIA->toggleCollision(bit);
string message = bitname + (result ? " collision enabled" : " collsion disabled");
myOSystem->frameBuffer().showMessage(message);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::toggleHMOVE() const void Console::toggleHMOVE() const
{ {
@ -811,6 +819,14 @@ void Console::enableBits(bool enable) const
myOSystem->frameBuffer().showMessage(message); myOSystem->frameBuffer().showMessage(message);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::enableCollisions(bool enable) const
{
myTIA->enableCollisions(enable);
string message = string("TIA collisions") + (enable ? " enabled" : " disabled");
myOSystem->frameBuffer().showMessage(message);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::toggleFixedColors() const void Console::toggleFixedColors() const
{ {

View File

@ -265,6 +265,17 @@ class Console : public Serializable
void toggleHMOVE() const; void toggleHMOVE() const;
void enableBits(bool enable) const; void enableBits(bool enable) const;
/**
Toggles the TIA collisions specified in the method name.
*/
void toggleP0Collision() const { toggleTIACollision(P0Bit, "P0"); }
void toggleP1Collision() const { toggleTIACollision(P1Bit, "P1"); }
void toggleM0Collision() const { toggleTIACollision(M0Bit, "M0"); }
void toggleM1Collision() const { toggleTIACollision(M1Bit, "M1"); }
void toggleBLCollision() const { toggleTIACollision(BLBit, "BL"); }
void togglePFCollision() const { toggleTIACollision(PFBit, "PF"); }
void enableCollisions(bool enable) const;
/** /**
Toggles the TIA 'fixed debug colors' mode. Toggles the TIA 'fixed debug colors' mode.
*/ */
@ -296,6 +307,7 @@ class Console : public Serializable
const uInt32* getPalette(int direction) const; const uInt32* getPalette(int direction) const;
void toggleTIABit(TIABit bit, const string& bitname, bool show = true) const; void toggleTIABit(TIABit bit, const string& bitname, bool show = true) const;
void toggleTIACollision(TIABit bit, const string& bitname, bool show = true) const;
private: private:
// Pointer to the osystem object // Pointer to the osystem object

View File

@ -369,27 +369,45 @@ void EventHandler::poll(uInt64 time)
break; break;
case SDLK_z: case SDLK_z:
myOSystem->console().toggleP0Bit(); if(mod & KMOD_SHIFT)
myOSystem->console().toggleP0Collision();
else
myOSystem->console().toggleP0Bit();
break; break;
case SDLK_x: case SDLK_x:
myOSystem->console().toggleP1Bit(); if(mod & KMOD_SHIFT)
myOSystem->console().toggleP1Collision();
else
myOSystem->console().toggleP1Bit();
break; break;
case SDLK_c: case SDLK_c:
myOSystem->console().toggleM0Bit(); if(mod & KMOD_SHIFT)
myOSystem->console().toggleM0Collision();
else
myOSystem->console().toggleM0Bit();
break; break;
case SDLK_v: case SDLK_v:
myOSystem->console().toggleM1Bit(); if(mod & KMOD_SHIFT)
myOSystem->console().toggleM1Collision();
else
myOSystem->console().toggleM1Bit();
break; break;
case SDLK_b: case SDLK_b:
myOSystem->console().toggleBLBit(); if(mod & KMOD_SHIFT)
myOSystem->console().toggleBLCollision();
else
myOSystem->console().toggleBLBit();
break; break;
case SDLK_n: case SDLK_n:
myOSystem->console().togglePFBit(); if(mod & KMOD_SHIFT)
myOSystem->console().togglePFCollision();
else
myOSystem->console().togglePFBit();
break; break;
case SDLK_m: case SDLK_m:
@ -401,11 +419,17 @@ void EventHandler::poll(uInt64 time)
break; break;
case SDLK_PERIOD: case SDLK_PERIOD:
myOSystem->console().enableBits(false); if(mod & KMOD_SHIFT)
myOSystem->console().enableCollisions(false);
else
myOSystem->console().enableBits(false);
break; break;
case SDLK_SLASH: case SDLK_SLASH:
myOSystem->console().enableBits(true); if(mod & KMOD_SHIFT)
myOSystem->console().enableCollisions(true);
else
myOSystem->console().enableBits(true);
break; break;
case SDLK_p: // Alt-p toggles phosphor effect case SDLK_p: // Alt-p toggles phosphor effect

View File

@ -28,8 +28,8 @@
#include "StateManager.hxx" #include "StateManager.hxx"
#define STATE_HEADER "03000000state" #define STATE_HEADER "03000100state"
#define MOVIE_HEADER "03000000movie" #define MOVIE_HEADER "03000100movie"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
StateManager::StateManager(OSystem* osystem) StateManager::StateManager(OSystem* osystem)

View File

@ -125,7 +125,7 @@ void TIA::reset()
// Currently no objects are enabled or selectively disabled // Currently no objects are enabled or selectively disabled
myEnabledObjects = 0; myEnabledObjects = 0;
myDisabledObjects = 0; myDisabledObjects = 0xFF;
myAllowHMOVEBlanks = true; myAllowHMOVEBlanks = true;
// Some default values for the registers // Some default values for the registers
@ -144,6 +144,7 @@ void TIA::reset()
myHMP0 = myHMP1 = myHMM0 = myHMM1 = myHMBL = 0; myHMP0 = myHMP1 = myHMM0 = myHMM1 = myHMBL = 0;
myVDELP0 = myVDELP1 = myVDELBL = myRESMP0 = myRESMP1 = false; myVDELP0 = myVDELP1 = myVDELBL = myRESMP0 = myRESMP1 = false;
myCollision = 0; myCollision = 0;
myCollisionEnabledMask = 0xFFFFFFFF;
myPOSP0 = myPOSP1 = myPOSM0 = myPOSM1 = myPOSBL = 0; myPOSP0 = myPOSP1 = myPOSM0 = myPOSM1 = myPOSBL = 0;
// Some default values for the "current" variables // Some default values for the "current" variables
@ -360,6 +361,7 @@ bool TIA::save(Serializer& out) const
out.putBool(myRESMP0); out.putBool(myRESMP0);
out.putBool(myRESMP1); out.putBool(myRESMP1);
out.putInt(myCollision); out.putInt(myCollision);
out.putInt(myCollisionEnabledMask);
out.putByte((char)myCurrentGRP0); out.putByte((char)myCurrentGRP0);
out.putByte((char)myCurrentGRP1); out.putByte((char)myCurrentGRP1);
@ -468,6 +470,7 @@ bool TIA::load(Serializer& in)
myRESMP0 = in.getBool(); myRESMP0 = in.getBool();
myRESMP1 = in.getBool(); myRESMP1 = in.getBool();
myCollision = (uInt16) in.getInt(); myCollision = (uInt16) in.getInt();
myCollisionEnabledMask = in.getInt();
myCurrentGRP0 = (uInt8) in.getByte(); myCurrentGRP0 = (uInt8) in.getByte();
myCurrentGRP1 = (uInt8) in.getByte(); myCurrentGRP1 = (uInt8) in.getByte();
@ -742,6 +745,49 @@ bool TIA::toggleBit(TIABit b, uInt8 mode)
return on; return on;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIA::enableCollisions(bool mode)
{
toggleCollision(P0Bit, mode ? 1 : 0);
toggleCollision(P1Bit, mode ? 1 : 0);
toggleCollision(M0Bit, mode ? 1 : 0);
toggleCollision(M1Bit, mode ? 1 : 0);
toggleCollision(BLBit, mode ? 1 : 0);
toggleCollision(PFBit, mode ? 1 : 0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool TIA::toggleCollision(TIABit b, uInt8 mode)
{
uInt16 enabled = myCollisionEnabledMask >> 16;
// If mode is 0 or 1, use it as a boolean (off or on)
// Otherwise, flip the state
bool on = (mode == 0 || mode == 1) ? bool(mode) : !(enabled & b);
if(on) enabled |= b;
else enabled &= ~b;
// Assume all collisions are on, then selectively turn the desired ones off
uInt16 mask = 0xffff;
if(!(enabled & P0Bit))
mask &= ~(Cx_M0P0 | Cx_M1P0 | Cx_P0PF | Cx_P0BL | Cx_P0P1);
if(!(enabled & P1Bit))
mask &= ~(Cx_M0P1 | Cx_M1P1 | Cx_P1PF | Cx_P1BL | Cx_P0P1);
if(!(enabled & M0Bit))
mask &= ~(Cx_M0P0 | Cx_M0P1 | Cx_M0PF | Cx_M0BL | Cx_M0M1);
if(!(enabled & M1Bit))
mask &= ~(Cx_M1P0 | Cx_M1P1 | Cx_M1PF | Cx_M1BL | Cx_M0M1);
if(!(enabled & BLBit))
mask &= ~(Cx_P0BL | Cx_P1BL | Cx_M0BL | Cx_M1BL | Cx_BLPF);
if(!(enabled & PFBit))
mask &= ~(Cx_P0PF | Cx_P1PF | Cx_M0PF | Cx_M1PF | Cx_BLPF);
// Now combine the masks
myCollisionEnabledMask = (enabled << 16) | mask;
return on;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool TIA::toggleHMOVEBlank() bool TIA::toggleHMOVEBlank()
{ {
@ -965,22 +1011,48 @@ void TIA::updateFrame(Int32 clock)
// simulates the behaviour as visually seen in the aforementioned // simulates the behaviour as visually seen in the aforementioned
// ROMs. Other ROMs may break this simulation; more testing is // ROMs. Other ROMs may break this simulation; more testing is
// required to figure out what's really going on here. // required to figure out what's really going on here.
if(myHMM0mmr && myPOSM0 % 4 == 3) if(myHMM0mmr)
{ {
// Stretch this missle so it's 4 pixels wide, with the 3rd pixel switch(myPOSM0 % 4)
// blanked out; this is indicated by using a size of '4' {
myCurrentM0Mask = &TIATables::MxMask[myPOSM0 & 0x03] case 3:
[myNUSIZ0 & 0x07][4][160 - (myPOSM0 & 0xFC)]; // Stretch this missle so it's 2 pixels wide and shifted one
// pixel to the left
myCurrentM0Mask = &TIATables::MxMask[(myPOSM0-1) & 0x03]
[myNUSIZ0 & 0x07][((myNUSIZ0 & 0x30) >> 4)|1][160 - ((myPOSM0-1) & 0xFC)];
break;
case 2:
// Missle is disabled on this line
myCurrentM0Mask = &TIATables::DisabledMask[0];
break;
default:
myCurrentM0Mask = &TIATables::MxMask[myPOSM0 & 0x03]
[myNUSIZ0 & 0x07][(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFC)];
break;
}
} }
else else
myCurrentM0Mask = &TIATables::MxMask[myPOSM0 & 0x03] myCurrentM0Mask = &TIATables::MxMask[myPOSM0 & 0x03]
[myNUSIZ0 & 0x07][(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFC)]; [myNUSIZ0 & 0x07][(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFC)];
if(myHMM1mmr && myPOSM1 % 4 == 3) if(myHMM1mmr)
{ {
// Stretch this missle so it's 4 pixels wide, with the 3rd pixel switch(myPOSM1 % 4)
// blanked out; this is indicated by using a size of '4' {
myCurrentM1Mask = &TIATables::MxMask[myPOSM1 & 0x03] case 3:
[myNUSIZ1 & 0x07][4][160 - (myPOSM1 & 0xFC)]; // Stretch this missle so it's 2 pixels wide and shifted one
// pixel to the left
myCurrentM1Mask = &TIATables::MxMask[(myPOSM1-1) & 0x03]
[myNUSIZ1 & 0x07][((myNUSIZ1 & 0x30) >> 4)|1][160 - ((myPOSM1-1) & 0xFC)];
break;
case 2:
// Missle is disabled on this line
myCurrentM1Mask = &TIATables::DisabledMask[0];
break;
default:
myCurrentM1Mask = &TIATables::MxMask[myPOSM1 & 0x03]
[myNUSIZ1 & 0x07][(myNUSIZ1 & 0x30) >> 4][160 - (myPOSM1 & 0xFC)];
break;
}
} }
else else
myCurrentM1Mask = &TIATables::MxMask[myPOSM1 & 0x03] myCurrentM1Mask = &TIATables::MxMask[myPOSM1 & 0x03]
@ -1089,46 +1161,47 @@ uInt8 TIA::peek(uInt16 addr)
updateFrame(mySystem->cycles() * 3); updateFrame(mySystem->cycles() * 3);
uInt8 value = 0x00; uInt8 value = 0x00;
uInt16 collision = myCollision & (uInt16)myCollisionEnabledMask;
switch(addr & 0x000f) switch(addr & 0x000f)
{ {
case CXM0P: case CXM0P:
value = ((myCollision & Cx_M0P1) ? 0x80 : 0x00) | value = ((collision & Cx_M0P1) ? 0x80 : 0x00) |
((myCollision & Cx_M0P0) ? 0x40 : 0x00); ((collision & Cx_M0P0) ? 0x40 : 0x00);
break; break;
case CXM1P: case CXM1P:
value = ((myCollision & Cx_M1P0) ? 0x80 : 0x00) | value = ((collision & Cx_M1P0) ? 0x80 : 0x00) |
((myCollision & Cx_M1P1) ? 0x40 : 0x00); ((collision & Cx_M1P1) ? 0x40 : 0x00);
break; break;
case CXP0FB: case CXP0FB:
value = ((myCollision & Cx_P0PF) ? 0x80 : 0x00) | value = ((collision & Cx_P0PF) ? 0x80 : 0x00) |
((myCollision & Cx_P0BL) ? 0x40 : 0x00); ((collision & Cx_P0BL) ? 0x40 : 0x00);
break; break;
case CXP1FB: case CXP1FB:
value = ((myCollision & Cx_P1PF) ? 0x80 : 0x00) | value = ((collision & Cx_P1PF) ? 0x80 : 0x00) |
((myCollision & Cx_P1BL) ? 0x40 : 0x00); ((collision & Cx_P1BL) ? 0x40 : 0x00);
break; break;
case CXM0FB: case CXM0FB:
value = ((myCollision & Cx_M0PF) ? 0x80 : 0x00) | value = ((collision & Cx_M0PF) ? 0x80 : 0x00) |
((myCollision & Cx_M0BL) ? 0x40 : 0x00); ((collision & Cx_M0BL) ? 0x40 : 0x00);
break; break;
case CXM1FB: case CXM1FB:
value = ((myCollision & Cx_M1PF) ? 0x80 : 0x00) | value = ((collision & Cx_M1PF) ? 0x80 : 0x00) |
((myCollision & Cx_M1BL) ? 0x40 : 0x00); ((collision & Cx_M1BL) ? 0x40 : 0x00);
break; break;
case CXBLPF: case CXBLPF:
value = (myCollision & Cx_BLPF) ? 0x80 : 0x00; value = (collision & Cx_BLPF) ? 0x80 : 0x00;
break; break;
case CXPPMM: case CXPPMM:
value = ((myCollision & Cx_P0P1) ? 0x80 : 0x00) | value = ((collision & Cx_P0P1) ? 0x80 : 0x00) |
((myCollision & Cx_M0M1) ? 0x40 : 0x00); ((collision & Cx_M0M1) ? 0x40 : 0x00);
break; break;
case INPT0: case INPT0:
@ -1345,9 +1418,6 @@ void TIA::poke(uInt16 addr, uInt8 value)
if(((clock - myClockWhenFrameStarted) % 228) < (68 + 79)) if(((clock - myClockWhenFrameStarted) % 228) < (68 + 79))
myCurrentPFMask = TIATables::PFMask[myCTRLPF & 0x01]; myCurrentPFMask = TIATables::PFMask[myCTRLPF & 0x01];
myCurrentBLMask = &TIATables::BLMask[myPOSBL & 0x03]
[(myCTRLPF & 0x30) >> 4][160 - (myPOSBL & 0xFC)];
break; break;
} }

View File

@ -249,14 +249,16 @@ class TIA : public Device
bool scanlinePos(uInt16& x, uInt16& y) const; bool scanlinePos(uInt16& x, uInt16& y) const;
/** /**
Enables/disables all TIABit bits. Enables/disables all TIABit bits. Note that disabling a graphical
object also disables its collisions.
@param mode Whether to enable or disable all bits @param mode Whether to enable or disable all bits
*/ */
void enableBits(bool mode); void enableBits(bool mode);
/** /**
Enables/disable/toggle the specified TIA bit. Enables/disable/toggle the specified TIA bit. Note that disabling a
graphical object also disables its collisions.
@param mode 1/0 indicates on/off, and values greater than 1 mean @param mode 1/0 indicates on/off, and values greater than 1 mean
flip the bit from its current state flip the bit from its current state
@ -265,6 +267,23 @@ class TIA : public Device
*/ */
bool toggleBit(TIABit b, uInt8 mode = 2); bool toggleBit(TIABit b, uInt8 mode = 2);
/**
Enables/disables all TIABit collisions.
@param mode Whether to enable or disable all collisions
*/
void enableCollisions(bool mode);
/**
Enables/disable/toggle the specified TIA bit collision.
@param mode 1/0 indicates on/off, and values greater than 1 mean
flip the collision from its current state
@return Whether the collision was enabled or disabled
*/
bool toggleCollision(TIABit b, uInt8 mode = 2);
/** /**
Toggle the display of HMOVE blanks. Toggle the display of HMOVE blanks.
@ -452,6 +471,15 @@ class TIA : public Device
uInt16 myCollision; // Collision register uInt16 myCollision; // Collision register
// Determines whether specified collisions are enabled or disabled
// The lower 16 bits are and'ed with the collision register to mask out
// any collisions we don't want to be processed
// The upper 16 bits are used to store which objects is currently
// enabled or disabled
// This is necessary since there are 15 collision combinations which
// are controlled by 6 objects
uInt32 myCollisionEnabledMask;
// Note that these position registers contain the color clock // Note that these position registers contain the color clock
// on which the object's serial output should begin (0 to 159) // on which the object's serial output should begin (0 to 159)
Int16 myPOSP0; // Player 0 position register Int16 myPOSP0; // Player 0 position register