Too many changes to list here specifically.

The major changes are a stabilization of the core code.  There should
be much fewer major core changes from now on.

Updated the SDL port to the latest core changes.  Next I'll start on the
Windows port.

There are still many optimizations left to do.  Specifically, when using
the SDL port on a Pentium4 2.4GHz, normal mode results in 4% CPU usage,
while menu mode makes it jump to 46%.  This must be improved.

The porters guide is a work-in-progress, and not yet available.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@199 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2003-10-26 19:40:39 +00:00
parent c7233b35b0
commit d098cb1207
16 changed files with 1528 additions and 200 deletions

View File

@ -13,7 +13,7 @@
## See the file "license" for information on usage and redistribution of
## this file, and for a DISCLAIMER OF ALL WARRANTIES.
##
## $Id: makefile,v 1.42 2003-10-17 18:02:15 stephena Exp $
## $Id: makefile,v 1.43 2003-10-26 19:40:39 stephena Exp $
##============================================================================
##============================================================================
@ -30,14 +30,14 @@ OPTIMIZATIONS = $(CXXFLAGS) -Wall -Wunused
### comment out all lines to completely disable sound
###
#SOUND_ALSA = 1
#SOUND_OSS = 1
SOUND_OSS = 1
#SOUND_SDL = 1
### to include OpenGL video support (SDL)
#DISPLAY_OPENGL = 1
### to include joystick support (SDL)
# JOYSTICK_SUPPORT = 1
JOYSTICK_SUPPORT = 1
### to include support for saving snapshots in png format
### (requires PNG library) FIXME

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Console.cxx,v 1.18 2003-10-17 18:02:16 stephena Exp $
// $Id: Console.cxx,v 1.19 2003-10-26 19:40:39 stephena Exp $
//============================================================================
#include <assert.h>
@ -174,7 +174,7 @@ Console::Console(const uInt8* image, uInt32 size, const char* filename,
// Initialize the framebuffer interface.
// This must be done *after* a reset, since it needs updated values.
myFrameBuffer.init(this, myMediaSource);
myFrameBuffer.initDisplay(this, myMediaSource);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -268,12 +268,12 @@ void Console::toggleFormat()
if(format == "NTSC")
{
myFrameBuffer->showMessage("PAL Mode");
myFrameBuffer.showMessage("PAL Mode");
myProperties.set("Display.Format", "PAL");
}
else if(format == "PAL")
{
myFrameBuffer->showMessage("NTSC Mode");
myFrameBuffer.showMessage("NTSC Mode");
myProperties.set("Display.Format", "NTSC");
}
}
@ -291,12 +291,12 @@ void Console::changeXStart(const uInt32 direction)
xstart += 4;
if(xstart > 80)
{
myFrameBuffer->showMessage("XStart at maximum");
myFrameBuffer.showMessage("XStart at maximum");
return;
}
else if((width + xstart) > 160)
{
myFrameBuffer->showMessage("XStart no effect");
myFrameBuffer.showMessage("XStart no effect");
return;
}
}
@ -305,7 +305,7 @@ void Console::changeXStart(const uInt32 direction)
xstart -= 4;
if(xstart < 0)
{
myFrameBuffer->showMessage("XStart at minimum");
myFrameBuffer.showMessage("XStart at minimum");
return;
}
}
@ -316,7 +316,7 @@ void Console::changeXStart(const uInt32 direction)
message = "XStart ";
message += strval.str();
myFrameBuffer->showMessage(message);
myFrameBuffer.showMessage(message);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -331,7 +331,7 @@ void Console::changeYStart(const uInt32 direction)
ystart++;
if(ystart > 64)
{
myFrameBuffer->showMessage("YStart at maximum");
myFrameBuffer.showMessage("YStart at maximum");
return;
}
}
@ -340,7 +340,7 @@ void Console::changeYStart(const uInt32 direction)
ystart--;
if(ystart < 0)
{
myFrameBuffer->showMessage("YStart at minimum");
myFrameBuffer.showMessage("YStart at minimum");
return;
}
}
@ -351,7 +351,7 @@ void Console::changeYStart(const uInt32 direction)
message = "YStart ";
message += strval.str();
myFrameBuffer->showMessage(message);
myFrameBuffer.showMessage(message);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -367,12 +367,12 @@ void Console::changeWidth(const uInt32 direction)
width += 4;
if((width > 160) || ((width % 4) != 0))
{
myFrameBuffer->showMessage("Width at maximum");
myFrameBuffer.showMessage("Width at maximum");
return;
}
else if((width + xstart) > 160)
{
myFrameBuffer->showMessage("Width no effect");
myFrameBuffer.showMessage("Width no effect");
return;
}
}
@ -381,7 +381,7 @@ void Console::changeWidth(const uInt32 direction)
width -= 4;
if(width < 80)
{
myFrameBuffer->showMessage("Width at minimum");
myFrameBuffer.showMessage("Width at minimum");
return;
}
}
@ -392,7 +392,7 @@ void Console::changeWidth(const uInt32 direction)
message = "Width ";
message += strval.str();
myFrameBuffer->showMessage(message);
myFrameBuffer.showMessage(message);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -407,7 +407,7 @@ void Console::changeHeight(const uInt32 direction)
height++;
if(height > 256)
{
myFrameBuffer->showMessage("Height at maximum");
myFrameBuffer.showMessage("Height at maximum");
return;
}
}
@ -416,7 +416,7 @@ void Console::changeHeight(const uInt32 direction)
height--;
if(height < 100)
{
myFrameBuffer->showMessage("Height at minimum");
myFrameBuffer.showMessage("Height at minimum");
return;
}
}
@ -427,7 +427,7 @@ void Console::changeHeight(const uInt32 direction)
message = "Height ";
message += strval.str();
myFrameBuffer->showMessage(message);
myFrameBuffer.showMessage(message);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -437,9 +437,9 @@ void Console::saveProperties(string filename, bool merge)
if(merge)
{
if(myPropSet.merge(myProperties, filename))
myFrameBuffer->showMessage("Properties merged");
myFrameBuffer.showMessage("Properties merged");
else
myFrameBuffer->showMessage("Properties not merged");
myFrameBuffer.showMessage("Properties not merged");
}
else // Save to the specified file directly
{
@ -449,11 +449,11 @@ void Console::saveProperties(string filename, bool merge)
{
myProperties.save(out);
out.close();
myFrameBuffer->showMessage("Properties saved");
myFrameBuffer.showMessage("Properties saved");
}
else
{
myFrameBuffer->showMessage("Properties not saved");
myFrameBuffer.showMessage("Properties not saved");
}
}
}

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Console.hxx,v 1.13 2003-10-17 18:02:16 stephena Exp $
// $Id: Console.hxx,v 1.14 2003-10-26 19:40:39 stephena Exp $
//============================================================================
#ifndef CONSOLE_HXX
@ -41,7 +41,7 @@ class FrameBuffer;
This class represents the entire game console.
@author Bradford W. Mott
@version $Id: Console.hxx,v 1.13 2003-10-17 18:02:16 stephena Exp $
@version $Id: Console.hxx,v 1.14 2003-10-26 19:40:39 stephena Exp $
*/
class Console
{
@ -55,6 +55,7 @@ class Console
@param filename The name of the file that contained the ROM image
@param rcsettings The settings object to use
@param profiles The game profiles object to use
@param framebuffer The framebuffer object to use
@param sampleRate The rate to create audio samples at
*/
Console(const uInt8* image, uInt32 size, const char* filename,

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: EventHandler.cxx,v 1.16 2003-10-17 18:02:16 stephena Exp $
// $Id: EventHandler.cxx,v 1.17 2003-10-26 19:40:39 stephena Exp $
//============================================================================
#include <algorithm>
@ -37,23 +37,23 @@
EventHandler::EventHandler(Console* console)
: myConsole(console),
myCurrentState(0),
myMenuStatus(false)
myPauseStatus(false),
myMenuStatus(false),
myRemapEnabledFlag(true)
{
Int32 i;
// Create the event object which will be used for this handler
myEvent = new Event();
// Erase the KeyEvent array
for(i = 0; i < StellaEvent::LastKCODE; ++i)
for(Int32 i = 0; i < StellaEvent::LastKCODE; ++i)
myKeyTable[i] = Event::NoType;
// Erase the JoyEvent array
for(i = 0; i < StellaEvent::LastJSTICK*StellaEvent::LastJCODE; ++i)
for(Int32 i = 0; i < StellaEvent::LastJSTICK*StellaEvent::LastJCODE; ++i)
myJoyTable[i] = Event::NoType;
// Erase the Message array
for(i = 0; i < Event::LastType; ++i)
for(Int32 i = 0; i < Event::LastType; ++i)
ourMessageTable[i] = "";
// Set unchanging messages
@ -85,7 +85,7 @@ Event* EventHandler::event()
void EventHandler::sendKeyEvent(StellaEvent::KeyCode key, Int32 state)
{
// First check if we are entering menu mode
if(key == StellaEvent::KCODE_TAB && state == 1)
if(myRemapEnabledFlag && key == StellaEvent::KCODE_TAB && state == 1)
{
myMenuStatus = !myMenuStatus;
myConsole->frameBuffer().showMainMenu(myMenuStatus);
@ -143,7 +143,9 @@ void EventHandler::sendEvent(Event::Type event, Int32 state)
}
else if(event == Event::Pause)
{
myConsole->settings().setPauseEvent();
myPauseStatus = !myPauseStatus;
myConsole->frameBuffer().pause(myPauseStatus);
//FIXME myConsole->sound().pause(myPauseStatus);
return;
}
else if(event == Event::Quit)
@ -417,7 +419,7 @@ void EventHandler::takeSnapshot()
// Now save the snapshot file
string filename = myConsole->settings().snapshotFilename();
myConsole->snapshot().savePNG(filename, myConsole->frameBuffer(),
myConsole->settings().getInt("zoom")); // FIXME - update zoom in resizewindow
myConsole->settings().getInt("zoom"));
myConsole->frameBuffer().showMessage("Snapshot saved");
#else

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: EventHandler.hxx,v 1.10 2003-09-30 01:22:45 stephena Exp $
// $Id: EventHandler.hxx,v 1.11 2003-10-26 19:40:39 stephena Exp $
//============================================================================
#ifndef EVENTHANDLER_HXX
@ -41,7 +41,7 @@ class MediaSource;
mapping can take place.
@author Stephen Anthony
@version $Id: EventHandler.hxx,v 1.10 2003-09-30 01:22:45 stephena Exp $
@version $Id: EventHandler.hxx,v 1.11 2003-10-26 19:40:39 stephena Exp $
*/
class EventHandler
{
@ -111,6 +111,13 @@ class EventHandler
*/
string getJoymap();
/**
Enable/disable remapping mode.
@param status The toggle for enable/disable
*/
void enableRemapping(bool status) { myRemapEnabledFlag = status; }
void getKeymapArray(Event::Type** array, uInt32* size);
void getJoymapArray(Event::Type** array, uInt32* size);
@ -160,6 +167,9 @@ class EventHandler
// Indicates that the main menu is being entered
bool myMenuStatus;
// Indicates that remapping mode is enabled
bool myRemapEnabledFlag;
};
#endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: FrameBuffer.cxx,v 1.1 2003-10-17 18:02:16 stephena Exp $
// $Id: FrameBuffer.cxx,v 1.2 2003-10-26 19:40:39 stephena Exp $
//============================================================================
#include <sstream>
@ -28,26 +28,32 @@
#include "FrameBuffer.hxx"
// Eventually, these may become variables
#define FGCOLOR 10 // A white color in NTSC and PAL mode
#define BGCOLOR 0 // A black color in NTSC and PAL mode
#define FONTWIDTH 8 // FIXME - TIA framebuffers must be updated for this
#define FGCOLOR 10 // A white color in NTSC and PAL mode
#define BGCOLOR 0 // A black color in NTSC and PAL mode
#define FONTWIDTH 8
#define FONTHEIGHT 8
#define LINEOFFSET 10 // FONTHEIGHT + 1 pixel on top and bottom
#define XBOXOFFSET 8 // 4 pixels to the left and right of text
#define YBOXOFFSET 8 // 4 pixels to the top and bottom of text
#define LINEOFFSET 10 // FONTHEIGHT + 1 pixel on top and bottom
#define XBOXOFFSET 8 // 4 pixels to the left and right of text
#define YBOXOFFSET 8 // 4 pixels to the top and bottom of text
#define UPARROW 24 // Indicates more lines above
#define DOWNARROW 25 // Indicates more lines below
#define LEFTARROW 26 // Left arrow for indicating current line
#define RIGHTARROW 27 // Left arrow for indicating current line
#define UPARROW 24 // Indicates more lines above
#define DOWNARROW 25 // Indicates more lines below
#define LEFTARROW 26 // Left arrow for indicating current line
#define RIGHTARROW 27 // Left arrow for indicating current line
#define LEFTMARKER 17 // Indicates item being remapped
#define RIGHTMARKER 16 // Indicates item being remapped
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBuffer::FrameBuffer()
: myFrameRate(0),
: myConsole(0),
myMediaSource(0),
myWidth(160),
myHeight(300),
theRedrawEntireFrameIndicator(true),
myPauseStatus(false),
myFrameRate(0),
myCurrentWidget(W_NONE),
myRemapEventSelectedFlag(false),
mySelectedEvent(Event::NoType),
@ -61,20 +67,17 @@ FrameBuffer::FrameBuffer()
myRemapMenuMaxLines(0),
myMessageTime(0),
myMessageText(""),
myInfoMenuWidth(0),
isFullscreen(false) // FIXME
myInfoMenuWidth(0)
{
cerr << "FrameBuffer::FrameBuffer()\n";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBuffer::~FrameBuffer(void)
{
cerr << "FrameBuffer::~FrameBuffer()\n";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBuffer::initBase(Console* console, MediaSource* mediasrc)
void FrameBuffer::initDisplay(Console* console, MediaSource* mediasrc)
{
myConsole = console;
myMediaSource = mediasrc;
@ -99,14 +102,6 @@ void FrameBuffer::initBase(Console* console, MediaSource* mediasrc)
if(ourPropertiesInfo[5].length() > myInfoMenuWidth)
myInfoMenuWidth = ourPropertiesInfo[5].length();
// Determine the maximum number of items that can be onscreen vertically
myMaxLines = myHeight / LINEOFFSET - 2;
// Set up the correct bounds for the remap menu
myRemapMenuMaxLines = myRemapMenuItems > myMaxLines ? myMaxLines : myRemapMenuItems;
myRemapMenuLowIndex = 0;
myRemapMenuHighIndex = myRemapMenuMaxLines;
// Get the arrays containing key and joystick mappings
myConsole->eventHandler().getKeymapArray(&myKeyTable, &myKeyTableSize);
myConsole->eventHandler().getJoymapArray(&myJoyTable, &myJoyTableSize);
@ -114,6 +109,74 @@ void FrameBuffer::initBase(Console* console, MediaSource* mediasrc)
myFrameRate = myConsole->settings().getInt("framerate");
loadRemapMenu();
// Now initialize the derived class
init();
// The following has to be done after the initialization of the derived class
// Determine the maximum number of items that can be onscreen vertically
myMaxLines = myHeight / LINEOFFSET - 2;
// Set up the correct bounds for the remap menu
myRemapMenuMaxLines = myRemapMenuItems > myMaxLines ? myMaxLines : myRemapMenuItems;
myRemapMenuLowIndex = 0;
myRemapMenuHighIndex = myRemapMenuMaxLines;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBuffer::update()
{
// Do any pre-frame stuff
preFrameUpdate();
// Draw changes to the mediasource
if(!myPauseStatus) // FIXME - sound class
myMediaSource->update();
drawMediaSource();
// Then overlay any menu items
switch(myCurrentWidget)
{
case W_NONE:
break;
case MAIN_MENU:
drawMainMenu();
break;
case REMAP_MENU:
drawRemapMenu();
break;
case INFO_MENU:
drawInfoMenu();
break;
default:
break;
}
// A message is a special case of interface element
// It can overwrite even a menu
if(myMessageTime > 0)
{
uInt32 width = myMessageText.length()*FONTWIDTH + FONTWIDTH;
uInt32 height = LINEOFFSET + FONTHEIGHT;
uInt32 x = (myWidth >> 1) - (width >> 1);
uInt32 y = myHeight - height - LINEOFFSET/2;
// Draw the bounded box and text
drawBoundedBox(x, y, width, height, FGCOLOR, BGCOLOR);
drawText(x + XBOXOFFSET/2, LINEOFFSET/2 + y, myMessageText, FGCOLOR);
myMessageTime--;
// Erase this message on next update
if(myMessageTime == 0)
theRedrawEntireFrameIndicator = true;
}
// Do any post-frame stuff
postFrameUpdate();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -122,6 +185,7 @@ void FrameBuffer::showMainMenu(bool show)
myCurrentWidget = show ? MAIN_MENU : W_NONE;
myRemapEventSelectedFlag = false;
mySelectedEvent = Event::NoType;
theRedrawEntireFrameIndicator = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -129,6 +193,96 @@ void FrameBuffer::showMessage(const string& message)
{
myMessageText = message;
myMessageTime = myFrameRate << 1;
theRedrawEntireFrameIndicator = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void FrameBuffer::drawMainMenu()
{
uInt32 x, y, width, height, i, xpos, ypos;
width = 16*FONTWIDTH + (FONTWIDTH << 1);
height = myMainMenuItems*LINEOFFSET + 2*FONTHEIGHT;
x = (myWidth >> 1) - (width >> 1);
y = (myHeight >> 1) - (height >> 1);
// Draw the bounded box and text, leaving a little room for arrows
xpos = x + XBOXOFFSET;
drawBoundedBox(x-2, y-2, width+3, height+3, FGCOLOR, BGCOLOR);
for(i = 0; i < myMainMenuItems; i++)
drawText(xpos, LINEOFFSET*i + y + YBOXOFFSET, ourMainMenu[i].action, FGCOLOR);
// Now draw the selection arrow around the currently selected item
ypos = LINEOFFSET*myMainMenuIndex + y + YBOXOFFSET;
drawChar(x, ypos, LEFTARROW, FGCOLOR);
drawChar(x + width - FONTWIDTH, ypos, RIGHTARROW, FGCOLOR);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void FrameBuffer::drawRemapMenu()
{
uInt32 x, y, width, height, i, xpos, ypos;
width = (myWidth >> 3) * FONTWIDTH - (FONTWIDTH << 1);
height = myMaxLines*LINEOFFSET + 2*FONTHEIGHT;
x = (myWidth >> 1) - (width >> 1);
y = (myHeight >> 1) - (height >> 1);
// Draw the bounded box and text, leaving a little room for arrows
drawBoundedBox(x-2, y-2, width+3, height+3, FGCOLOR, BGCOLOR);
for(i = myRemapMenuLowIndex; i < myRemapMenuHighIndex; i++)
{
ypos = LINEOFFSET*(i-myRemapMenuLowIndex) + y + YBOXOFFSET;
drawText(x + XBOXOFFSET, ypos, ourRemapMenu[i].action, FGCOLOR);
xpos = width - ourRemapMenu[i].key.length() * FONTWIDTH;
drawText(xpos, ypos, ourRemapMenu[i].key, FGCOLOR);
}
// Normally draw an arrow indicating the current line,
// otherwise highlight the currently selected item for remapping
if(!myRemapEventSelectedFlag)
{
ypos = LINEOFFSET*(myRemapMenuIndex-myRemapMenuLowIndex) + y + YBOXOFFSET;
drawChar(x, ypos, LEFTARROW, FGCOLOR);
drawChar(x + width - FONTWIDTH, ypos, RIGHTARROW, FGCOLOR);
}
else
{
ypos = LINEOFFSET*(myRemapMenuIndex-myRemapMenuLowIndex) + y + YBOXOFFSET;
// Left marker is at the beginning of event name text
xpos = width - ourRemapMenu[myRemapMenuIndex].key.length() * FONTWIDTH - FONTWIDTH;
drawChar(xpos, ypos, LEFTMARKER, FGCOLOR);
// Right marker is at the end of the line
drawChar(x + width - FONTWIDTH, ypos, RIGHTMARKER, FGCOLOR);
}
// Finally, indicate that there are more items to the top or bottom
xpos = (width >> 1) - FONTWIDTH/2;
if(myRemapMenuHighIndex - myMaxLines > 0)
drawChar(xpos, y, UPARROW, FGCOLOR);
if(myRemapMenuLowIndex + myMaxLines < myRemapMenuItems)
drawChar(xpos, height - FONTWIDTH/2, DOWNARROW, FGCOLOR);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void FrameBuffer::drawInfoMenu()
{
uInt32 x, y, width, height, i, xpos;
width = myInfoMenuWidth*FONTWIDTH + 2*FONTWIDTH;
height = 6*LINEOFFSET + 2*FONTHEIGHT;
x = (myWidth >> 1) - (width >> 1);
y = (myHeight >> 1) - (height >> 1);
// Draw the bounded box and text
xpos = x + XBOXOFFSET;
drawBoundedBox(x, y, width, height, FGCOLOR, BGCOLOR);
for(i = 0; i < 6; i++)
drawText(xpos, LINEOFFSET*i + y + YBOXOFFSET, ourPropertiesInfo[i], FGCOLOR);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -164,7 +318,6 @@ void FrameBuffer::sendKeyEvent(StellaEvent::KeyCode key, Int32 state)
{
mySelectedEvent = currentSelectedEvent();
myRemapEventSelectedFlag = true;
cerr << "'" << ourRemapMenu[myRemapMenuIndex].action << "' selected for remapping\n";
}
else if(key == StellaEvent::KCODE_UP)
moveCursorUp();
@ -175,17 +328,19 @@ cerr << "'" << ourRemapMenu[myRemapMenuIndex].action << "' selected for remappin
else if(key == StellaEvent::KCODE_PAGEDOWN)
movePageDown();
else if(key == StellaEvent::KCODE_ESCAPE)
{
myCurrentWidget = MAIN_MENU;
theRedrawEntireFrameIndicator = true;
}
break; // REMAP_MENU
case INFO_MENU:
if(key == StellaEvent::KCODE_ESCAPE)
{
myCurrentWidget = MAIN_MENU;
case FONTS_MENU:
if(key == StellaEvent::KCODE_ESCAPE)
myCurrentWidget = MAIN_MENU;
theRedrawEntireFrameIndicator = true;
}
break; // INFO_MENU
@ -240,6 +395,15 @@ cerr << "stick = " << stick << ", button = " << code << endl;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MediaSource* FrameBuffer::mediaSource() const
{
if(myMediaSource)
return myMediaSource;
else
return (MediaSource*) NULL;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBuffer::Widget FrameBuffer::currentSelectedWidget()
{
@ -413,7 +577,7 @@ void FrameBuffer::loadRemapMenu()
}
for(uInt32 j = 0; j < myJoyTableSize; ++j)
{
if(myJoyTable[j] == event) // FIXME - don't label axis as button
if(myJoyTable[j] == event)
{
ostringstream joyevent;
uInt32 stick = j / StellaEvent::LastJCODE;
@ -498,10 +662,9 @@ const uInt8 FrameBuffer::ourFontData[2048] = {
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBuffer::MainMenuItem FrameBuffer::ourMainMenu[3] = {
FrameBuffer::MainMenuItem FrameBuffer::ourMainMenu[2] = {
{ REMAP_MENU, "Key Remapping" },
{ INFO_MENU, "Game Information" },
{ FONTS_MENU, "Character Set" }
{ INFO_MENU, "Game Information" }
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: FrameBuffer.hxx,v 1.1 2003-10-17 18:02:16 stephena Exp $
// $Id: FrameBuffer.hxx,v 1.2 2003-10-26 19:40:39 stephena Exp $
//============================================================================
#ifndef FRAMEBUFFER_HXX
@ -27,11 +27,15 @@
class Console;
/**
This class implements a MAME-like user interface where Stella settings
can be changed. It also encapsulates the MediaSource.
This class encapsulates the MediaSource and is the basis for the video
display in Stella. All ports should derive from this class for
platform-specific video stuff.
This class also implements a MAME-like user interface where Stella settings
can be changed.
@author Stephen Anthony
@version $Id: FrameBuffer.hxx,v 1.1 2003-10-17 18:02:16 stephena Exp $
@version $Id: FrameBuffer.hxx,v 1.2 2003-10-26 19:40:39 stephena Exp $
*/
class FrameBuffer
{
@ -44,13 +48,58 @@ class FrameBuffer
/**
Destructor
*/
virtual ~FrameBuffer(void);
virtual ~FrameBuffer();
/**
Initializes the framebuffer display. This must be called before any
calls are made to derived methods.
@param console The console
@param mediasrc The console
*/
void initDisplay(Console* console, MediaSource* mediasrc);
/**
Updates the display. Also draws any pending menus, etc.
*/
void update();
/**
Shows the main menu onscreen. This will only be called if event
remapping has been enabled in the event handler.
@param show Show/hide the menu based on the boolean value
*/
void showMainMenu(bool show);
/**
Shows a message onscreen.
@param message The message to be shown
*/
void showMessage(const string& message);
/**
Returns the current width of the framebuffer.
Note that this will take into account the current scaling (if any).
@return The current width
*/
uInt32 width() { return myWidth; }
/**
Returns the current height of the framebuffer.
Note that this will take into account the current scaling (if any).
@return The current height
*/
uInt32 height() { return myHeight; }
/**
Send a keyboard event to the user interface.
@param code The StellaEvent code
@param state The StellaEvent state
@param code The StellaEvent code
@param state The StellaEvent state
*/
void sendKeyEvent(StellaEvent::KeyCode code, Int32 state);
@ -64,40 +113,104 @@ class FrameBuffer
void sendJoyEvent(StellaEvent::JoyStick stick, StellaEvent::JoyCode code,
Int32 state);
void showMainMenu(bool show);
void showMessage(const string& message);
uInt32 width() { return myWidth; }
uInt32 height() { return myHeight; }
uInt16* pixels() const;
/**
Answers if the display is currently in fullscreen mode.
Returns the mediasource used in the framebuffer.
@result The mediasource for this framebuffer
*/
bool fullScreen() { return isFullscreen; }
MediaSource* mediaSource() const;
public:
//////////////////////////////////////////////////////////////////////
// The following methods are system-specific and must be implemented
// in derived classes.
//////////////////////////////////////////////////////////////////////
/**
This routine should be called once the console is created to setup
the video system for us to use. Return false if any operation fails,
otherwise return true.
*/
virtual bool init(Console* console, MediaSource* mediasrc) = 0;
virtual bool init() = 0;
/**
This routine should be called anytime the display needs to be updated
This routine should be called anytime the MediaSource needs to be redrawn
to the screen.
*/
virtual void update() = 0;
virtual void drawMediaSource() = 0;
/**
Toggles between fullscreen and windowed mode.
This routine should be called to draw a rectangular box with sides
at the specified coordinates.
@param x The x coordinate
@param y The y coordinate
@param w The width of the box
@param h The height of the box
@param fg The color of the bounding sides
@param bg The color of the background
*/
virtual void toggleFullscreen() = 0;
virtual void drawBoundedBox(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt8 fg, uInt8 bg) = 0;
/**
This routine should be called to draw text at the specified coordinates.
@param x The x coordinate
@param y The y coordinate
@param message The message text
@param fg The color of the text
*/
virtual void drawText(uInt32 x, uInt32 y, const string& message, uInt8 fg) = 0;
/**
This routine should be called to draw character 'c' at the specified coordinates.
@param x The x coordinate
@param y The y coordinate
@param c The character to draw
@param fg The color of the character
*/
virtual void drawChar(uInt32 x, uInt32 y, uInt32 c, uInt8 fg) = 0;
/**
This routine is called before any drawing is done (per-frame).
*/
virtual void preFrameUpdate() = 0;
/**
This routine is called after any drawing is done (per-frame).
*/
virtual void postFrameUpdate() = 0;
/**
This routine is called when the emulation has been paused.
@param status Toggle pause based on status
*/
virtual void pause(bool status) = 0;
protected:
// The Console for the system
Console* myConsole;
// The Mediasource for the system
MediaSource* myMediaSource;
// Bounds for the window frame
uInt32 myWidth, myHeight;
// Indicates if the entire frame should be redrawn
bool theRedrawEntireFrameIndicator;
// Indicates the current pause status
bool myPauseStatus;
// Table of bitmapped fonts.
static const uInt8 ourFontData[2048];
private:
// Enumeration representing the different types of user interface widgets
enum Widget { W_NONE, MAIN_MENU, REMAP_MENU, INFO_MENU, FONTS_MENU };
enum Widget { W_NONE, MAIN_MENU, REMAP_MENU, INFO_MENU };
Widget currentSelectedWidget();
Event::Type currentSelectedEvent();
@ -112,6 +225,15 @@ class FrameBuffer
// Remove all bindings for this core event
void deleteBinding(Event::Type event);
// Draw the main menu
void drawMainMenu();
// Draw the remap menu
void drawRemapMenu();
// Draw the info menu
void drawInfoMenu();
// Move the cursor up 1 line, possibly scrolling the list of items
void moveCursorUp();
@ -127,15 +249,7 @@ class FrameBuffer
// scan the mapping arrays and update the remap menu
void loadRemapMenu();
void initBase(Console* console, MediaSource* mediasrc);
protected:
// The Console for the system
Console* myConsole;
// The Mediasource for the system
MediaSource* myMediaSource;
private:
// Indicates the current framerate of the system
uInt32 myFrameRate;
@ -154,12 +268,6 @@ class FrameBuffer
string key;
};
// Bounds for the window frame
uInt32 myXStart, myYStart, myWidth, myHeight;
// Table of bitmapped fonts.
static const uInt8 ourFontData[2048];
// Table of strings representing the various StellaEvent codes
static const char* ourEventName[StellaEvent::LastKCODE];
@ -195,7 +303,7 @@ class FrameBuffer
string ourPropertiesInfo[6];
// Holds static strings for the main menu
static MainMenuItem ourMainMenu[3];
static MainMenuItem ourMainMenu[2];
// Holds static strings for the remap menu
static RemapMenuItem ourRemapMenu[57];
@ -211,9 +319,6 @@ class FrameBuffer
// Holds the number of items in the joytable array
uInt32 myJoyTableSize;
// Indicates whether the emulator is currently in fullscreen mode
bool isFullscreen; // FIXME - remove from here, its specific
};
#endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: MediaSrc.hxx,v 1.5 2003-09-26 22:39:36 stephena Exp $
// $Id: MediaSrc.hxx,v 1.6 2003-10-26 19:40:39 stephena Exp $
//============================================================================
#ifndef MEDIASOURCE_HXX
@ -29,7 +29,7 @@ class MediaSource;
This class provides an interface for accessing graphics and audio data.
@author Bradford W. Mott
@version $Id: MediaSrc.hxx,v 1.5 2003-09-26 22:39:36 stephena Exp $
@version $Id: MediaSrc.hxx,v 1.6 2003-10-26 19:40:39 stephena Exp $
*/
class MediaSource
{
@ -53,16 +53,6 @@ class MediaSource
*/
virtual void update() = 0;
/**
This method should be called to change the pause state of the
media source. Once the media source is paused further calls to
the update method will be ignored until the media source is
unpaused.
@return Status of the pause, success (true) or failure (false)
*/
virtual bool pause(bool state) = 0;
/**
Answers the current frame buffer

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Settings.hxx,v 1.7 2003-09-23 17:27:11 stephena Exp $
// $Id: Settings.hxx,v 1.8 2003-10-26 19:40:39 stephena Exp $
//============================================================================
#ifndef SETTINGS_HXX
@ -32,7 +32,7 @@ class Console;
This class provides an interface for accessing frontend specific settings.
@author Stephen Anthony
@version $Id: Settings.hxx,v 1.7 2003-09-23 17:27:11 stephena Exp $
@version $Id: Settings.hxx,v 1.8 2003-10-26 19:40:39 stephena Exp $
*/
class Settings
{
@ -151,7 +151,7 @@ class Settings
This method should be called at when the emulation core receives
a PAUSE event.
*/
void setPauseEvent() { myPauseIndicator = !myPauseIndicator; }
void setPauseEvent(bool status) { myPauseIndicator = status; }
/**
This method determines whether the PAUSE event has been received.

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: TIA.cxx,v 1.24 2003-10-17 18:02:16 stephena Exp $
// $Id: TIA.cxx,v 1.25 2003-10-26 19:40:39 stephena Exp $
//============================================================================
#include <cassert>
@ -35,7 +35,6 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TIA::TIA(const Console& console, uInt32 sampleRate)
: myConsole(console),
myPauseState(false),
myLastSoundUpdateCycle(0),
myColorLossEnabled(false),
myCOLUBK(myColor[0]),
@ -510,12 +509,6 @@ bool TIA::load(Deserializer& in)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIA::update()
{
// Don't do an update if the emulator is paused
if(myPauseState)
{
return;
}
uInt8* tmp = myCurrentFrameBuffer;
myCurrentFrameBuffer = myPreviousFrameBuffer;
myPreviousFrameBuffer = tmp;
@ -572,21 +565,6 @@ void TIA::update()
myScanlineCountForLastFrame = totalClocks / 228;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool TIA::pause(bool state)
{
if(myPauseState == state)
{
// Ignore multiple calls to do the same thing
return false;
}
else
{
myPauseState = state;
return true;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt32* TIA::palette() const
{
@ -3217,4 +3195,3 @@ uInt32 TIA::SampleQueue::size() const
{
return mySize;
}

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: TIA.hxx,v 1.9 2003-09-28 21:59:24 stephena Exp $
// $Id: TIA.hxx,v 1.10 2003-10-26 19:40:39 stephena Exp $
//============================================================================
#ifndef TIA_HXX
@ -43,7 +43,7 @@ class Deserializer;
in a bounded queue.
@author Bradford W. Mott
@version $Id: TIA.hxx,v 1.9 2003-09-28 21:59:24 stephena Exp $
@version $Id: TIA.hxx,v 1.10 2003-10-26 19:40:39 stephena Exp $
*/
class TIA : public Device , public MediaSource
{
@ -128,15 +128,6 @@ class TIA : public Device , public MediaSource
*/
virtual void update();
/**
This method should be called to cause further calls to 'update'
to be ignored until an unpause is given. Will also send a mute to
the Sound device.
@return Status of the pause, success (true) or failure (false)
*/
virtual bool pause(bool state);
/**
Answers the current frame buffer
@ -307,9 +298,6 @@ class TIA : public Device , public MediaSource
// Console the TIA is associated with
const Console& myConsole;
// Indicates whether the emulation is paused or not
bool myPauseState;
private:
// Indicates the CPU cycle when a TIA sound register was last updated
Int32 myLastSoundUpdateCycle;

View File

@ -0,0 +1,611 @@
//============================================================================
//
// 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-1999 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: FrameBufferSDL.cxx,v 1.1 2003-10-26 19:40:39 stephena Exp $
//============================================================================
#include <SDL.h>
#include <SDL_syswm.h>
#include <sstream>
#include "Console.hxx"
#include "FrameBuffer.hxx"
#include "FrameBufferSDL.hxx"
#include "MediaSrc.hxx"
#include "RectList.hxx"
#include "Settings.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBufferSDL::FrameBufferSDL()
: x11Available(false),
theZoomLevel(1),
theMaxZoomLevel(1),
isCentered(false),
theGrabMouseIndicator(false),
theHideCursorIndicator(false),
isFullscreen(false)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBufferSDL::~FrameBufferSDL()
{
if(myRectList)
delete myRectList;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferSDL::init()
{
// Get the desired width and height of the display
myWidth = myMediaSource->width() << 1;
myHeight = myMediaSource->height();
// Now create the software SDL screen
Uint32 initflags = SDL_INIT_VIDEO | SDL_INIT_TIMER;
if(SDL_Init(initflags) < 0)
return false;
// Check which system we are running under
x11Available = false;
SDL_VERSION(&myWMInfo.version);
if(SDL_GetWMInfo(&myWMInfo) > 0)
if(myWMInfo.subsystem == SDL_SYSWM_X11)
x11Available = true;
// Get the maximum size of a window for THIS screen
theMaxZoomLevel = maxWindowSizeForScreen();
// Check to see if window size will fit in the screen
if((uInt32)myConsole->settings().getInt("zoom") > theMaxZoomLevel)
theZoomLevel = theMaxZoomLevel;
else
theZoomLevel = myConsole->settings().getInt("zoom");
mySDLFlags = SDL_SWSURFACE;
mySDLFlags |= myConsole->settings().getBool("fullscreen") ? SDL_FULLSCREEN : 0;
// Set up the rectangle list to be used in the dirty update
myRectList = new RectList();
if(!myRectList)
{
cerr << "ERROR: Unable to get memory for SDL rects" << endl;
return false;
}
// Set the window title and icon
ostringstream name;
name << "Stella: \"" << myConsole->properties().get("Cartridge.Name") << "\"";
SDL_WM_SetCaption(name.str().c_str(), "stella");
// Create the screen
if(!createScreen())
return false;
setupPalette(1.0);
// Make sure that theUseFullScreenFlag sets up fullscreen mode correctly
theGrabMouseIndicator = myConsole->settings().getBool("grabmouse");
theHideCursorIndicator = myConsole->settings().getBool("hidecursor");
if(myConsole->settings().getBool("fullscreen"))
{
grabMouse(true);
showCursor(false);
isFullscreen = true;
}
else
{
// Keep mouse in game window if grabmouse is selected
grabMouse(theGrabMouseIndicator);
// Show or hide the cursor depending on the 'hidecursor' argument
showCursor(!theHideCursorIndicator);
}
// Center the window if centering is selected and not fullscreen
if(myConsole->settings().getBool("center") &&
!myConsole->settings().getBool("fullscreen"))
centerScreen();
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL::drawMediaSource()
{
uInt8* currentFrame = myMediaSource->currentFrameBuffer();
uInt8* previousFrame = myMediaSource->previousFrameBuffer();
uInt16 screenMultiple = (uInt16) theZoomLevel;
uInt32 width = myMediaSource->width();
uInt32 height = myMediaSource->height();
struct Rectangle
{
uInt8 color;
uInt16 x, y, width, height;
} rectangles[2][160];
// This array represents the rectangles that need displaying
// on the current scanline we're processing
Rectangle* currentRectangles = rectangles[0];
// This array represents the rectangles that are still active
// from the previous scanlines we have processed
Rectangle* activeRectangles = rectangles[1];
// Indicates the number of active rectangles
uInt16 activeCount = 0;
// This update procedure requires theWidth to be a multiple of four.
// This is validated when the properties are loaded.
for(uInt16 y = 0; y < height; ++y)
{
// Indicates the number of current rectangles
uInt16 currentCount = 0;
// Look at four pixels at a time to see if anything has changed
uInt32* current = (uInt32*)(currentFrame);
uInt32* previous = (uInt32*)(previousFrame);
for(uInt16 x = 0; x < width; x += 4, ++current, ++previous)
{
// Has something changed in this set of four pixels?
if((*current != *previous) || theRedrawEntireFrameIndicator)
{
uInt8* c = (uInt8*)current;
uInt8* p = (uInt8*)previous;
// Look at each of the bytes that make up the uInt32
for(uInt16 i = 0; i < 4; ++i, ++c, ++p)
{
// See if this pixel has changed
if((*c != *p) || theRedrawEntireFrameIndicator)
{
// Can we extend a rectangle or do we have to create a new one?
if((currentCount != 0) &&
(currentRectangles[currentCount - 1].color == *c) &&
((currentRectangles[currentCount - 1].x +
currentRectangles[currentCount - 1].width) == (x + i)))
{
currentRectangles[currentCount - 1].width += 1;
}
else
{
currentRectangles[currentCount].x = x + i;
currentRectangles[currentCount].y = y;
currentRectangles[currentCount].width = 1;
currentRectangles[currentCount].height = 1;
currentRectangles[currentCount].color = *c;
currentCount++;
}
}
}
}
}
// Merge the active and current rectangles flushing any that are of no use
uInt16 activeIndex = 0;
for(uInt16 t = 0; (t < currentCount) && (activeIndex < activeCount); ++t)
{
Rectangle& current = currentRectangles[t];
Rectangle& active = activeRectangles[activeIndex];
// Can we merge the current rectangle with an active one?
if((current.x == active.x) && (current.width == active.width) &&
(current.color == active.color))
{
current.y = active.y;
current.height = active.height + 1;
++activeIndex;
}
// Is it impossible for this active rectangle to be merged?
else if(current.x >= active.x)
{
// Flush the active rectangle
SDL_Rect temp;
temp.x = active.x * screenMultiple << 1;
temp.y = active.y * screenMultiple;
temp.w = active.width * screenMultiple << 1;
temp.h = active.height * screenMultiple;
myRectList->add(&temp);
SDL_FillRect(myScreen, &temp, palette[active.color]);
++activeIndex;
}
}
// Flush any remaining active rectangles
for(uInt16 s = activeIndex; s < activeCount; ++s)
{
Rectangle& active = activeRectangles[s];
SDL_Rect temp;
temp.x = active.x * screenMultiple << 1;
temp.y = active.y * screenMultiple;
temp.w = active.width * screenMultiple << 1;
temp.h = active.height * screenMultiple;
myRectList->add(&temp);
SDL_FillRect(myScreen, &temp, palette[active.color]);
}
// We can now make the current rectangles into the active rectangles
Rectangle* tmp = currentRectangles;
currentRectangles = activeRectangles;
activeRectangles = tmp;
activeCount = currentCount;
currentFrame += width;
previousFrame += width;
}
// Flush any rectangles that are still active
for(uInt16 t = 0; t < activeCount; ++t)
{
Rectangle& active = activeRectangles[t];
SDL_Rect temp;
temp.x = active.x * screenMultiple << 1;
temp.y = active.y * screenMultiple;
temp.w = active.width * screenMultiple << 1;
temp.h = active.height * screenMultiple;
myRectList->add(&temp);
SDL_FillRect(myScreen, &temp, palette[active.color]);
}
// The frame doesn't need to be completely redrawn anymore
theRedrawEntireFrameIndicator = false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL::preFrameUpdate()
{
// Start a new rectlist on each display update
myRectList->start();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL::postFrameUpdate()
{
// Now update all the rectangles at once
SDL_UpdateRects(myScreen, myRectList->numRects(), myRectList->rects());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferSDL::createScreen()
{
int w = myWidth * theZoomLevel;
int h = myHeight * theZoomLevel;
myScreen = SDL_SetVideoMode(w, h, 0, mySDLFlags);
if(myScreen == NULL)
{
cerr << "ERROR: Unable to open SDL window: " << SDL_GetError() << endl;
return false;
}
theRedrawEntireFrameIndicator = true;
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL::setupPalette(float shade)
{
const uInt32* gamePalette = myMediaSource->palette();
for(uInt32 i = 0; i < 256; ++i)
{
Uint8 r, g, b;
r = (Uint8) (((gamePalette[i] & 0x00ff0000) >> 16) * shade);
g = (Uint8) (((gamePalette[i] & 0x0000ff00) >> 8) * shade);
b = (Uint8) ((gamePalette[i] & 0x000000ff) * shade);
switch(myScreen->format->BitsPerPixel)
{
case 15:
palette[i] = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
break;
case 16:
palette[i] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
break;
case 24:
case 32:
palette[i] = (r << 16) | (g << 8) | b;
break;
}
}
theRedrawEntireFrameIndicator = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL::pause(bool status)
{
myPauseStatus = status;
// Shade the palette to 75% normal value in pause mode
if(myPauseStatus)
setupPalette(0.75);
else
setupPalette(1.0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL::toggleFullscreen()
{
isFullscreen = !isFullscreen;
if(isFullscreen)
mySDLFlags |= SDL_FULLSCREEN;
else
mySDLFlags &= ~SDL_FULLSCREEN;
if(!createScreen())
return;
if(isFullscreen) // now in fullscreen mode
{
grabMouse(true);
showCursor(false);
}
else // now in windowed mode
{
grabMouse(theGrabMouseIndicator);
showCursor(!theHideCursorIndicator);
if(myConsole->settings().getBool("center"))
centerScreen();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL::resize(int mode)
{
// reset size to that given in properties
// this is a special case of allowing a resize while in fullscreen mode
if(mode == 0)
{
myWidth = myMediaSource->width() << 1;
myHeight = myMediaSource->height();
}
else if(mode == 1) // increase size
{
if(isFullscreen)
return;
if(theZoomLevel == theMaxZoomLevel)
theZoomLevel = 1;
else
theZoomLevel++;
}
else if(mode == -1) // decrease size
{
if(isFullscreen)
return;
if(theZoomLevel == 1)
theZoomLevel = theMaxZoomLevel;
else
theZoomLevel--;
}
if(!createScreen())
return;
// A resize may mean that the window is no longer centered
isCentered = false;
if(myConsole->settings().getBool("center"))
centerScreen();
// Now update the settings
ostringstream tmp;
tmp << theZoomLevel;
myConsole->settings().set("zoom", tmp.str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL::showCursor(bool show)
{
if(isFullscreen)
return;
if(show)
SDL_ShowCursor(SDL_ENABLE);
else
SDL_ShowCursor(SDL_DISABLE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL::grabMouse(bool grab)
{
if(isFullscreen)
return;
if(grab)
SDL_WM_GrabInput(SDL_GRAB_ON);
else
SDL_WM_GrabInput(SDL_GRAB_OFF);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL::centerScreen()
{
if(!x11Available)
{
cerr << "Window centering only available under X11.\n";
return;
}
if(isFullscreen || isCentered)
return;
uInt32 x, y, w, h;
myWMInfo.info.x11.lock_func();
Display* theX11Display = myWMInfo.info.x11.display;
Window theX11Window = myWMInfo.info.x11.wmwindow;
w = DisplayWidth(theX11Display, DefaultScreen(theX11Display));
h = DisplayHeight(theX11Display, DefaultScreen(theX11Display));
x = (w - myScreen->w)/2;
y = (h - myScreen->h)/2;
XMoveWindow(theX11Display, theX11Window, x, y);
myWMInfo.info.x11.unlock_func();
isCentered = true;
theRedrawEntireFrameIndicator = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 FrameBufferSDL::maxWindowSizeForScreen()
{
if(!x11Available)
return 1;
// Otherwise, lock the screen and get the width and height
myWMInfo.info.x11.lock_func();
Display* theX11Display = myWMInfo.info.x11.display;
myWMInfo.info.x11.unlock_func();
int screenWidth = DisplayWidth(theX11Display, DefaultScreen(theX11Display));
int screenHeight = DisplayHeight(theX11Display, DefaultScreen(theX11Display));
uInt32 multiplier = screenWidth / myWidth;
bool found = false;
while(!found && (multiplier > 0))
{
// Figure out the desired size of the window
int width = myWidth * multiplier;
int height = myHeight * multiplier;
if((width < screenWidth) && (height < screenHeight))
found = true;
else
multiplier--;
}
if(found)
return multiplier;
else
return 1;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL::drawBoundedBox(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
uInt8 fg, uInt8 bg)
{
SDL_Rect tmp;
// Scale all values to the current window size
x *= theZoomLevel;
y *= theZoomLevel;
w *= theZoomLevel;
h *= theZoomLevel;
// First draw the underlying box
tmp.x = x;
tmp.y = y;
tmp.w = w;
tmp.h = h;
myRectList->add(&tmp);
SDL_FillRect(myScreen, &tmp, palette[bg]);
// Now draw the bounding sides
tmp.x = x;
tmp.y = y;
tmp.w = w;
tmp.h = theZoomLevel;
SDL_FillRect(myScreen, &tmp, palette[fg]); // top
tmp.x = x;
tmp.y = y + h - theZoomLevel;
tmp.w = w;
tmp.h = theZoomLevel;
SDL_FillRect(myScreen, &tmp, palette[fg]); // bottom
tmp.x = x;
tmp.y = y;
tmp.w = theZoomLevel;
tmp.h = h;
SDL_FillRect(myScreen, &tmp, palette[fg]); // left
tmp.x = x + w - theZoomLevel;
tmp.y = y;
tmp.w = theZoomLevel;
tmp.h = h;
SDL_FillRect(myScreen, &tmp, palette[fg]); // right
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL::drawText(uInt32 xorig, uInt32 yorig,
const string& message, uInt8 fg)
{
SDL_Rect tmp;
uInt8 length = message.length();
for(uInt32 x = 0; x < length; x++)
{
for(uInt32 y = 0; y < 8; y++)
{
for(uInt32 z = 0; z < 8; z++)
{
char letter = message[x];
if((ourFontData[(letter << 3) + y] >> z) & 1)
{
// myFrameBuffer[(y + yorig)*myWidth + (x<<3) + z + xorig] = 0xF0F0F0;
tmp.x = ((x<<3) + z + xorig) * theZoomLevel;
tmp.y = (y + yorig) * theZoomLevel;
tmp.w = tmp.h = theZoomLevel;
SDL_FillRect(myScreen, &tmp, palette[fg]);
// FIXME - this can be a lot more efficient
}
}
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL::drawChar(uInt32 xorig, uInt32 yorig, uInt32 c, uInt8 fg)
{
if(c >= 256 )
return;
SDL_Rect tmp;
for(uInt32 y = 0; y < 8; y++)
{
for(uInt32 z = 0; z < 8; z++)
{
if((ourFontData[(c << 3) + y] >> z) & 1)
{
// myFrameBuffer[(y + yorig)*myWidth + z + xorig] = 0xF0F0F0;
tmp.x = (z + xorig) * theZoomLevel;
tmp.y = (y + yorig) * theZoomLevel;
tmp.w = tmp.h = theZoomLevel;
myRectList->add(&tmp);
SDL_FillRect(myScreen, &tmp, palette[fg]);
// FIXME - this can be a lot more efficient
}
}
}
}

View File

@ -0,0 +1,205 @@
//============================================================================
//
// 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-1999 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: FrameBufferSDL.hxx,v 1.1 2003-10-26 19:40:39 stephena Exp $
//============================================================================
#ifndef FRAMEBUFFER_SDL_HXX
#define FRAMEBUFFER_SDL_HXX
#include <SDL.h>
#include <SDL_syswm.h>
#include "FrameBuffer.hxx"
#include "bspf.hxx"
class Console;
class MediaSource;
class RectList;
class FrameBufferSDL : public FrameBuffer
{
public:
/**
Creates a new SDL software framebuffer
*/
FrameBufferSDL();
/**
Destructor
*/
virtual ~FrameBufferSDL();
/**
This routine should be called once the console is created to setup
the video system for us to use. Return false if any operation fails,
otherwise return true.
*/
virtual bool init();
/**
This routine should be called anytime the MediaSource needs to be redrawn
to the screen.
*/
virtual void drawMediaSource();
/**
This routine should be called to draw a rectangular box with sides
at the specified coordinates.
@param x The x coordinate
@param y The y coordinate
@param w The width of the box
@param h The height of the box
@param fg The color of the bounding sides
@param bg The color of the background
*/
virtual void drawBoundedBox(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt8 fg, uInt8 bg);
/**
This routine should be called to draw text at the specified coordinates.
@param x The x coordinate
@param y The y coordinate
@param message The message text
@param fg The color of the text
*/
virtual void drawText(uInt32 x, uInt32 y, const string& message, uInt8 fg);
/**
This routine should be called to draw character 'c' at the specified coordinates.
@param x The x coordinate
@param y The y coordinate
@param c The character to draw
@param fg The color of the character
*/
virtual void drawChar(uInt32 x, uInt32 y, uInt32 c, uInt8 fg);
/**
This routine is called before any drawing is done (per-frame).
*/
virtual void preFrameUpdate();
/**
This routine is called after any drawing is done (per-frame).
*/
virtual void postFrameUpdate();
/**
This routine is called when the emulation has been paused.
@param status Toggle pause based on status
*/
virtual void pause(bool status);
/**
Toggles between fullscreen and window mode. Grabmouse and hidecursor
activated when in fullscreen mode.
*/
void toggleFullscreen();
/**
This routine is called when the user wants to resize the window.
A '1' argument indicates that the window should increase in size, while '-1'
indicates that the windows should decrease in size. A '0' indicates that
the window should be sized according to the current properties.
Can't resize in fullscreen mode. Will only resize up to the maximum size
of the screen.
*/
void resize(int mode);
/**
Shows or hides the cursor based on the given boolean value.
*/
void showCursor(bool show);
/**
Grabs or ungrabs the mouse based on the given boolean value.
*/
void grabMouse(bool grab);
/**
Answers if the display is currently in fullscreen mode.
*/
bool fullScreen() { return isFullscreen; }
/**
Answers the current zoom level of the SDL
*/
uInt32 zoomLevel() { return theZoomLevel; }
/**
This routine is called whenever the screen needs to be recreated.
It updates the global screen variable.
*/
bool createScreen();
/**
Centers the game window onscreen. Only works in X11 for now.
*/
void centerScreen();
/**
Calculate the maximum window size that the current screen can hold.
Only works in X11 for now. If not running under X11, always return 4.
*/
uInt32 maxWindowSizeForScreen();
/**
Set up the palette for a screen of any depth > 8.
Scales the palette by 'shade'.
*/
void setupPalette(float shade);
private:
// The SDL video buffer
SDL_Surface* myScreen;
// Used in the dirty update of the SDL surface
RectList* myRectList;
// SDL initialization flags
uInt32 mySDLFlags;
// SDL palette
Uint32 palette[256];
// Used to get window-manager specifics
SDL_SysWMinfo myWMInfo;
// Indicates if we are running under X11
bool x11Available;
// Indicates the current zoom level of the SDL screen
uInt32 theZoomLevel;
// Indicates the maximum zoom of the SDL screen
uInt32 theMaxZoomLevel;
// Indicates whether the window is currently centered
bool isCentered;
// Indicates if the mouse should be grabbed
bool theGrabMouseIndicator;
// Indicates if the mouse cursor should be hidden
bool theHideCursorIndicator;
// Indicates whether the game is currently in fullscreen
bool isFullscreen;
};
#endif

View File

@ -0,0 +1,197 @@
//============================================================================
//
// 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-1999 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: SettingsUNIX.cxx,v 1.1 2003-10-26 19:40:39 stephena Exp $
//============================================================================
#include <cstdlib>
#include <sstream>
#include <fstream>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "bspf.hxx"
#include "Console.hxx"
#include "EventHandler.hxx"
#include "StellaEvent.hxx"
#include "Settings.hxx"
#include "SettingsUNIX.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SettingsUNIX::SettingsUNIX()
{
// First set variables that the parent class needs
myBaseDir = getenv("HOME");
string stelladir = myBaseDir + "/.stella";
if(access(stelladir.c_str(), R_OK|W_OK|X_OK) != 0 )
mkdir(stelladir.c_str(), 0777);
myStateDir = stelladir + "/state/";
if(access(myStateDir.c_str(), R_OK|W_OK|X_OK) != 0 )
mkdir(myStateDir.c_str(), 0777);
myUserPropertiesFile = stelladir + "/stella.pro";
mySystemPropertiesFile = "/etc/stella.pro";
myUserConfigFile = stelladir + "/stellarc";
mySystemConfigFile = "/etc/stellarc";
// Set up the names of the input and output config files
mySettingsOutputFilename = myUserConfigFile;
if(access(myUserConfigFile.c_str(), R_OK) == 0)
mySettingsInputFilename = myUserConfigFile;
else
mySettingsInputFilename = mySystemConfigFile;
mySnapshotFile = "";
myStateFile = "";
// Now create UNIX specific settings
#ifdef DISPLAY_OPENGL
set("opengl", "false");
#endif
set("fullscreen", "false");
set("grabmouse", "false");
set("center", "false");
set("hidecursor", "false");
set("accurate", "true");
set("volume", "-1");
set("sound", "oss");
set("joyleft", "0");
set("joyright", "1");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SettingsUNIX::~SettingsUNIX()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SettingsUNIX::usage(string& message)
{
cout << endl
<< message << endl
<< endl
<< "Valid options are:" << endl
<< endl
<< " -framerate <number> Display the given number of frames per second\n"
<< " -zoom <size> Makes window be 'size' times normal\n"
<< " -fullscreen <0|1> Play the game in fullscreen mode\n"
<< " -grabmouse <0|1> Keeps the mouse in the game window\n"
<< " -hidecursor <0|1> Hides the mouse cursor in the game window\n"
<< " -center <0|1> Centers the game window onscreen\n"
<< " -volume <number> Set the volume (0 - 100)\n"
#ifdef DISPLAY_OPENGL
<< " -opengl <0|1> Use OpenGL mode.\n"
#endif
#ifdef HAVE_JOYSTICK
<< " -paddle <0|1|2|3|real> Indicates which paddle the mouse should emulate\n"
<< " or that real Atari 2600 paddles are being used\n"
<< " -joyleft <number> The joystick number representing the left controller\n"
<< " -joyright <number> The joystick number representing the right controller\n"
#else
<< " -paddle <0|1|2|3> Indicates which paddle the mouse should emulate\n"
#endif
<< " -altpro <props file> Use the given properties file instead of stella.pro\n"
<< " -showinfo <0|1> Shows some game info\n"
<< " -accurate <0|1> Accurate game timing (uses more CPU)\n"
#ifdef SNAPSHOT_SUPPORT
<< " -ssdir <path> The directory to save snapshot files to\n"
<< " -ssname <name> How to name the snapshot (romname or md5sum)\n"
<< " -sssingle <0|1> Generate single snapshot instead of many\n"
#endif
<< endl
<< " -sound <type> Type is one of the following:\n"
<< " 0 Disables all sound generation\n"
#ifdef SOUND_ALSA
<< " alsa ALSA version 0.9 driver\n"
#endif
#ifdef SOUND_OSS
<< " oss Open Sound System driver\n"
#endif
<< endl
#ifdef DEVELOPER_SUPPORT
<< " DEVELOPER options (see Stella manual for details)\n"
<< " -Dformat Sets \"Display.Format\"\n"
<< " -Dxstart Sets \"Display.XStart\"\n"
<< " -Dwidth Sets \"Display.Width\"\n"
<< " -Dystart Sets \"Display.YStart\"\n"
<< " -Dheight Sets \"Display.Height\"\n"
<< " -mergeprops <0|1> Merge changed properties into properties file,\n"
<< " or save into a separate file\n"
#endif
<< endl;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string SettingsUNIX::stateFilename(uInt32 state)
{
if(!myConsole)
return "";
ostringstream buf;
buf << myStateDir << myConsole->properties().get("Cartridge.MD5")
<< ".st" << state;
myStateFile = buf.str();
return myStateFile;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string SettingsUNIX::snapshotFilename()
{
if(!myConsole)
return "";
string filename;
string path = getString("ssdir");
string theSnapshotName = getString("ssname");
if(theSnapshotName == "romname")
path = path + "/" + myConsole->properties().get("Cartridge.Name");
else if(theSnapshotName == "md5sum")
path = path + "/" + myConsole->properties().get("Cartridge.MD5");
// Replace all spaces in name with underscores
replace(path.begin(), path.end(), ' ', '_');
// Check whether we want multiple snapshots created
if(!getBool("sssingle"))
{
// Determine if the file already exists, checking each successive filename
// until one doesn't exist
filename = path + ".png";
if(access(filename.c_str(), F_OK) == 0 )
{
ostringstream buf;
for(uInt32 i = 1; ;++i)
{
buf.str("");
buf << path << "_" << i << ".png";
if(access(buf.str().c_str(), F_OK) == -1 )
break;
}
filename = buf.str();
}
}
else
filename = path + ".png";
mySnapshotFile = filename;
return mySnapshotFile;
}

View File

@ -0,0 +1,70 @@
//============================================================================
//
// 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-1999 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: SettingsUNIX.hxx,v 1.1 2003-10-26 19:40:39 stephena Exp $
//============================================================================
#ifndef SETTINGS_UNIX_HXX
#define SETTINGS_UNIX_HXX
#include "bspf.hxx"
class Console;
/**
This class defines UNIX-like OS's (Linux) system specific settings.
@author Stephen Anthony
@version $Id: SettingsUNIX.hxx,v 1.1 2003-10-26 19:40:39 stephena Exp $
*/
class SettingsUNIX : public Settings
{
public:
/**
Create a new UNIX settings object
*/
SettingsUNIX();
/**
Destructor
*/
virtual ~SettingsUNIX();
public:
/**
This method should be called to get the filename of a state file
given the state number.
@return String representing the full path of the state filename.
*/
virtual string stateFilename(uInt32 state);
/**
This method should be called to get the filename of a snapshot.
@return String representing the full path of the snapshot filename.
*/
virtual string snapshotFilename();
/**
Display the commandline settings for this UNIX version of Stella.
@param message A short message about this version of Stella
*/
virtual void usage(string& message);
};
#endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: mainSDL.cxx,v 1.55 2003-10-17 18:02:16 stephena Exp $
// $Id: mainSDL.cxx,v 1.56 2003-10-26 19:40:39 stephena Exp $
//============================================================================
#include <fstream>
@ -95,6 +95,9 @@ static bool theHideCursorIndicator = false;
// Indicates the current paddle mode
static Int32 thePaddleMode;
// Indicates relative mouse position horizontally
static Int32 mouseX = 0;
// Indicates whether to show information during program execution
static bool theShowInfoFlag;
@ -331,29 +334,29 @@ void handleEvents()
if(key == SDLK_EQUALS)
theDisplay->resize(1);
else if(key == SDLK_MINUS)
theDisplay->resize(0);
theDisplay->resize(-1);
else if(key == SDLK_RETURN)
theDisplay->toggleFullscreen();
#ifdef DEVELOPER_SUPPORT
else if(key == SDLK_END) // Alt-End increases XStart
{
theConsole->changeXStart(1);
theDisplay->resize(-1);
theDisplay->resize(0);
}
else if(key == SDLK_HOME) // Alt-Home decreases XStart
{
theConsole->changeXStart(0);
theDisplay->resize(-1);
theDisplay->resize(0);
}
else if(key == SDLK_PAGEUP) // Alt-PageUp increases YStart
{
theConsole->changeYStart(1);
theDisplay->resize(-1);
theDisplay->resize(0);
}
else if(key == SDLK_PAGEDOWN) // Alt-PageDown decreases YStart
{
theConsole->changeYStart(0);
theDisplay->resize(-1);
theDisplay->resize(0);
}
#endif
}
@ -381,27 +384,27 @@ void handleEvents()
else if(key == SDLK_f) // Ctrl-f toggles NTSC/PAL mode
{
theConsole->toggleFormat();
theDisplay->setupPalette();
theDisplay->setupPalette(1.0);
}
else if(key == SDLK_END) // Ctrl-End increases Width
{
theConsole->changeWidth(1);
theDisplay->resize(-1);
theDisplay->resize(0);
}
else if(key == SDLK_HOME) // Ctrl-Home decreases Width
{
theConsole->changeWidth(0);
theDisplay->resize(-1);
theDisplay->resize(0);
}
else if(key == SDLK_PAGEUP) // Ctrl-PageUp increases Height
{
theConsole->changeHeight(1);
theDisplay->resize(-1);
theDisplay->resize(0);
}
else if(key == SDLK_PAGEDOWN) // Ctrl-PageDown decreases Height
{
theConsole->changeHeight(0);
theDisplay->resize(-1);
theDisplay->resize(0);
}
else if(key == SDLK_s) // Ctrl-s saves properties to a file
{
@ -441,21 +444,21 @@ void handleEvents()
}
else if(event.type == SDL_MOUSEMOTION)
{
float fudgeFactor = 1000000.0;
Int32 resistance = 0, x = 0, mouseX;
Int32 width = 640;//theWidth * theWindowSize * 2; FIXME
Event::Type type = Event::LastType;
Int32 resistance;
uInt32 zoom = theDisplay->zoomLevel();
Int32 width = theDisplay->width() * zoom;
Event::Type type = Event::NoType;
// Grabmouse and hidecursor introduce some lag into the mouse movement,
// so we need to fudge the numbers a bit
if(theGrabMouseIndicator && theHideCursorIndicator)
{
// mouseX = (int)((float)mouseX + (float)event.motion.xrel
// * 1.5 * (float) theWindowSize); FIXME
mouseX = (int)((float)mouseX + (float)event.motion.xrel
* 1.5 * (float) zoom);
}
else
{
// mouseX = mouseX + event.motion.xrel * theWindowSize; FIXME
mouseX = mouseX + event.motion.xrel * zoom;
}
// Check to make sure mouseX is within the game window
@ -464,8 +467,7 @@ void handleEvents()
else if(mouseX > width)
mouseX = width;
x = width - mouseX;
resistance = (Int32)((fudgeFactor * x) / width);
resistance = (Int32)(1000000.0 * (width - mouseX) / width);
// Now, set the event of the correct paddle to the calculated resistance
if(thePaddleMode == 0)
@ -739,7 +741,7 @@ int main(int argc, char* argv[])
// Get just the filename of the file containing the ROM image
const char* filename = (!strrchr(file, '/')) ? file : strrchr(file, '/') + 1;
// Setup the SDL window and joystick
// Setup the SDL window
#ifdef DISPLAY_OPENGL
bool useGL = theSettings->getBool("opengl");
if(useGL)
@ -755,13 +757,6 @@ int main(int argc, char* argv[])
return 0;
}
if(!setupJoystick())
{
cerr << "ERROR: Couldn't set up joysticks.\n";
cleanup();
return 0;
}
// Create the 2600 game console
theConsole = new Console(image, size, filename, *theSettings, propertiesSet,
*theDisplay, theSound->getSampleRate());
@ -769,6 +764,15 @@ int main(int argc, char* argv[])
// Free the image since we don't need it any longer
delete[] image;
// Setup the SDL joysticks
// This must be done after the console is created
if(!setupJoystick())
{
cerr << "ERROR: Couldn't set up joysticks.\n";
cleanup();
return 0;
}
// These variables are common to both timing options
// and are needed to calculate the overall frames per second.
uInt32 frameTime = 0, numberOfFrames = 0;
@ -802,7 +806,7 @@ int main(int argc, char* argv[])
}
theDisplay->update();
//FIXME theSound->updateSound(theConsole->mediaSource());
theSound->updateSound(*theDisplay->mediaSource());
// Now, waste time if we need to so that we are at the desired frame rate
for(;;)
@ -835,15 +839,20 @@ int main(int argc, char* argv[])
{
break;
}
/*
startTime = getTicks();
handleEvents();
if(!theSettings->pause())
{
//FIXME theSound->updateSound(theConsole->mediaSource());
theSound->updateSound(*theDisplay->mediaSource());
}
theDisplay->update();
*/
startTime = getTicks();
handleEvents();
theDisplay->update();
theSound->updateSound(*theDisplay->mediaSource());
///
currentTime = getTicks();
virtualTime += timePerFrame;
if(currentTime < virtualTime)