Huge changes across the map. Lets see if I can remember it all ...

There is now an SDL OpenGL port with filtering and alpha-blending.
It's a work in progress right now, but is already quite stable.
It's not as optimized as the software version yet, but this will
change as well.  For now, you have to compile the SDL version in
either normal software mode or OpenGL mode.  This will change
before the 1.4 release.

When entering menu mode, the emulation is now suspended.  And when
pause is pressed, you can't enter menu mode.  Because of these changes,
CPU use has dropped dramatically when viewing menus.  This will benefit
all ports, since menus are now redrawn only when necessary, instead of
at the current framerate.

For a reference, on a Pentium-IV 2.4GHz, the software SDL version
maxes CPU usage at 9%, and the SDL OpenGL version at 13.5%.  This is
at 60 fps and a zoomlevel of 4.  While some small improvements can
(possibly) be made to the OpenGL version, I think we'll soon be hitting
the glass ceiling.

Work on the Porting.txt document is progressing, and I estimate it to
be 45% complete.

The Windows version still doesn't compile, and I still haven't looked
at it.  Rest assured that it will be done before 1.4.  There will be
a simultaneous release, even if the Linux versions are finished.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@200 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2003-11-06 22:22:33 +00:00
parent d098cb1207
commit 8239748980
28 changed files with 1225 additions and 341 deletions

View File

@ -13,7 +13,7 @@
## See the file "license" for information on usage and redistribution of ## See the file "license" for information on usage and redistribution of
## this file, and for a DISCLAIMER OF ALL WARRANTIES. ## this file, and for a DISCLAIMER OF ALL WARRANTIES.
## ##
## $Id: makefile,v 1.43 2003-10-26 19:40:39 stephena Exp $ ## $Id: makefile,v 1.44 2003-11-06 22:22:32 stephena Exp $
##============================================================================ ##============================================================================
##============================================================================ ##============================================================================
@ -34,10 +34,10 @@ SOUND_OSS = 1
#SOUND_SDL = 1 #SOUND_SDL = 1
### to include OpenGL video support (SDL) ### to include OpenGL video support (SDL)
#DISPLAY_OPENGL = 1 DISPLAY_OPENGL = 0
### to include joystick support (SDL) ### to include joystick support (SDL)
JOYSTICK_SUPPORT = 1 # JOYSTICK_SUPPORT = 1
### to include support for saving snapshots in png format ### to include support for saving snapshots in png format
### (requires PNG library) FIXME ### (requires PNG library) FIXME
@ -142,10 +142,14 @@ endif
ifeq ($(DISPLAY_OPENGL), 1) ifeq ($(DISPLAY_OPENGL), 1)
OPTS.SDL += -DDISPLAY_OPENGL=1 OPTS.SDL += -DDISPLAY_OPENGL=1
OBJS.SDL += DispGLSDL.o OBJS.SDL += FrameBufferGL.o
LIBS.SDL += -lGL -lGLU LIBS.SDL += -lGL -lGLU
endif endif
ifeq ($(DISPLAY_OPENGL), 0)
OBJS.SDL += FrameBufferSDL.o
endif
default: default:
@echo "" @echo ""
@ -181,7 +185,7 @@ linux-sdl:
LDFLAGS+="$(CFLAGS.SDL)" \ LDFLAGS+="$(CFLAGS.SDL)" \
LDLIBS="-lX11 -lXext" \ LDLIBS="-lX11 -lXext" \
LDLIBS+="$(LIBS.SDL)" \ LDLIBS+="$(LIBS.SDL)" \
OBJS="mainSDL.o FrameBufferSDL.o RectList.o SettingsUNIX.o" \ OBJS="mainSDL.o SettingsUNIX.o" \
OBJS+="$(OBJS.SDL)" OBJS+="$(OBJS.SDL)"
############################################################################### ###############################################################################

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: Console.cxx,v 1.19 2003-10-26 19:40:39 stephena Exp $ // $Id: Console.cxx,v 1.20 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#include <assert.h> #include <assert.h>
@ -39,6 +39,7 @@
#include "Props.hxx" #include "Props.hxx"
#include "PropsSet.hxx" #include "PropsSet.hxx"
#include "Settings.hxx" #include "Settings.hxx"
#include "Sound.hxx"
#include "Switches.hxx" #include "Switches.hxx"
#include "System.hxx" #include "System.hxx"
#include "TIA.hxx" #include "TIA.hxx"
@ -50,11 +51,12 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Console::Console(const uInt8* image, uInt32 size, const char* filename, Console::Console(const uInt8* image, uInt32 size, const char* filename,
Settings& rcsettings, PropertiesSet& propertiesSet, Settings& settings, PropertiesSet& propertiesSet,
FrameBuffer& framebuffer, uInt32 sampleRate) FrameBuffer& framebuffer, Sound& sound)
: mySettings(rcsettings), : mySettings(settings),
myPropSet(propertiesSet), myPropSet(propertiesSet),
myFrameBuffer(framebuffer) myFrameBuffer(framebuffer),
mySound(sound)
{ {
myControllers[0] = 0; myControllers[0] = 0;
myControllers[1] = 0; myControllers[1] = 0;
@ -158,7 +160,7 @@ Console::Console(const uInt8* image, uInt32 size, const char* filename,
} }
M6532* m6532 = new M6532(*this); M6532* m6532 = new M6532(*this);
TIA* tia = new TIA(*this, sampleRate); TIA* tia = new TIA(*this, mySound.getSampleRate());
Cartridge* cartridge = Cartridge::create(image, size, myProperties); Cartridge* cartridge = Cartridge::create(image, size, myProperties);
mySystem->attach(m6502); mySystem->attach(m6502);
@ -181,7 +183,8 @@ Console::Console(const uInt8* image, uInt32 size, const char* filename,
Console::Console(const Console& console) Console::Console(const Console& console)
: mySettings(console.mySettings), : mySettings(console.mySettings),
myPropSet(console.myPropSet), myPropSet(console.myPropSet),
myFrameBuffer(console.myFrameBuffer) myFrameBuffer(console.myFrameBuffer),
mySound(console.mySound)
{ {
// TODO: Write this method // TODO: Write this method
assert(false); assert(false);
@ -215,6 +218,12 @@ FrameBuffer& Console::frameBuffer() const
return myFrameBuffer; return myFrameBuffer;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Sound& Console::sound() const
{
return mySound;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Console& Console::operator = (const Console&) Console& Console::operator = (const Console&)
{ {

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: Console.hxx,v 1.14 2003-10-26 19:40:39 stephena Exp $ // $Id: Console.hxx,v 1.15 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#ifndef CONSOLE_HXX #ifndef CONSOLE_HXX
@ -41,7 +41,7 @@ class FrameBuffer;
This class represents the entire game console. This class represents the entire game console.
@author Bradford W. Mott @author Bradford W. Mott
@version $Id: Console.hxx,v 1.14 2003-10-26 19:40:39 stephena Exp $ @version $Id: Console.hxx,v 1.15 2003-11-06 22:22:32 stephena Exp $
*/ */
class Console class Console
{ {
@ -50,17 +50,17 @@ class Console
Create a new console for emulating the specified game using the Create a new console for emulating the specified game using the
given event object and game profiles. given event object and game profiles.
@param image The ROM image of the game to emulate @param image The ROM image of the game to emulate
@param size The size of the ROM image @param size The size of the ROM image
@param filename The name of the file that contained the ROM image @param filename The name of the file that contained the ROM image
@param rcsettings The settings object to use @param settings The settings object to use
@param profiles The game profiles object to use @param profiles The game profiles object to use
@param framebuffer The framebuffer object to use @param framebuffer The framebuffer object to use
@param sampleRate The rate to create audio samples at @param sound The sound object to use
*/ */
Console(const uInt8* image, uInt32 size, const char* filename, Console(const uInt8* image, uInt32 size, const char* filename,
Settings& rcsettings, PropertiesSet& propertiesSet, Settings& settings, PropertiesSet& propertiesSet,
FrameBuffer& framebuffer, uInt32 sampleRate); FrameBuffer& framebuffer, Sound& sound);
/** /**
Create a new console object by copying another one Create a new console object by copying another one
@ -106,6 +106,13 @@ class Console
*/ */
FrameBuffer& frameBuffer() const; FrameBuffer& frameBuffer() const;
/**
Get the sound object of the console
@return The sound object for this console
*/
Sound& sound() const;
/** /**
Get the console switches Get the console switches
@ -246,6 +253,9 @@ class Console
// Reference to the FrameBuffer object // Reference to the FrameBuffer object
FrameBuffer& myFrameBuffer; FrameBuffer& myFrameBuffer;
// Reference to the Sound object
Sound& mySound;
// Pointer to the EventHandler object // Pointer to the EventHandler object
EventHandler* myEventHandler; EventHandler* myEventHandler;

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: EventHandler.cxx,v 1.17 2003-10-26 19:40:39 stephena Exp $ // $Id: EventHandler.cxx,v 1.18 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#include <algorithm> #include <algorithm>
@ -27,6 +27,7 @@
#include "StellaEvent.hxx" #include "StellaEvent.hxx"
#include "System.hxx" #include "System.hxx"
#include "FrameBuffer.hxx" #include "FrameBuffer.hxx"
#include "Sound.hxx"
#include "bspf.hxx" #include "bspf.hxx"
#ifdef SNAPSHOT_SUPPORT #ifdef SNAPSHOT_SUPPORT
@ -38,6 +39,7 @@ EventHandler::EventHandler(Console* console)
: myConsole(console), : myConsole(console),
myCurrentState(0), myCurrentState(0),
myPauseStatus(false), myPauseStatus(false),
myQuitStatus(false),
myMenuStatus(false), myMenuStatus(false),
myRemapEnabledFlag(true) myRemapEnabledFlag(true)
{ {
@ -84,11 +86,13 @@ Event* EventHandler::event()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::sendKeyEvent(StellaEvent::KeyCode key, Int32 state) void EventHandler::sendKeyEvent(StellaEvent::KeyCode key, Int32 state)
{ {
// First check if we are entering menu mode // First check if we are changing menu mode, and only change when not paused
if(myRemapEnabledFlag && key == StellaEvent::KCODE_TAB && state == 1) // Sound is paused when entering menu mode, but the framebuffer is kept active
if(myRemapEnabledFlag && key == StellaEvent::KCODE_TAB && state == 1 && !myPauseStatus)
{ {
myMenuStatus = !myMenuStatus; myMenuStatus = !myMenuStatus;
myConsole->frameBuffer().showMainMenu(myMenuStatus); myConsole->frameBuffer().showMenu(myMenuStatus);
myConsole->sound().pause(myMenuStatus);
return; return;
} }
@ -145,13 +149,13 @@ void EventHandler::sendEvent(Event::Type event, Int32 state)
{ {
myPauseStatus = !myPauseStatus; myPauseStatus = !myPauseStatus;
myConsole->frameBuffer().pause(myPauseStatus); myConsole->frameBuffer().pause(myPauseStatus);
//FIXME myConsole->sound().pause(myPauseStatus); myConsole->sound().pause(myPauseStatus);
return; return;
} }
else if(event == Event::Quit) else if(event == Event::Quit)
{ {
myQuitStatus = !myQuitStatus;
myConsole->settings().saveConfig(); myConsole->settings().saveConfig();
myConsole->settings().setQuitEvent();
return; return;
} }

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: EventHandler.hxx,v 1.11 2003-10-26 19:40:39 stephena Exp $ // $Id: EventHandler.hxx,v 1.12 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#ifndef EVENTHANDLER_HXX #ifndef EVENTHANDLER_HXX
@ -41,7 +41,7 @@ class MediaSource;
mapping can take place. mapping can take place.
@author Stephen Anthony @author Stephen Anthony
@version $Id: EventHandler.hxx,v 1.11 2003-10-26 19:40:39 stephena Exp $ @version $Id: EventHandler.hxx,v 1.12 2003-11-06 22:22:32 stephena Exp $
*/ */
class EventHandler class EventHandler
{ {
@ -118,6 +118,16 @@ class EventHandler
*/ */
void enableRemapping(bool status) { myRemapEnabledFlag = status; } void enableRemapping(bool status) { myRemapEnabledFlag = status; }
/**
This method indicated whether a pause event has been received.
*/
bool doPause() { return myPauseStatus; }
/**
This method indicated whether a quit event has been received.
*/
bool doQuit() { return myQuitStatus; }
void getKeymapArray(Event::Type** array, uInt32* size); void getKeymapArray(Event::Type** array, uInt32* size);
void getJoymapArray(Event::Type** array, uInt32* size); void getJoymapArray(Event::Type** array, uInt32* size);
@ -159,6 +169,9 @@ class EventHandler
// Indicates the current pause status // Indicates the current pause status
bool myPauseStatus; bool myPauseStatus;
// Indicates the current quit status
bool myQuitStatus;
// The current keymap in string form // The current keymap in string form
string myKeymapString; string myKeymapString;

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: FrameBuffer.cxx,v 1.2 2003-10-26 19:40:39 stephena Exp $ // $Id: FrameBuffer.cxx,v 1.3 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#include <sstream> #include <sstream>
@ -57,6 +57,8 @@ FrameBuffer::FrameBuffer()
myCurrentWidget(W_NONE), myCurrentWidget(W_NONE),
myRemapEventSelectedFlag(false), myRemapEventSelectedFlag(false),
mySelectedEvent(Event::NoType), mySelectedEvent(Event::NoType),
myMenuMode(false),
theMenuChangedIndicator(false),
myMaxLines(0), myMaxLines(0),
myMainMenuIndex(0), myMainMenuIndex(0),
myMainMenuItems(sizeof(ourMainMenu)/sizeof(MainMenuItem)), myMainMenuItems(sizeof(ourMainMenu)/sizeof(MainMenuItem)),
@ -84,23 +86,19 @@ void FrameBuffer::initDisplay(Console* console, MediaSource* mediasrc)
// Fill the properties info array with game information // Fill the properties info array with game information
ourPropertiesInfo[0] = myConsole->properties().get("Cartridge.Name"); ourPropertiesInfo[0] = myConsole->properties().get("Cartridge.Name");
if(ourPropertiesInfo[0].length() > myInfoMenuWidth) ourPropertiesInfo[1] = "";
myInfoMenuWidth = ourPropertiesInfo[0].length(); ourPropertiesInfo[2] = "Manufacturer: " + myConsole->properties().get("Cartridge.Manufacturer");
ourPropertiesInfo[1] = myConsole->properties().get("Cartridge.Manufacturer"); ourPropertiesInfo[3] = "Model: " + myConsole->properties().get("Cartridge.ModelNo");
if(ourPropertiesInfo[1].length() > myInfoMenuWidth) ourPropertiesInfo[4] = "Rarity: " + myConsole->properties().get("Cartridge.Rarity");
myInfoMenuWidth = ourPropertiesInfo[1].length(); ourPropertiesInfo[5] = "Type: " + myConsole->properties().get("Cartridge.Type");
ourPropertiesInfo[2] = myConsole->properties().get("Cartridge.Rarity"); ourPropertiesInfo[6] = "";
if(ourPropertiesInfo[2].length() > myInfoMenuWidth) ourPropertiesInfo[7] = "MD5SUM:";
myInfoMenuWidth = ourPropertiesInfo[2].length(); ourPropertiesInfo[8] = myConsole->properties().get("Cartridge.MD5");
ourPropertiesInfo[3] = myConsole->properties().get("Cartridge.MD5");
if(ourPropertiesInfo[3].length() > myInfoMenuWidth) // Figure out the longest string
myInfoMenuWidth = ourPropertiesInfo[3].length(); for(uInt8 i = 0; i < 9; i++)
ourPropertiesInfo[4] = myConsole->properties().get("Cartridge.Type"); if(ourPropertiesInfo[i].length() > myInfoMenuWidth)
if(ourPropertiesInfo[4].length() > myInfoMenuWidth) myInfoMenuWidth = ourPropertiesInfo[i].length();
myInfoMenuWidth = ourPropertiesInfo[4].length();
ourPropertiesInfo[5] = myConsole->properties().get("Cartridge.ModelNo");
if(ourPropertiesInfo[5].length() > myInfoMenuWidth)
myInfoMenuWidth = ourPropertiesInfo[5].length();
// Get the arrays containing key and joystick mappings // Get the arrays containing key and joystick mappings
myConsole->eventHandler().getKeymapArray(&myKeyTable, &myKeyTableSize); myConsole->eventHandler().getKeymapArray(&myKeyTable, &myKeyTableSize);
@ -128,51 +126,75 @@ void FrameBuffer::update()
// Do any pre-frame stuff // Do any pre-frame stuff
preFrameUpdate(); preFrameUpdate();
// Draw changes to the mediasource // Determine which mode we are in (normal or menu mode)
if(!myPauseStatus) // FIXME - sound class // In normal mode, only the mediasource or messages are shown,
myMediaSource->update(); // and they are shown per-frame
// In menu mode, any of the menus are shown, but the mediasource
drawMediaSource(); // is not updated, and all updates depend on whether the screen is dirty
if(!myMenuMode)
// Then overlay any menu items
switch(myCurrentWidget)
{ {
case W_NONE: // Draw changes to the mediasource
break; if(!myPauseStatus)
myMediaSource->update();
case MAIN_MENU: // We always draw the screen, even if the core is paused
drawMainMenu(); drawMediaSource();
break;
case REMAP_MENU: if(!myPauseStatus)
drawRemapMenu(); {
break; // Draw any pending messages
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;
case INFO_MENU: // Draw the bounded box and text
drawInfoMenu(); drawBoundedBox(x, y, width, height, FGCOLOR, BGCOLOR);
break; drawText(x + XBOXOFFSET/2, LINEOFFSET/2 + y, myMessageText, FGCOLOR);
myMessageTime--;
default: // Erase this message on next update
break; if(myMessageTime == 0)
theRedrawEntireFrameIndicator = true;
}
}
} }
else // we are in MENU_MODE
// A message is a special case of interface element
// It can overwrite even a menu
if(myMessageTime > 0)
{ {
uInt32 width = myMessageText.length()*FONTWIDTH + FONTWIDTH; // Only update the screen if it's been invalidated
uInt32 height = LINEOFFSET + FONTHEIGHT; // or the menus have changed
uInt32 x = (myWidth >> 1) - (width >> 1); if(theMenuChangedIndicator || theRedrawEntireFrameIndicator)
uInt32 y = myHeight - height - LINEOFFSET/2; {
cerr << "redrawing screen and menus\n";
drawMediaSource();
// Draw the bounded box and text // Then overlay any menu items
drawBoundedBox(x, y, width, height, FGCOLOR, BGCOLOR); switch(myCurrentWidget)
drawText(x + XBOXOFFSET/2, LINEOFFSET/2 + y, myMessageText, FGCOLOR); {
myMessageTime--; case W_NONE:
break;
// Erase this message on next update case MAIN_MENU:
if(myMessageTime == 0) drawMainMenu();
theRedrawEntireFrameIndicator = true; break;
case REMAP_MENU:
drawRemapMenu();
break;
case INFO_MENU:
drawInfoMenu();
break;
default:
break;
}
// Now the screen is up to date
theMenuChangedIndicator = theRedrawEntireFrameIndicator = false;
}
} }
// Do any post-frame stuff // Do any post-frame stuff
@ -180,8 +202,10 @@ void FrameBuffer::update()
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBuffer::showMainMenu(bool show) void FrameBuffer::showMenu(bool show)
{ {
myMenuMode = show;
myCurrentWidget = show ? MAIN_MENU : W_NONE; myCurrentWidget = show ? MAIN_MENU : W_NONE;
myRemapEventSelectedFlag = false; myRemapEventSelectedFlag = false;
mySelectedEvent = Event::NoType; mySelectedEvent = Event::NoType;
@ -192,7 +216,7 @@ void FrameBuffer::showMainMenu(bool show)
void FrameBuffer::showMessage(const string& message) void FrameBuffer::showMessage(const string& message)
{ {
myMessageText = message; myMessageText = message;
myMessageTime = myFrameRate << 1; myMessageTime = myFrameRate << 1; // Show message for 2 seconds
theRedrawEntireFrameIndicator = true; theRedrawEntireFrameIndicator = true;
} }
@ -202,7 +226,7 @@ inline void FrameBuffer::drawMainMenu()
uInt32 x, y, width, height, i, xpos, ypos; uInt32 x, y, width, height, i, xpos, ypos;
width = 16*FONTWIDTH + (FONTWIDTH << 1); width = 16*FONTWIDTH + (FONTWIDTH << 1);
height = myMainMenuItems*LINEOFFSET + 2*FONTHEIGHT; height = myMainMenuItems*LINEOFFSET + (FONTHEIGHT << 1);
x = (myWidth >> 1) - (width >> 1); x = (myWidth >> 1) - (width >> 1);
y = (myHeight >> 1) - (height >> 1); y = (myHeight >> 1) - (height >> 1);
@ -224,7 +248,7 @@ inline void FrameBuffer::drawRemapMenu()
uInt32 x, y, width, height, i, xpos, ypos; uInt32 x, y, width, height, i, xpos, ypos;
width = (myWidth >> 3) * FONTWIDTH - (FONTWIDTH << 1); width = (myWidth >> 3) * FONTWIDTH - (FONTWIDTH << 1);
height = myMaxLines*LINEOFFSET + 2*FONTHEIGHT; height = myMaxLines*LINEOFFSET + (FONTHEIGHT << 1);
x = (myWidth >> 1) - (width >> 1); x = (myWidth >> 1) - (width >> 1);
y = (myHeight >> 1) - (height >> 1); y = (myHeight >> 1) - (height >> 1);
@ -260,12 +284,12 @@ inline void FrameBuffer::drawRemapMenu()
} }
// Finally, indicate that there are more items to the top or bottom // Finally, indicate that there are more items to the top or bottom
xpos = (width >> 1) - FONTWIDTH/2; xpos = (width >> 1) - (FONTWIDTH >> 1);
if(myRemapMenuHighIndex - myMaxLines > 0) if(myRemapMenuHighIndex - myMaxLines > 0)
drawChar(xpos, y, UPARROW, FGCOLOR); drawChar(xpos, y, UPARROW, FGCOLOR);
if(myRemapMenuLowIndex + myMaxLines < myRemapMenuItems) if(myRemapMenuLowIndex + myMaxLines < myRemapMenuItems)
drawChar(xpos, height - FONTWIDTH/2, DOWNARROW, FGCOLOR); drawChar(xpos, height - (FONTWIDTH >> 1), DOWNARROW, FGCOLOR);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -273,15 +297,15 @@ inline void FrameBuffer::drawInfoMenu()
{ {
uInt32 x, y, width, height, i, xpos; uInt32 x, y, width, height, i, xpos;
width = myInfoMenuWidth*FONTWIDTH + 2*FONTWIDTH; width = myInfoMenuWidth*FONTWIDTH + (FONTWIDTH << 1);
height = 6*LINEOFFSET + 2*FONTHEIGHT; height = 9*LINEOFFSET + (FONTHEIGHT << 1);
x = (myWidth >> 1) - (width >> 1); x = (myWidth >> 1) - (width >> 1);
y = (myHeight >> 1) - (height >> 1); y = (myHeight >> 1) - (height >> 1);
// Draw the bounded box and text // Draw the bounded box and text
xpos = x + XBOXOFFSET; xpos = x + XBOXOFFSET;
drawBoundedBox(x, y, width, height, FGCOLOR, BGCOLOR); drawBoundedBox(x, y, width, height, FGCOLOR, BGCOLOR);
for(i = 0; i < 6; i++) for(i = 0; i < 9; i++)
drawText(xpos, LINEOFFSET*i + y + YBOXOFFSET, ourPropertiesInfo[i], FGCOLOR); drawText(xpos, LINEOFFSET*i + y + YBOXOFFSET, ourPropertiesInfo[i], FGCOLOR);
} }
@ -291,6 +315,9 @@ void FrameBuffer::sendKeyEvent(StellaEvent::KeyCode key, Int32 state)
if(myCurrentWidget == W_NONE || state != 1) if(myCurrentWidget == W_NONE || state != 1)
return; return;
// Redraw the menus whenever a key event is received
theMenuChangedIndicator = true;
// Check which type of widget is pending // Check which type of widget is pending
switch(myCurrentWidget) switch(myCurrentWidget)
{ {
@ -357,6 +384,8 @@ void FrameBuffer::sendJoyEvent(StellaEvent::JoyStick stick,
return; return;
cerr << "stick = " << stick << ", button = " << code << endl; cerr << "stick = " << stick << ", button = " << code << endl;
// Redraw the menus whenever a joy event is received
theMenuChangedIndicator = true;
// Check which type of widget is pending // Check which type of widget is pending
switch(myCurrentWidget) switch(myCurrentWidget)
@ -663,7 +692,7 @@ const uInt8 FrameBuffer::ourFontData[2048] = {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBuffer::MainMenuItem FrameBuffer::ourMainMenu[2] = { FrameBuffer::MainMenuItem FrameBuffer::ourMainMenu[2] = {
{ REMAP_MENU, "Key Remapping" }, { REMAP_MENU, "Event Remapping" },
{ INFO_MENU, "Game Information" } { INFO_MENU, "Game Information" }
}; };

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: FrameBuffer.hxx,v 1.2 2003-10-26 19:40:39 stephena Exp $ // $Id: FrameBuffer.hxx,v 1.3 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#ifndef FRAMEBUFFER_HXX #ifndef FRAMEBUFFER_HXX
@ -35,7 +35,7 @@ class Console;
can be changed. can be changed.
@author Stephen Anthony @author Stephen Anthony
@version $Id: FrameBuffer.hxx,v 1.2 2003-10-26 19:40:39 stephena Exp $ @version $Id: FrameBuffer.hxx,v 1.3 2003-11-06 22:22:32 stephena Exp $
*/ */
class FrameBuffer class FrameBuffer
{ {
@ -70,7 +70,7 @@ class FrameBuffer
@param show Show/hide the menu based on the boolean value @param show Show/hide the menu based on the boolean value
*/ */
void showMainMenu(bool show); void showMenu(bool show);
/** /**
Shows a message onscreen. Shows a message onscreen.
@ -280,6 +280,12 @@ class FrameBuffer
// Indicates the current selected event being remapped // Indicates the current selected event being remapped
Event::Type mySelectedEvent; Event::Type mySelectedEvent;
// Indicates if we are in menu mode
bool myMenuMode;
// Indicates if the menus should be redrawn
bool theMenuChangedIndicator;
// The maximum number of vertical lines of text that can be onscreen // The maximum number of vertical lines of text that can be onscreen
uInt32 myMaxLines; uInt32 myMaxLines;
@ -300,7 +306,7 @@ class FrameBuffer
uInt32 myInfoMenuWidth; uInt32 myInfoMenuWidth;
// Holds information about the current selected ROM image // Holds information about the current selected ROM image
string ourPropertiesInfo[6]; string ourPropertiesInfo[9];
// Holds static strings for the main menu // Holds static strings for the main menu
static MainMenuItem ourMainMenu[2]; static MainMenuItem ourMainMenu[2];

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: Settings.cxx,v 1.10 2003-09-28 21:59:24 stephena Exp $ // $Id: Settings.cxx,v 1.11 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#include <cassert> #include <cassert>
@ -32,9 +32,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Settings::Settings() Settings::Settings()
: myPauseIndicator(false), : myConsole(0)
myQuitIndicator(false),
myConsole(0)
{ {
// First create the settings array // First create the settings array
myCapacity = 30; myCapacity = 30;

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: Settings.hxx,v 1.8 2003-10-26 19:40:39 stephena Exp $ // $Id: Settings.hxx,v 1.9 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#ifndef SETTINGS_HXX #ifndef SETTINGS_HXX
@ -32,7 +32,7 @@ class Console;
This class provides an interface for accessing frontend specific settings. This class provides an interface for accessing frontend specific settings.
@author Stephen Anthony @author Stephen Anthony
@version $Id: Settings.hxx,v 1.8 2003-10-26 19:40:39 stephena Exp $ @version $Id: Settings.hxx,v 1.9 2003-11-06 22:22:32 stephena Exp $
*/ */
class Settings class Settings
{ {
@ -134,32 +134,6 @@ class Settings
*/ */
void setConsole(Console* console) { myConsole = console; } void setConsole(Console* console) { myConsole = console; }
/**
This method should be called when the emulation core receives
a QUIT event.
*/
void setQuitEvent() { myQuitIndicator = true; }
/**
This method determines whether the QUIT event has been received.
@return Boolean representing whether a QUIT event has been received
*/
bool quit() { return myQuitIndicator; }
/**
This method should be called at when the emulation core receives
a PAUSE event.
*/
void setPauseEvent(bool status) { myPauseIndicator = status; }
/**
This method determines whether the PAUSE event has been received.
@return Boolean representing whether a PAUSE event has been received
*/
bool pause() { return myPauseIndicator; }
/** /**
This method should be called to get the filename of the users' This method should be called to get the filename of the users'
properties (stella.pro) file. properties (stella.pro) file.
@ -204,9 +178,6 @@ class Settings
#endif #endif
protected: protected:
bool myPauseIndicator;
bool myQuitIndicator;
string myBaseDir; string myBaseDir;
string myStateDir; string myStateDir;
string myStateFile; string myStateFile;

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: Sound.cxx,v 1.5 2003-02-25 03:12:54 stephena Exp $ // $Id: Sound.cxx,v 1.6 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#include "Sound.hxx" #include "Sound.hxx"
@ -50,6 +50,11 @@ void Sound::setSoundVolume(Int32 volume)
{ {
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Sound::pause(bool status)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Sound::updateSound(MediaSource& mediaSource) void Sound::updateSound(MediaSource& mediaSource)
{ {

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: Sound.hxx,v 1.5 2003-02-25 03:12:55 stephena Exp $ // $Id: Sound.hxx,v 1.6 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#ifndef SOUND_HXX #ifndef SOUND_HXX
@ -28,7 +28,7 @@
to compile Stella with no sound support whatsoever. to compile Stella with no sound support whatsoever.
@author Stephen Anthony @author Stephen Anthony
@version $Id: Sound.hxx,v 1.5 2003-02-25 03:12:55 stephena Exp $ @version $Id: Sound.hxx,v 1.6 2003-11-06 22:22:32 stephena Exp $
*/ */
class Sound class Sound
{ {
@ -72,6 +72,14 @@ class Sound
*/ */
virtual void setSoundVolume(Int32 percent); virtual void setSoundVolume(Int32 percent);
/**
Sets the pause status. While pause is selected, updateSound()
should not play any sound.
@param status Toggle pause based on status
*/
virtual void pause(bool status);
/** /**
Update the sound device using the audio sample from the specified Update the sound device using the audio sample from the specified
media source. media source.

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: Snapshot.cxx,v 1.6 2003-10-17 18:02:16 stephena Exp $ // $Id: Snapshot.cxx,v 1.7 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#include <png.h> #include <png.h>
@ -22,6 +22,7 @@
#include "bspf.hxx" #include "bspf.hxx"
#include "FrameBuffer.hxx" #include "FrameBuffer.hxx"
#include "MediaSrc.hxx"
#include "Snapshot.hxx" #include "Snapshot.hxx"
@ -62,20 +63,19 @@ void Snapshot::png_user_error(png_structp ctx, png_const_charp str)
This routine saves the current frame buffer to a 256 color PNG file, This routine saves the current frame buffer to a 256 color PNG file,
appropriately scaled by the amount specified in 'multiplier'. appropriately scaled by the amount specified in 'multiplier'.
*/ */
int Snapshot::savePNG(string filename, FrameBuffer& frameBuffer, uInt32 multiplier) int Snapshot::savePNG(string filename, FrameBuffer& framebuffer, uInt32 multiplier)
{ {
#if 0
// FIXME
png_structp png_ptr = 0; png_structp png_ptr = 0;
png_infop info_ptr = 0; png_infop info_ptr = 0;
MediaSource* source = framebuffer.mediaSource();
uInt8* pixels = frameBuffer.current(); uInt8* pixels = source->currentFrameBuffer();
// PNG and window dimensions will be different because of scaling // PNG and window dimensions will be different because of scaling
int picWidth = frameBuffer.width() * 2 * multiplier; int picWidth = framebuffer.width() * multiplier;
int picHeight = frameBuffer.height() * multiplier; int picHeight = framebuffer.height() * multiplier;
int width = frameBuffer.width(); int width = source->width();
int height = frameBuffer.height(); int height = source->height();
ofstream* out = new ofstream(filename.c_str()); ofstream* out = new ofstream(filename.c_str());
if(!out) if(!out)
@ -93,7 +93,7 @@ int Snapshot::savePNG(string filename, FrameBuffer& frameBuffer, uInt32 multipli
return 0; return 0;
} }
const uInt32* gamePalette = frameBuffer.palette(); const uInt32* gamePalette = source->palette();
for(uInt32 i = 0; i < 256; ++i) for(uInt32 i = 0; i < 256; ++i)
{ {
palette[i].red = (uInt8) ((gamePalette[i] & 0x00ff0000) >> 16); palette[i].red = (uInt8) ((gamePalette[i] & 0x00ff0000) >> 16);
@ -138,7 +138,7 @@ int Snapshot::savePNG(string filename, FrameBuffer& frameBuffer, uInt32 multipli
// The width has to be scaled by 2 * multiplier. Each pixel must be // The width has to be scaled by 2 * multiplier. Each pixel must be
// present scaleX times. Each scanline must be present scaleY times. // present scaleX times. Each scanline must be present scaleY times.
int scaleX = 2 * multiplier; int scaleX = multiplier << 1;
int scaleY = multiplier; int scaleY = multiplier;
// Create a buffer to hold the new scanline. // Create a buffer to hold the new scanline.
@ -172,6 +172,6 @@ int Snapshot::savePNG(string filename, FrameBuffer& frameBuffer, uInt32 multipli
out->close(); out->close();
delete out; delete out;
#endif
return 1; return 1;
} }

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: Snapshot.hxx,v 1.3 2003-10-17 18:02:16 stephena Exp $ // $Id: Snapshot.hxx,v 1.4 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#ifndef SNAPSHOT_HXX #ifndef SNAPSHOT_HXX
@ -31,7 +31,7 @@ class Snapshot
Snapshot(); Snapshot();
~Snapshot(); ~Snapshot();
int savePNG(string filename, FrameBuffer& mediaSource, uInt32 multiplier = 1); int savePNG(string filename, FrameBuffer& framebuffer, uInt32 multiplier = 1);
private: private:
static void png_write_data(png_structp ctx, png_bytep area, png_size_t size); static void png_write_data(png_structp ctx, png_bytep area, png_size_t size);

View File

@ -0,0 +1,586 @@
//============================================================================
//
// 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: FrameBufferGL.cxx,v 1.1 2003-11-06 22:22:32 stephena Exp $
//============================================================================
#include <SDL.h>
#include <SDL_syswm.h>
#include <sstream>
#include "Console.hxx"
#include "FrameBuffer.hxx"
#include "FrameBufferGL.hxx"
#include "MediaSrc.hxx"
#include "Settings.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBufferGL::FrameBufferGL()
: myScreen(0),
myTexture(0),
x11Available(false),
theZoomLevel(1),
theMaxZoomLevel(1),
theGrabMouseIndicator(false),
theHideCursorIndicator(false),
isFullscreen(false)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBufferGL::~FrameBufferGL()
{
if(myTexture)
SDL_FreeSurface(myTexture);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferGL::init()
{
// Get the desired width and height of the display
myWidth = myMediaSource->width() << 1;
myHeight = myMediaSource->height();
// Now create the OpenGL 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_OPENGL;
mySDLFlags |= myConsole->settings().getBool("fullscreen") ? SDL_FULLSCREEN : 0;
// Set the window title and icon
ostringstream name;
name << "Stella: \"" << myConsole->properties().get("Cartridge.Name") << "\"";
SDL_WM_SetCaption(name.str().c_str(), "stella");
// Set up the OpenGL attributes
int rgb_size[3];
int bpp = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
switch(bpp)
{
case 8:
rgb_size[0] = 3;
rgb_size[1] = 3;
rgb_size[2] = 2;
break;
case 15:
case 16:
rgb_size[0] = 5;
rgb_size[1] = 5;
rgb_size[2] = 5;
break;
default:
rgb_size[0] = 8;
rgb_size[1] = 8;
rgb_size[2] = 8;
break;
}
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, rgb_size[0] );
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, rgb_size[1] );
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, rgb_size[2] );
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, bpp );
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
// Create the screen
if(!createScreen())
return false;
setupPalette(1.0);
// Show some OpenGL info
if(myConsole->settings().getBool("showinfo"))
{
cout << endl
<< "Vendor : " << glGetString(GL_VENDOR) << endl
<< "Renderer: " << glGetString(GL_RENDERER) << endl
<< "Version : " << glGetString(GL_VERSION) << endl;
}
// Create the texture surface and texture fonts
createTextures();
// 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);
}
// Set up global GL stuff
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glEnable(GL_LINE_SMOOTH);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::drawMediaSource() // FIXME - maybe less copying can be done?
{
// Copy the mediasource framebuffer to the RGB texture
uInt8* currentFrame = myMediaSource->currentFrameBuffer();
uInt8* previousFrame = myMediaSource->previousFrameBuffer();
uInt32 width = myMediaSource->width();
uInt32 height = myMediaSource->height();
uInt32* buffer = (uInt32*) myTexture->pixels;
register uInt32 y;
for(y = 0; y < height; ++y )
{
const uInt32 bufofsY = y * width;
const uInt32 screenofsY = y * myTexture->w;
register uInt32 x;
for(x = 0; x < width; ++x )
{
const uInt32 bufofs = bufofsY + x;
uInt8 v = currentFrame[bufofs];
if(v == previousFrame[bufofs] && !theRedrawEntireFrameIndicator)
continue;
// x << 1 is times 2 ( doubling width ) WIDTH_FACTOR
const uInt32 pos = screenofsY + (x << 1);
buffer[pos] = buffer[pos+1] = myPalette[v];
}
}
// Texturemap complete texture to surface so we have free scaling
// and antialiasing
glBindTexture(GL_TEXTURE_2D, myTextureID);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, myTexture->w, myTexture->h,
GL_RGBA, GL_UNSIGNED_BYTE, myTexture->pixels);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glBegin(GL_QUADS);
glTexCoord2f(myTexCoord[0], myTexCoord[1]); glVertex2i(0, 0);
glTexCoord2f(myTexCoord[2], myTexCoord[1]); glVertex2i(myWidth, 0);
glTexCoord2f(myTexCoord[2], myTexCoord[3]); glVertex2i(myWidth, myHeight);
glTexCoord2f(myTexCoord[0], myTexCoord[3]); glVertex2i(0, myHeight);
glEnd();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::preFrameUpdate()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::postFrameUpdate()
{
// Now show all changes made to the textures
SDL_GL_SwapBuffers();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferGL::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;
}
glPushAttrib(GL_ENABLE_BIT);
glViewport(0, 0, myScreen->w, myScreen->h);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0.0, (GLdouble) myScreen->w/theZoomLevel,
(GLdouble) myScreen->h/theZoomLevel, 0.0, 0.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
theRedrawEntireFrameIndicator = true;
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::setupPalette(float shade)
{
// FIXME - OpenGL should be able to shade the texture itself
const uInt32* gamePalette = myMediaSource->palette();
for(uInt32 i = 0; i < 256; ++i)
{
Uint8 r, g, b, a;
r = (Uint8) (((gamePalette[i] & 0x00ff0000) >> 16) * shade);
g = (Uint8) (((gamePalette[i] & 0x0000ff00) >> 8) * shade);
b = (Uint8) ((gamePalette[i] & 0x000000ff) * shade);
a = 0xff;
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
myPalette[i] = (a << 24) | (b << 16) | (g << 8) | r;
#else
myPalette[i] = (r << 24) | (g << 16) | (b << 8) | a;
#endif
}
theRedrawEntireFrameIndicator = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::pause(bool status)
{
myPauseStatus = status;
// Shade the palette to 75% normal value in pause mode
// FIXME - this seems like cheating, we should be using OpenGL instead
if(myPauseStatus)
setupPalette(0.75);
else
setupPalette(1.0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::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);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::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;
// Now update the settings
ostringstream tmp;
tmp << theZoomLevel;
myConsole->settings().set("zoom", tmp.str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::showCursor(bool show)
{
if(isFullscreen)
return;
if(show)
SDL_ShowCursor(SDL_ENABLE);
else
SDL_ShowCursor(SDL_DISABLE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::grabMouse(bool grab)
{
if(isFullscreen)
return;
if(grab)
SDL_WM_GrabInput(SDL_GRAB_ON);
else
SDL_WM_GrabInput(SDL_GRAB_OFF);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 FrameBufferGL::maxWindowSizeForScreen()
{
if(!x11Available)
return 1;
#ifdef UNIX
// 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;
#else
return 1;
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::drawBoundedBox(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
uInt8 fg, uInt8 bg)
{
// First draw the box in the background, alpha-blended
// We don't care about the specified bg color, since
// we always want black with alpha
glEnable(GL_BLEND);
glColor4f(0.0, 0.0, 0.0, 0.7);
glRecti(x, y, x+w, y+h);
// Now draw the outer edges
// Again, we don't care about the provided fg color, since
// we always want a light grey with no alpha
glDisable(GL_BLEND);
glColor3f(0.8, 0.8, 0.8);
glBegin(GL_LINE_LOOP);
glVertex2i(x, y ); // Top Left
glVertex2i(x+w, y ); // Top Right
glVertex2i(x+w, y+h); // Bottom Right
glVertex2i(x, y+h); // Bottom Left
glEnd();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::drawText(uInt32 xorig, uInt32 yorig,
const string& message, uInt8 fg)
{
glBindTexture(GL_TEXTURE_2D, myFontTextureID);
glEnable(GL_BLEND);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
// We place the loop here to avoid multiple calls to glBegin/glEnd
glBegin(GL_QUADS);
for(uInt32 i = 0; i < message.length(); i++)
{
uInt32 x = xorig + i*8;
uInt32 y = yorig;
uInt8 c = message[i];
glTexCoord2f(myFontCoord[c].minX, myFontCoord[c].minY); glVertex2i(x, y );
glTexCoord2f(myFontCoord[c].maxX, myFontCoord[c].minY); glVertex2i(x+8, y );
glTexCoord2f(myFontCoord[c].maxX, myFontCoord[c].maxY); glVertex2i(x+8, y+8);
glTexCoord2f(myFontCoord[c].minX, myFontCoord[c].maxY); glVertex2i(x, y+8);
}
glEnd();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::drawChar(uInt32 x, uInt32 y, uInt32 c, uInt8 fg)
{
if(c >= 256 )
return;
glBindTexture(GL_TEXTURE_2D, myFontTextureID);
glEnable(GL_BLEND);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
glBegin(GL_QUADS);
glTexCoord2f(myFontCoord[c].minX, myFontCoord[c].minY); glVertex2i(x, y );
glTexCoord2f(myFontCoord[c].maxX, myFontCoord[c].minY); glVertex2i(x+8, y );
glTexCoord2f(myFontCoord[c].maxX, myFontCoord[c].maxY); glVertex2i(x+8, y+8);
glTexCoord2f(myFontCoord[c].minX, myFontCoord[c].maxY); glVertex2i(x, y+8);
glEnd();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferGL::createTextures()
{
uInt32 w = power_of_two(myWidth);
uInt32 h = power_of_two(myHeight);
myTexCoord[0] = 0.0f;
myTexCoord[1] = 0.0f;
myTexCoord[2] = (GLfloat) myWidth / w;
myTexCoord[3] = (GLfloat) myHeight / h;
myTexture = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32,
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
#else
0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
#endif
if(myTexture == NULL)
return false;
// Create an OpenGL texture from the SDL texture
bool showinfo = myConsole->settings().getBool("showinfo");
string filter = myConsole->settings().getString("gl_filter");
GLint param = GL_NEAREST;
if(filter == "linear")
{
param = GL_LINEAR;
if(showinfo)
cout << "Using GL_LINEAR filtering.\n\n";
}
else if(filter == "nearest")
{
param = GL_NEAREST;
if(showinfo)
cout << "Using GL_NEAREST filtering.\n\n";
}
glGenTextures(1, &myTextureID);
glBindTexture(GL_TEXTURE_2D, myTextureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, param);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, param);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE,
myTexture->pixels);
// Now create the font texture. There are 256 fonts of 8x8 pixels.
// These will be stored in a texture of size 256x64, which is 32 characters
// per line, and 8 lines.
SDL_Surface* fontTexture = SDL_CreateRGBSurface(SDL_SWSURFACE, 256, 64, 32,
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
#else
0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
#endif
if(fontTexture == NULL)
return false;
// First clear the texture
SDL_Rect tmp;
tmp.x = 0; tmp.y = 0; tmp.w = 256; tmp.h = 64;
SDL_FillRect(fontTexture, &tmp,
SDL_MapRGBA(fontTexture->format, 0xff, 0xff, 0xff, 0x0));
// Now fill the texture with font data
for(uInt32 lines = 0; lines < 8; lines++)
{
for(uInt32 x = lines*32; x < (lines+1)*32; x++)
{
for(uInt32 y = 0; y < 8; y++)
{
for(uInt32 z = 0; z < 8; z++)
{
if((ourFontData[(x << 3) + y] >> z) & 1)
{
tmp.x = ((x-lines*32)<<3) + z;
tmp.y = y + lines*8;
tmp.w = tmp.h = 1;
SDL_FillRect(fontTexture, &tmp,
SDL_MapRGBA(fontTexture->format, 0x10, 0x10, 0x10, 0xff));
}
}
}
}
}
// Generate the character coordinates
for(uInt32 i = 0; i < 256; i++)
{
uInt32 row = i / 32;
uInt32 col = i - (row*32);
myFontCoord[i].minX = (GLfloat) (col*8) / 256;
myFontCoord[i].maxX = (GLfloat) (col*8+8) / 256;
myFontCoord[i].minY = (GLfloat) (row*8) / 64;
myFontCoord[i].maxY = (GLfloat) (row*8+8) / 64;
}
glGenTextures(1, &myFontTextureID);
glBindTexture(GL_TEXTURE_2D, myFontTextureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, param);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, param);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE,
fontTexture->pixels);
SDL_FreeSurface(fontTexture);
return true;
}

View File

@ -0,0 +1,232 @@
//============================================================================
//
// 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: FrameBufferGL.hxx,v 1.1 2003-11-06 22:22:32 stephena Exp $
//============================================================================
#ifndef FRAMEBUFFER_GL_HXX
#define FRAMEBUFFER_GL_HXX
#include <SDL.h>
#include <SDL_opengl.h>
#include <SDL_syswm.h>
#include "FrameBuffer.hxx"
#include "bspf.hxx"
class Console;
class MediaSource;
class FrameBufferGL : public FrameBuffer
{
public:
/**
Creates a new SDL OpenGL framebuffer
*/
FrameBufferGL();
/**
Destructor
*/
virtual ~FrameBufferGL();
/**
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);
/**
Set up the palette for a screen of any depth > 8.
Scales the palette by 'shade'.
*/
void setupPalette(float shade);
/**
Answers if the display is currently in fullscreen mode.
*/
bool fullScreen() { return isFullscreen; }
/**
Answers the current zoom level of the SDL window
*/
uInt32 zoomLevel() { return theZoomLevel; }
private:
/**
This routine is called whenever the screen needs to be recreated.
It updates the global screen variable.
*/
bool createScreen();
/**
Calculate the maximum window size that the current screen can hold.
Only works in X11 for now. If not running under X11, always return 1.
*/
uInt32 maxWindowSizeForScreen();
bool createTextures();
uInt32 power_of_two(uInt32 input)
{
uInt32 value = 1;
while( value < input )
value <<= 1;
return value;
}
private:
// The SDL video buffer
SDL_Surface* myScreen;
// The main texture buffer
SDL_Surface* myTexture;
// The OpenGL main texture handle
GLuint myTextureID;
// OpenGL texture coordinates for the main surface
GLfloat myTexCoord[4];
// The OpenGL font texture handle
GLuint myFontTextureID;
// Structure to hold a characters coordinates
struct Coordinates
{
GLfloat minX;
GLfloat maxX;
GLfloat minY;
GLfloat maxY;
};
// OpenGL texture coordinates for the font surface
Coordinates myFontCoord[256];
// SDL initialization flags
uInt32 mySDLFlags;
// SDL palette
uInt32 myPalette[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

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: FrameBufferSDL.cxx,v 1.1 2003-10-26 19:40:39 stephena Exp $ // $Id: FrameBufferSDL.cxx,v 1.2 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#include <SDL.h> #include <SDL.h>
@ -24,7 +24,6 @@
#include "FrameBuffer.hxx" #include "FrameBuffer.hxx"
#include "FrameBufferSDL.hxx" #include "FrameBufferSDL.hxx"
#include "MediaSrc.hxx" #include "MediaSrc.hxx"
#include "RectList.hxx"
#include "Settings.hxx" #include "Settings.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -609,3 +608,59 @@ void FrameBufferSDL::drawChar(uInt32 xorig, uInt32 yorig, uInt32 c, uInt8 fg)
} }
} }
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RectList::RectList(Uint32 size)
{
currentSize = size;
currentRect = 0;
rectArray = new SDL_Rect[currentSize];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RectList::~RectList()
{
delete[] rectArray;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RectList::add(SDL_Rect* newRect)
{
if(currentRect >= currentSize)
{
currentSize = currentSize * 2;
SDL_Rect *temp = new SDL_Rect[currentSize];
for(Uint32 i = 0; i < currentRect; ++i)
temp[i] = rectArray[i];
delete[] rectArray;
rectArray = temp;
}
rectArray[currentRect].x = newRect->x;
rectArray[currentRect].y = newRect->y;
rectArray[currentRect].w = newRect->w;
rectArray[currentRect].h = newRect->h;
++currentRect;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SDL_Rect* RectList::rects()
{
return rectArray;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Uint32 RectList::numRects()
{
return currentRect;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RectList::start()
{
currentRect = 0;
}

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: FrameBufferSDL.hxx,v 1.1 2003-10-26 19:40:39 stephena Exp $ // $Id: FrameBufferSDL.hxx,v 1.2 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#ifndef FRAMEBUFFER_SDL_HXX #ifndef FRAMEBUFFER_SDL_HXX
@ -202,4 +202,25 @@ class FrameBufferSDL : public FrameBuffer
bool isFullscreen; bool isFullscreen;
}; };
/**
*/
class RectList
{
public:
RectList(Uint32 size = 512);
~RectList();
void add(SDL_Rect* rect);
SDL_Rect* rects();
Uint32 numRects();
void start();
private:
Uint32 currentSize, currentRect;
SDL_Rect* rectArray;
};
#endif #endif

View File

@ -1,72 +0,0 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-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: RectList.cxx,v 1.1 2002-03-05 22:39:47 stephena Exp $
//============================================================================
#include <SDL.h>
#include "RectList.hxx"
RectList::RectList(Uint32 size)
{
currentSize = size;
currentRect = 0;
rectArray = new SDL_Rect[currentSize];
}
RectList::~RectList()
{
delete[] rectArray;
}
void RectList::add(SDL_Rect* newRect)
{
if(currentRect >= currentSize)
{
currentSize = currentSize * 2;
SDL_Rect *temp = new SDL_Rect[currentSize];
for(Uint32 i = 0; i < currentRect; ++i)
temp[i] = rectArray[i];
delete[] rectArray;
rectArray = temp;
}
rectArray[currentRect].x = newRect->x;
rectArray[currentRect].y = newRect->y;
rectArray[currentRect].w = newRect->w;
rectArray[currentRect].h = newRect->h;
++currentRect;
}
SDL_Rect* RectList::rects()
{
return rectArray;
}
Uint32 RectList::numRects()
{
return currentRect;
}
void RectList::start()
{
currentRect = 0;
}

View File

@ -1,42 +0,0 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-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: RectList.hxx,v 1.1 2002-03-05 22:39:47 stephena Exp $
//============================================================================
#ifndef RECT_LIST_HXX
#define RECT_LIST_HXX
#include <SDL.h>
class RectList
{
public:
RectList(Uint32 size = 512);
~RectList();
void add(SDL_Rect* rect);
SDL_Rect* rects();
Uint32 numRects();
void start();
private:
Uint32 currentSize, currentRect;
SDL_Rect* rectArray;
};
#endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: SettingsUNIX.cxx,v 1.1 2003-10-26 19:40:39 stephena Exp $ // $Id: SettingsUNIX.cxx,v 1.2 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#include <cstdlib> #include <cstdlib>
@ -63,11 +63,15 @@ SettingsUNIX::SettingsUNIX()
// Now create UNIX specific settings // Now create UNIX specific settings
#ifdef DISPLAY_OPENGL #ifdef DISPLAY_OPENGL
set("opengl", "false"); set("gl_filter", "nearest");
#endif
#ifdef SNAPSHOT_SUPPORT
set("ssname", "romname");
set("ssdir", "./");
set("ssingle", "false");
#endif #endif
set("fullscreen", "false"); set("fullscreen", "false");
set("grabmouse", "false"); set("grabmouse", "false");
set("center", "false");
set("hidecursor", "false"); set("hidecursor", "false");
set("accurate", "true"); set("accurate", "true");
set("volume", "-1"); set("volume", "-1");
@ -89,6 +93,24 @@ void SettingsUNIX::usage(string& message)
<< endl << endl
<< "Valid options are:" << endl << "Valid options are:" << endl
<< endl << endl
#ifdef DISPLAY_OPENGL
<< " -gl_filter <type> Type is one of the following:\n"
<< " nearest Normal scaling (GL_NEAREST)\n"
<< " linear Blurred scaling (GL_LINEAR)\n"
<< endl
#endif
<< " -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
#ifdef SOUND_SDL
<< " SDL Native SDL driver\n"
#endif
<< endl
<< " -framerate <number> Display the given number of frames per second\n" << " -framerate <number> Display the given number of frames per second\n"
<< " -zoom <size> Makes window be 'size' times normal\n" << " -zoom <size> Makes window be 'size' times normal\n"
<< " -fullscreen <0|1> Play the game in fullscreen mode\n" << " -fullscreen <0|1> Play the game in fullscreen mode\n"
@ -96,9 +118,6 @@ void SettingsUNIX::usage(string& message)
<< " -hidecursor <0|1> Hides the mouse cursor 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" << " -center <0|1> Centers the game window onscreen\n"
<< " -volume <number> Set the volume (0 - 100)\n" << " -volume <number> Set the volume (0 - 100)\n"
#ifdef DISPLAY_OPENGL
<< " -opengl <0|1> Use OpenGL mode.\n"
#endif
#ifdef HAVE_JOYSTICK #ifdef HAVE_JOYSTICK
<< " -paddle <0|1|2|3|real> Indicates which paddle the mouse should emulate\n" << " -paddle <0|1|2|3|real> Indicates which paddle the mouse should emulate\n"
<< " or that real Atari 2600 paddles are being used\n" << " or that real Atari 2600 paddles are being used\n"
@ -114,15 +133,6 @@ void SettingsUNIX::usage(string& message)
<< " -ssdir <path> The directory to save snapshot files to\n" << " -ssdir <path> The directory to save snapshot files to\n"
<< " -ssname <name> How to name the snapshot (romname or md5sum)\n" << " -ssname <name> How to name the snapshot (romname or md5sum)\n"
<< " -sssingle <0|1> Generate single snapshot instead of many\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 #endif
<< endl << endl
#ifdef DEVELOPER_SUPPORT #ifdef DEVELOPER_SUPPORT

View File

@ -13,13 +13,14 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: mainSDL.cxx,v 1.56 2003-10-26 19:40:39 stephena Exp $ // $Id: mainSDL.cxx,v 1.57 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <algorithm> #include <algorithm>
#include <cstdlib>
#ifdef HAVE_GETTIMEOFDAY #ifdef HAVE_GETTIMEOFDAY
#include <time.h> #include <time.h>
@ -34,13 +35,18 @@
#include "StellaEvent.hxx" #include "StellaEvent.hxx"
#include "EventHandler.hxx" #include "EventHandler.hxx"
#include "FrameBuffer.hxx" #include "FrameBuffer.hxx"
#include "FrameBufferSDL.hxx"
#include "PropsSet.hxx" #include "PropsSet.hxx"
#include "Sound.hxx" #include "Sound.hxx"
#include "Settings.hxx" #include "Settings.hxx"
#ifdef DISPLAY_OPENGL #ifdef DISPLAY_OPENGL
#include "FrameBufferGL.hxx" #include "FrameBufferGL.hxx"
// Pointer to the OpenGL display object or the null pointer
static FrameBufferGL* theDisplay = (FrameBufferGL*) NULL;
#else
#include "FrameBufferSDL.hxx"
// Pointer to the software display object or the null pointer
static FrameBufferSDL* theDisplay = (FrameBufferSDL*) NULL;
#endif #endif
#ifdef SOUND_ALSA #ifdef SOUND_ALSA
@ -83,9 +89,6 @@ static Sound* theSound = (Sound*) NULL;
// Pointer to the settings object or the null pointer // Pointer to the settings object or the null pointer
static Settings* theSettings = (Settings*) NULL; static Settings* theSettings = (Settings*) NULL;
// Pointer to the display object or the null pointer
static FrameBufferSDL* theDisplay = (FrameBufferSDL*) NULL;
// Indicates if the mouse should be grabbed // Indicates if the mouse should be grabbed
static bool theGrabMouseIndicator = false; static bool theGrabMouseIndicator = false;
@ -201,7 +204,6 @@ static Switches keyList[] = {
{ SDLK_CLEAR, StellaEvent::KCODE_CLEAR }, { SDLK_CLEAR, StellaEvent::KCODE_CLEAR },
{ SDLK_RETURN, StellaEvent::KCODE_RETURN }, { SDLK_RETURN, StellaEvent::KCODE_RETURN },
{ SDLK_ESCAPE, StellaEvent::KCODE_ESCAPE }, { SDLK_ESCAPE, StellaEvent::KCODE_ESCAPE },
{ SDLK_SPACE, StellaEvent::KCODE_SPACE },
{ SDLK_COMMA, StellaEvent::KCODE_COMMA }, { SDLK_COMMA, StellaEvent::KCODE_COMMA },
{ SDLK_MINUS, StellaEvent::KCODE_MINUS }, { SDLK_MINUS, StellaEvent::KCODE_MINUS },
{ SDLK_PERIOD, StellaEvent::KCODE_PERIOD }, { SDLK_PERIOD, StellaEvent::KCODE_PERIOD },
@ -506,7 +508,7 @@ void handleEvents()
{ {
if((event.active.state & SDL_APPACTIVE) && (event.active.gain == 0)) if((event.active.state & SDL_APPACTIVE) && (event.active.gain == 0))
{ {
if(!theSettings->pause()) if(!theConsole->eventHandler().doPause())
{ {
theConsole->eventHandler().sendEvent(Event::Pause, 1); theConsole->eventHandler().sendEvent(Event::Pause, 1);
} }
@ -671,6 +673,10 @@ int main(int argc, char* argv[])
thePaddleMode = theSettings->getInt("paddle"); thePaddleMode = theSettings->getInt("paddle");
theShowInfoFlag = theSettings->getBool("showinfo"); theShowInfoFlag = theSettings->getBool("showinfo");
// Request that the SDL window be centered, if possible
// This will probably only work under Linux
setenv("SDL_VIDEO_CENTERED", "1", 1);
// Get a pointer to the file which contains the cartridge ROM // Get a pointer to the file which contains the cartridge ROM
const char* file = argv[argc - 1]; const char* file = argv[argc - 1];
@ -697,6 +703,24 @@ int main(int argc, char* argv[])
return 0; return 0;
} }
// Create an SDL window
#ifdef DISPLAY_OPENGL
theDisplay = new FrameBufferGL();
if(theShowInfoFlag)
cout << "Using OpenGL SDL for video.\n";
#else
theDisplay = new FrameBufferSDL();
if(theShowInfoFlag)
cout << "Using software SDL for video.\n";
#endif
if(!theDisplay)
{
cerr << "ERROR: Couldn't set up display.\n";
cleanup();
return 0;
}
// Create a sound object for playing audio // Create a sound object for playing audio
string driver = theSettings->getString("sound"); string driver = theSettings->getString("sound");
if(driver == "0") if(driver == "0")
@ -741,25 +765,9 @@ int main(int argc, char* argv[])
// Get just the filename of the file containing the ROM image // Get just the filename of the file containing the ROM image
const char* filename = (!strrchr(file, '/')) ? file : strrchr(file, '/') + 1; const char* filename = (!strrchr(file, '/')) ? file : strrchr(file, '/') + 1;
// Setup the SDL window
#ifdef DISPLAY_OPENGL
bool useGL = theSettings->getBool("opengl");
if(useGL)
theDisplay = new FrameBufferGL();
else
#endif
theDisplay = new FrameBufferSDL();
if(!theDisplay)
{
cerr << "ERROR: Couldn't set up display.\n";
cleanup();
return 0;
}
// Create the 2600 game console // Create the 2600 game console
theConsole = new Console(image, size, filename, *theSettings, propertiesSet, theConsole = new Console(image, size, filename, *theSettings, propertiesSet,
*theDisplay, theSound->getSampleRate()); *theDisplay, *theSound);
// Free the image since we don't need it any longer // Free the image since we don't need it any longer
delete[] image; delete[] image;
@ -790,21 +798,13 @@ int main(int argc, char* argv[])
for(;;) for(;;)
{ {
// Exit if the user wants to quit // Exit if the user wants to quit
if(theSettings->quit()) if(theConsole->eventHandler().doQuit())
{ {
break; break;
} }
// Call handleEvents here to see if user pressed pause
startTime = getTicks(); startTime = getTicks();
handleEvents(); handleEvents();
if(theSettings->pause())
{
theDisplay->update();
SDL_Delay(10);
continue;
}
theDisplay->update(); theDisplay->update();
theSound->updateSound(*theDisplay->mediaSource()); theSound->updateSound(*theDisplay->mediaSource());
@ -835,24 +835,16 @@ int main(int argc, char* argv[])
for(;;) for(;;)
{ {
// Exit if the user wants to quit // Exit if the user wants to quit
if(theSettings->quit()) if(theConsole->eventHandler().doQuit())
{ {
break; break;
} }
/*
startTime = getTicks();
handleEvents();
if(!theSettings->pause())
{
theSound->updateSound(*theDisplay->mediaSource());
}
theDisplay->update();
*/
startTime = getTicks(); startTime = getTicks();
handleEvents(); handleEvents();
theDisplay->update(); theDisplay->update();
theSound->updateSound(*theDisplay->mediaSource()); theSound->updateSound(*theDisplay->mediaSource());
///
currentTime = getTicks(); currentTime = getTicks();
virtualTime += timePerFrame; virtualTime += timePerFrame;
if(currentTime < virtualTime) if(currentTime < virtualTime)

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: SoundALSA.cxx,v 1.3 2003-02-25 03:12:55 stephena Exp $ // $Id: SoundALSA.cxx,v 1.4 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
@ -30,7 +30,8 @@ SoundALSA::SoundALSA()
myOriginalVolumeLeft(-1), myOriginalVolumeLeft(-1),
myOriginalVolumeRight(-1), myOriginalVolumeRight(-1),
myBufferSize(0), myBufferSize(0),
mySampleRate(0) mySampleRate(0),
myPauseStatus(false)
{ {
Int32 err; Int32 err;
char pcmName[] = "plughw:0,0"; char pcmName[] = "plughw:0,0";
@ -242,6 +243,9 @@ void SoundALSA::updateSound(MediaSource& mediaSource)
{ {
if(myIsInitializedFlag) if(myIsInitializedFlag)
{ {
if(myPauseStatus)
return;
snd_pcm_sframes_t frames; snd_pcm_sframes_t frames;
uInt8 periodCount = 0; uInt8 periodCount = 0;

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: SoundALSA.hxx,v 1.3 2003-02-25 03:12:55 stephena Exp $ // $Id: SoundALSA.hxx,v 1.4 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#ifndef SOUNDALSA_HXX #ifndef SOUNDALSA_HXX
@ -30,7 +30,7 @@
Advanced Linux Sound Architecture (ALSA) version 0.9.x API. Advanced Linux Sound Architecture (ALSA) version 0.9.x API.
@author Stephen Anthony @author Stephen Anthony
@version $Id: SoundALSA.hxx,v 1.3 2003-02-25 03:12:55 stephena Exp $ @version $Id: SoundALSA.hxx,v 1.4 2003-11-06 22:22:32 stephena Exp $
*/ */
class SoundALSA : public Sound class SoundALSA : public Sound
{ {
@ -74,6 +74,14 @@ class SoundALSA : public Sound
*/ */
void setSoundVolume(Int32 percent); void setSoundVolume(Int32 percent);
/**
Sets the pause status. While pause is selected, updateSound()
should not play any sound.
@param status Toggle pause based on status
*/
void pause(bool status) { myPauseStatus = status; }
/** /**
Update the sound device using the audio sample from the specified Update the sound device using the audio sample from the specified
media source. media source.
@ -110,5 +118,8 @@ class SoundALSA : public Sound
// PCM sample rate // PCM sample rate
uInt32 mySampleRate; uInt32 mySampleRate;
// The pause status
bool myPauseStatus;
}; };
#endif #endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: SoundOSS.cxx,v 1.2 2003-02-25 03:12:55 stephena Exp $ // $Id: SoundOSS.cxx,v 1.3 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#include <fcntl.h> #include <fcntl.h>
@ -39,7 +39,8 @@ SoundOSS::SoundOSS()
myDspFd(-1), myDspFd(-1),
myMixerFd(-1), myMixerFd(-1),
myOriginalVolume(-1), myOriginalVolume(-1),
mySampleRate(0) mySampleRate(0),
myPauseStatus(false)
{ {
// Open the sound device for writing // Open the sound device for writing
if((myDspFd = open(DSP_DEVICE, O_WRONLY, 0)) == -1) if((myDspFd = open(DSP_DEVICE, O_WRONLY, 0)) == -1)
@ -197,6 +198,9 @@ void SoundOSS::updateSound(MediaSource& mediaSource)
{ {
if(myIsInitializedFlag) if(myIsInitializedFlag)
{ {
if(myPauseStatus)
return;
// Get audio buffer information // Get audio buffer information
audio_buf_info info; audio_buf_info info;
if(ioctl(myDspFd, SNDCTL_DSP_GETOSPACE, &info) == -1) if(ioctl(myDspFd, SNDCTL_DSP_GETOSPACE, &info) == -1)

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: SoundOSS.hxx,v 1.2 2003-02-25 03:12:55 stephena Exp $ // $Id: SoundOSS.hxx,v 1.3 2003-11-06 22:22:32 stephena Exp $
//============================================================================ //============================================================================
#ifndef SOUNDOSS_HXX #ifndef SOUNDOSS_HXX
@ -28,7 +28,7 @@
Open Sound System (OSS) API. Open Sound System (OSS) API.
@author Bradford W. Mott @author Bradford W. Mott
@version $Id: SoundOSS.hxx,v 1.2 2003-02-25 03:12:55 stephena Exp $ @version $Id: SoundOSS.hxx,v 1.3 2003-11-06 22:22:32 stephena Exp $
*/ */
class SoundOSS : public Sound class SoundOSS : public Sound
{ {
@ -72,6 +72,14 @@ class SoundOSS : public Sound
*/ */
void setSoundVolume(Int32 percent); void setSoundVolume(Int32 percent);
/**
Sets the pause status. While pause is selected, updateSound()
should not play any sound.
@param status Toggle pause based on status
*/
void pause(bool status) { myPauseStatus = status; }
/** /**
Update the sound device using the audio sample from the specified Update the sound device using the audio sample from the specified
media source. media source.
@ -95,5 +103,8 @@ class SoundOSS : public Sound
// DSP sample rate // DSP sample rate
uInt32 mySampleRate; uInt32 mySampleRate;
// The pause status
bool myPauseStatus;
}; };
#endif #endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: SoundSDL.cxx,v 1.2 2003-02-25 03:12:55 stephena Exp $ // $Id: SoundSDL.cxx,v 1.3 2003-11-06 22:22:33 stephena Exp $
//============================================================================ //============================================================================
#include <SDL.h> #include <SDL.h>
@ -27,7 +27,8 @@ SoundSDL::SoundSDL(bool activate)
myIsInitializedFlag(false), myIsInitializedFlag(false),
myIsMuted(false), myIsMuted(false),
mySampleRate(31400), mySampleRate(31400),
mySampleQueue(mySampleRate) mySampleQueue(mySampleRate),
myPauseStatus(false)
{ {
if(activate) if(activate)
{ {
@ -165,6 +166,9 @@ void SoundSDL::updateSound(MediaSource& mediaSource)
{ {
if(myIsInitializedFlag) if(myIsInitializedFlag)
{ {
if(myPauseStatus)
return;
// Make sure we have exclusive access to the sample queue // Make sure we have exclusive access to the sample queue
SDL_LockAudio(); SDL_LockAudio();

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: SoundSDL.hxx,v 1.2 2003-02-25 03:12:55 stephena Exp $ // $Id: SoundSDL.hxx,v 1.3 2003-11-06 22:22:33 stephena Exp $
//============================================================================ //============================================================================
#ifndef SOUNDSDL_HXX #ifndef SOUNDSDL_HXX
@ -29,7 +29,7 @@
This class implements the sound API for SDL. This class implements the sound API for SDL.
@author Stephen Anthony and Bradford W. Mott @author Stephen Anthony and Bradford W. Mott
@version $Id: SoundSDL.hxx,v 1.2 2003-02-25 03:12:55 stephena Exp $ @version $Id: SoundSDL.hxx,v 1.3 2003-11-06 22:22:33 stephena Exp $
*/ */
class SoundSDL : public Sound class SoundSDL : public Sound
{ {
@ -80,6 +80,14 @@ class SoundSDL : public Sound
*/ */
void setSoundVolume(Int32 percent); void setSoundVolume(Int32 percent);
/**
Sets the pause status. While pause is selected, updateSound()
should not play any sound.
@param status Toggle pause based on status
*/
void pause(bool status) { myPauseStatus = status; }
/** /**
Update the sound device using the audio sample from the specified Update the sound device using the audio sample from the specified
media source. media source.
@ -165,6 +173,9 @@ class SoundSDL : public Sound
// Queue which holds samples from the media source before they are played // Queue which holds samples from the media source before they are played
SampleQueue mySampleQueue; SampleQueue mySampleQueue;
// The pause status
bool myPauseStatus;
private: private:
// Callback function invoked by the SDL Audio library when it needs data // Callback function invoked by the SDL Audio library when it needs data
static void callback(void* udata, uInt8* stream, int len); static void callback(void* udata, uInt8* stream, int len);

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: mainX11.cxx,v 1.42 2003-09-19 15:45:01 stephena Exp $ // $Id: mainX11.cxx,v 1.43 2003-11-06 22:22:33 stephena Exp $
//============================================================================ //============================================================================
#include <fstream> #include <fstream>
@ -64,7 +64,7 @@
#endif #endif
// function prototypes // function prototypes
// FIXME the following will be placed in a Display class eventually ... // the following will be placed in a Display class eventually ...
// A graphic context for each of the 2600's colors // A graphic context for each of the 2600's colors
static GC theGCTable[256]; static GC theGCTable[256];
static bool setupDisplay(); static bool setupDisplay();
@ -647,7 +647,7 @@ void handleEvents()
{ {
resizeWindow(0); resizeWindow(0);
} }
// FIXME - change x to Ctrl-x // change x to Ctrl-x
else if((key == XK_g) && (event.type == KeyPress)) else if((key == XK_g) && (event.type == KeyPress))
{ {
// don't change grabmouse in fullscreen mode // don't change grabmouse in fullscreen mode