mirror of https://github.com/stella-emu/stella.git
Integrated the SDL software and OpenGL modes into stella.sdl.
You can now select the video backend with '-video soft' or '-video gl'. Cleaned up the menu text lines that were longer than the current display width. These lines are now truncated and have a '...' appended to them. The menu modes are now more tolerant of display sizes. So (for example), if some port uses a 640 pixel wide framebuffer, the menu will now resize and fully take advantage of all available space. I've looked at the Windows code, but I still haven't mustered the strength to work on it. It will basically be a complete rewrite of sound, video, and input classes. And I'm not looking forward to it ... git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@201 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
8239748980
commit
fc96e5b0d8
|
@ -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.44 2003-11-06 22:22:32 stephena Exp $
|
||||
## $Id: makefile,v 1.45 2003-11-09 23:53:19 stephena Exp $
|
||||
##============================================================================
|
||||
|
||||
##============================================================================
|
||||
|
@ -34,7 +34,7 @@ SOUND_OSS = 1
|
|||
#SOUND_SDL = 1
|
||||
|
||||
### to include OpenGL video support (SDL)
|
||||
DISPLAY_OPENGL = 0
|
||||
# OPENGL_SUPPORT = 1
|
||||
|
||||
### to include joystick support (SDL)
|
||||
# JOYSTICK_SUPPORT = 1
|
||||
|
@ -140,16 +140,12 @@ ifeq ($(SOUND_ALSA), 1)
|
|||
LIBS.SDL += -lasound
|
||||
endif
|
||||
|
||||
ifeq ($(DISPLAY_OPENGL), 1)
|
||||
ifeq ($(OPENGL_SUPPORT), 1)
|
||||
OPTS.SDL += -DDISPLAY_OPENGL=1
|
||||
OBJS.SDL += FrameBufferGL.o
|
||||
LIBS.SDL += -lGL -lGLU
|
||||
endif
|
||||
|
||||
ifeq ($(DISPLAY_OPENGL), 0)
|
||||
OBJS.SDL += FrameBufferSDL.o
|
||||
endif
|
||||
|
||||
|
||||
default:
|
||||
@echo ""
|
||||
|
@ -185,7 +181,7 @@ linux-sdl:
|
|||
LDFLAGS+="$(CFLAGS.SDL)" \
|
||||
LDLIBS="-lX11 -lXext" \
|
||||
LDLIBS+="$(LIBS.SDL)" \
|
||||
OBJS="mainSDL.o SettingsUNIX.o" \
|
||||
OBJS="mainSDL.o SettingsUNIX.o FrameBufferSDL.o FrameBufferSoft.o" \
|
||||
OBJS+="$(OBJS.SDL)"
|
||||
|
||||
###############################################################################
|
||||
|
@ -403,6 +399,9 @@ RectList.o: $(UI)/sdl/RectList.cxx $(UI)/sdl/RectList.hxx
|
|||
FrameBufferSDL.o: $(UI)/sdl/FrameBufferSDL.cxx $(UI)/sdl/FrameBufferSDL.hxx
|
||||
$(CXX) -c $(FLAGS) $(OPTIONS) $(LDFLAGS) $(UI)/sdl/FrameBufferSDL.cxx
|
||||
|
||||
FrameBufferSoft.o: $(UI)/sdl/FrameBufferSoft.cxx $(UI)/sdl/FrameBufferSoft.hxx
|
||||
$(CXX) -c $(FLAGS) $(OPTIONS) $(LDFLAGS) $(UI)/sdl/FrameBufferSoft.cxx
|
||||
|
||||
FrameBufferGL.o: $(UI)/sdl/FrameBufferGL.cxx $(UI)/sdl/FrameBufferGL.hxx
|
||||
$(CXX) -c $(FLAGS) $(OPTIONS) $(LDFLAGS) $(UI)/sdl/FrameBufferGL.cxx
|
||||
|
||||
|
|
|
@ -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.3 2003-11-06 22:22:32 stephena Exp $
|
||||
// $Id: FrameBuffer.cxx,v 1.4 2003-11-09 23:53:19 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <sstream>
|
||||
|
@ -28,8 +28,6 @@
|
|||
#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
|
||||
#define FONTHEIGHT 8
|
||||
|
||||
|
@ -53,13 +51,16 @@ FrameBuffer::FrameBuffer()
|
|||
myHeight(300),
|
||||
theRedrawEntireFrameIndicator(true),
|
||||
myPauseStatus(false),
|
||||
myFGColor(10),
|
||||
myBGColor(0),
|
||||
myFrameRate(0),
|
||||
myCurrentWidget(W_NONE),
|
||||
myRemapEventSelectedFlag(false),
|
||||
mySelectedEvent(Event::NoType),
|
||||
myMenuMode(false),
|
||||
theMenuChangedIndicator(false),
|
||||
myMaxLines(0),
|
||||
myMaxRows(0),
|
||||
myMaxColumns(0),
|
||||
myMainMenuIndex(0),
|
||||
myMainMenuItems(sizeof(ourMainMenu)/sizeof(MainMenuItem)),
|
||||
myRemapMenuIndex(0),
|
||||
|
@ -95,29 +96,46 @@ void FrameBuffer::initDisplay(Console* console, MediaSource* mediasrc)
|
|||
ourPropertiesInfo[7] = "MD5SUM:";
|
||||
ourPropertiesInfo[8] = myConsole->properties().get("Cartridge.MD5");
|
||||
|
||||
// Figure out the longest string
|
||||
for(uInt8 i = 0; i < 9; i++)
|
||||
if(ourPropertiesInfo[i].length() > myInfoMenuWidth)
|
||||
myInfoMenuWidth = ourPropertiesInfo[i].length();
|
||||
|
||||
// Get the arrays containing key and joystick mappings
|
||||
myConsole->eventHandler().getKeymapArray(&myKeyTable, &myKeyTableSize);
|
||||
myConsole->eventHandler().getJoymapArray(&myJoyTable, &myJoyTableSize);
|
||||
|
||||
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;
|
||||
// The following has to be done after the initialization of the derived class,
|
||||
// since we need the exact width and height of the display
|
||||
|
||||
// Determine the maximum number of characters that can be onscreen
|
||||
myMaxColumns = myWidth / FONTWIDTH - 3;
|
||||
myMaxRows = myHeight / LINEOFFSET - 2;
|
||||
|
||||
// Set up the correct bounds for the remap menu
|
||||
myRemapMenuMaxLines = myRemapMenuItems > myMaxLines ? myMaxLines : myRemapMenuItems;
|
||||
myRemapMenuMaxLines = myRemapMenuItems > myMaxRows ? myMaxRows : myRemapMenuItems;
|
||||
myRemapMenuLowIndex = 0;
|
||||
myRemapMenuHighIndex = myRemapMenuMaxLines;
|
||||
|
||||
// Figure out the longest properties string,
|
||||
// and cut any string that is wider than the display
|
||||
for(uInt8 i = 0; i < 9; i++)
|
||||
{
|
||||
if(ourPropertiesInfo[i].length() > (uInt32) myInfoMenuWidth)
|
||||
{
|
||||
myInfoMenuWidth = ourPropertiesInfo[i].length();
|
||||
if(myInfoMenuWidth > myMaxColumns)
|
||||
{
|
||||
myInfoMenuWidth = myMaxColumns;
|
||||
string s = ourPropertiesInfo[i];
|
||||
ourPropertiesInfo[i] = s.substr(0, myMaxColumns - 3) + "...";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, load the remap menu with strings,
|
||||
// clipping any strings which are wider than the display
|
||||
loadRemapMenu();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -151,8 +169,8 @@ void FrameBuffer::update()
|
|||
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);
|
||||
drawBoundedBox(x, y+1, width, height-2);
|
||||
drawText(x + XBOXOFFSET/2, LINEOFFSET/2 + y, myMessageText);
|
||||
myMessageTime--;
|
||||
|
||||
// Erase this message on next update
|
||||
|
@ -167,7 +185,6 @@ void FrameBuffer::update()
|
|||
// or the menus have changed
|
||||
if(theMenuChangedIndicator || theRedrawEntireFrameIndicator)
|
||||
{
|
||||
cerr << "redrawing screen and menus\n";
|
||||
drawMediaSource();
|
||||
|
||||
// Then overlay any menu items
|
||||
|
@ -232,35 +249,35 @@ inline void FrameBuffer::drawMainMenu()
|
|||
|
||||
// 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);
|
||||
drawBoundedBox(x-2, y-2, width+3, height+3);
|
||||
for(i = 0; i < myMainMenuItems; i++)
|
||||
drawText(xpos, LINEOFFSET*i + y + YBOXOFFSET, ourMainMenu[i].action, FGCOLOR);
|
||||
drawText(xpos, LINEOFFSET*i + y + YBOXOFFSET, ourMainMenu[i].action);
|
||||
|
||||
// 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);
|
||||
drawChar(x, ypos, LEFTARROW);
|
||||
drawChar(x + width - FONTWIDTH, ypos, RIGHTARROW);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
inline void FrameBuffer::drawRemapMenu()
|
||||
{
|
||||
uInt32 x, y, width, height, i, xpos, ypos;
|
||||
uInt32 x, y, width, height, xpos, ypos;
|
||||
|
||||
width = (myWidth >> 3) * FONTWIDTH - (FONTWIDTH << 1);
|
||||
height = myMaxLines*LINEOFFSET + (FONTHEIGHT << 1);
|
||||
height = myMaxRows*LINEOFFSET + (FONTHEIGHT << 1);
|
||||
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++)
|
||||
drawBoundedBox(x-2, y-2, width+3, height+3);
|
||||
for(Int32 i = myRemapMenuLowIndex; i < myRemapMenuHighIndex; i++)
|
||||
{
|
||||
ypos = LINEOFFSET*(i-myRemapMenuLowIndex) + y + YBOXOFFSET;
|
||||
drawText(x + XBOXOFFSET, ypos, ourRemapMenu[i].action, FGCOLOR);
|
||||
drawText(x + XBOXOFFSET, ypos, ourRemapMenu[i].action);
|
||||
|
||||
xpos = width - ourRemapMenu[i].key.length() * FONTWIDTH;
|
||||
drawText(xpos, ypos, ourRemapMenu[i].key, FGCOLOR);
|
||||
drawText(xpos, ypos, ourRemapMenu[i].key);
|
||||
}
|
||||
|
||||
// Normally draw an arrow indicating the current line,
|
||||
|
@ -268,8 +285,8 @@ inline void FrameBuffer::drawRemapMenu()
|
|||
if(!myRemapEventSelectedFlag)
|
||||
{
|
||||
ypos = LINEOFFSET*(myRemapMenuIndex-myRemapMenuLowIndex) + y + YBOXOFFSET;
|
||||
drawChar(x, ypos, LEFTARROW, FGCOLOR);
|
||||
drawChar(x + width - FONTWIDTH, ypos, RIGHTARROW, FGCOLOR);
|
||||
drawChar(x, ypos, LEFTARROW);
|
||||
drawChar(x + width - FONTWIDTH, ypos, RIGHTARROW);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -277,19 +294,19 @@ inline void FrameBuffer::drawRemapMenu()
|
|||
|
||||
// Left marker is at the beginning of event name text
|
||||
xpos = width - ourRemapMenu[myRemapMenuIndex].key.length() * FONTWIDTH - FONTWIDTH;
|
||||
drawChar(xpos, ypos, LEFTMARKER, FGCOLOR);
|
||||
drawChar(xpos, ypos, LEFTMARKER);
|
||||
|
||||
// Right marker is at the end of the line
|
||||
drawChar(x + width - FONTWIDTH, ypos, RIGHTMARKER, FGCOLOR);
|
||||
drawChar(x + width - FONTWIDTH, ypos, RIGHTMARKER);
|
||||
}
|
||||
|
||||
// Finally, indicate that there are more items to the top or bottom
|
||||
xpos = (width >> 1) - (FONTWIDTH >> 1);
|
||||
if(myRemapMenuHighIndex - myMaxLines > 0)
|
||||
drawChar(xpos, y, UPARROW, FGCOLOR);
|
||||
if(myRemapMenuHighIndex - myMaxRows > 0)
|
||||
drawChar(xpos, y, UPARROW);
|
||||
|
||||
if(myRemapMenuLowIndex + myMaxLines < myRemapMenuItems)
|
||||
drawChar(xpos, height - (FONTWIDTH >> 1), DOWNARROW, FGCOLOR);
|
||||
if(myRemapMenuLowIndex + myMaxRows < myRemapMenuItems)
|
||||
drawChar(xpos, height - (FONTWIDTH >> 1), DOWNARROW);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -304,9 +321,9 @@ inline void FrameBuffer::drawInfoMenu()
|
|||
|
||||
// Draw the bounded box and text
|
||||
xpos = x + XBOXOFFSET;
|
||||
drawBoundedBox(x, y, width, height, FGCOLOR, BGCOLOR);
|
||||
drawBoundedBox(x, y, width, height);
|
||||
for(i = 0; i < 9; i++)
|
||||
drawText(xpos, LINEOFFSET*i + y + YBOXOFFSET, ourPropertiesInfo[i], FGCOLOR);
|
||||
drawText(xpos, LINEOFFSET*i + y + YBOXOFFSET, ourPropertiesInfo[i]);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -325,9 +342,9 @@ void FrameBuffer::sendKeyEvent(StellaEvent::KeyCode key, Int32 state)
|
|||
if(key == StellaEvent::KCODE_RETURN)
|
||||
myCurrentWidget = currentSelectedWidget();
|
||||
else if(key == StellaEvent::KCODE_UP)
|
||||
moveCursorUp();
|
||||
moveCursorUp(1);
|
||||
else if(key == StellaEvent::KCODE_DOWN)
|
||||
moveCursorDown();
|
||||
moveCursorDown(1);
|
||||
|
||||
break; // MAIN_MENU
|
||||
|
||||
|
@ -347,13 +364,13 @@ void FrameBuffer::sendKeyEvent(StellaEvent::KeyCode key, Int32 state)
|
|||
myRemapEventSelectedFlag = true;
|
||||
}
|
||||
else if(key == StellaEvent::KCODE_UP)
|
||||
moveCursorUp();
|
||||
moveCursorUp(1);
|
||||
else if(key == StellaEvent::KCODE_DOWN)
|
||||
moveCursorDown();
|
||||
moveCursorDown(1);
|
||||
else if(key == StellaEvent::KCODE_PAGEUP)
|
||||
movePageUp();
|
||||
moveCursorUp(4);
|
||||
else if(key == StellaEvent::KCODE_PAGEDOWN)
|
||||
movePageDown();
|
||||
moveCursorDown(4);
|
||||
else if(key == StellaEvent::KCODE_ESCAPE)
|
||||
{
|
||||
myCurrentWidget = MAIN_MENU;
|
||||
|
@ -383,7 +400,6 @@ void FrameBuffer::sendJoyEvent(StellaEvent::JoyStick stick,
|
|||
if(myCurrentWidget == W_NONE || state != 1)
|
||||
return;
|
||||
|
||||
cerr << "stick = " << stick << ", button = " << code << endl;
|
||||
// Redraw the menus whenever a joy event is received
|
||||
theMenuChangedIndicator = true;
|
||||
|
||||
|
@ -394,9 +410,9 @@ cerr << "stick = " << stick << ", button = " << code << endl;
|
|||
// if(key == StellaEvent::KCODE_RETURN)
|
||||
// myCurrentWidget = currentSelectedWidget();
|
||||
if(stick == StellaEvent::JSTICK_0 && code == StellaEvent::JAXIS_UP)
|
||||
moveCursorUp();
|
||||
moveCursorUp(1);
|
||||
else if(stick == StellaEvent::JSTICK_0 && code == StellaEvent::JAXIS_DOWN)
|
||||
moveCursorDown();
|
||||
moveCursorDown(1);
|
||||
|
||||
break; // MAIN_MENU
|
||||
|
||||
|
@ -407,9 +423,9 @@ cerr << "stick = " << stick << ", button = " << code << endl;
|
|||
myRemapEventSelectedFlag = false;
|
||||
}
|
||||
else if(stick == StellaEvent::JSTICK_0 && code == StellaEvent::JAXIS_UP)
|
||||
moveCursorUp();
|
||||
moveCursorUp(1);
|
||||
else if(stick == StellaEvent::JSTICK_0 && code == StellaEvent::JAXIS_DOWN)
|
||||
moveCursorDown();
|
||||
moveCursorDown(1);
|
||||
// else if(key == StellaEvent::KCODE_PAGEUP)
|
||||
// movePageUp();
|
||||
// else if(key == StellaEvent::KCODE_PAGEDOWN)
|
||||
|
@ -452,7 +468,7 @@ Event::Type FrameBuffer::currentSelectedEvent()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBuffer::moveCursorUp()
|
||||
void FrameBuffer::moveCursorUp(uInt32 amt)
|
||||
{
|
||||
switch(myCurrentWidget)
|
||||
{
|
||||
|
@ -463,20 +479,24 @@ void FrameBuffer::moveCursorUp()
|
|||
break;
|
||||
|
||||
case REMAP_MENU:
|
||||
// Since this menu will have more options than can fit it one screen,
|
||||
// we have to implement a sliding window
|
||||
if(myRemapMenuIndex > myRemapMenuLowIndex)
|
||||
// First move cursor down by the given amt
|
||||
myRemapMenuIndex -= amt;
|
||||
|
||||
// Move down the boundaries
|
||||
if(myRemapMenuIndex < myRemapMenuLowIndex)
|
||||
{
|
||||
myRemapMenuIndex--;
|
||||
Int32 x = myRemapMenuLowIndex - myRemapMenuIndex;
|
||||
myRemapMenuLowIndex -= x;
|
||||
myRemapMenuHighIndex -= x;
|
||||
}
|
||||
else if(myRemapMenuIndex == myRemapMenuLowIndex)
|
||||
|
||||
// Then scale back up, if necessary
|
||||
if(myRemapMenuLowIndex < 0)
|
||||
{
|
||||
if(myRemapMenuLowIndex > 0)
|
||||
{
|
||||
myRemapMenuLowIndex--;
|
||||
myRemapMenuHighIndex--;
|
||||
myRemapMenuIndex--;
|
||||
}
|
||||
Int32 x = 0 - myRemapMenuLowIndex;
|
||||
myRemapMenuIndex += x;
|
||||
myRemapMenuLowIndex += x;
|
||||
myRemapMenuHighIndex += x;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -487,7 +507,7 @@ void FrameBuffer::moveCursorUp()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBuffer::moveCursorDown()
|
||||
void FrameBuffer::moveCursorDown(uInt32 amt)
|
||||
{
|
||||
switch(myCurrentWidget)
|
||||
{
|
||||
|
@ -498,85 +518,27 @@ void FrameBuffer::moveCursorDown()
|
|||
break;
|
||||
|
||||
case REMAP_MENU:
|
||||
// Since this menu will have more options than can fit it one screen,
|
||||
// we have to implement a sliding window
|
||||
if(myRemapMenuIndex < myRemapMenuHighIndex - 1)
|
||||
// First move cursor up by the given amount
|
||||
myRemapMenuIndex += amt;
|
||||
|
||||
// Move up the boundaries
|
||||
if(myRemapMenuIndex >= myRemapMenuHighIndex)
|
||||
{
|
||||
myRemapMenuIndex++;
|
||||
}
|
||||
else if(myRemapMenuIndex == myRemapMenuHighIndex - 1)
|
||||
{
|
||||
if(myRemapMenuHighIndex < myRemapMenuItems)
|
||||
{
|
||||
myRemapMenuLowIndex++;
|
||||
myRemapMenuHighIndex++;
|
||||
myRemapMenuIndex++;
|
||||
}
|
||||
Int32 x = myRemapMenuIndex - myRemapMenuHighIndex + 1;
|
||||
|
||||
myRemapMenuLowIndex += x;
|
||||
myRemapMenuHighIndex += x;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default: // This should never happen
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBuffer::movePageUp()
|
||||
{
|
||||
switch(myCurrentWidget)
|
||||
{
|
||||
case MAIN_MENU:
|
||||
break;
|
||||
|
||||
case REMAP_MENU:
|
||||
if(myRemapMenuLowIndex < myMaxLines)
|
||||
// Then scale back down, if necessary
|
||||
if(myRemapMenuHighIndex >= myRemapMenuItems)
|
||||
{
|
||||
myRemapMenuLowIndex = 0;
|
||||
myRemapMenuHighIndex = myMaxLines;
|
||||
Int32 x = myRemapMenuHighIndex - myRemapMenuItems;
|
||||
|
||||
myRemapMenuIndex -= x;
|
||||
myRemapMenuLowIndex -= x;
|
||||
myRemapMenuHighIndex -= x;
|
||||
}
|
||||
else
|
||||
{
|
||||
myRemapMenuLowIndex -= myMaxLines;
|
||||
myRemapMenuHighIndex -= myMaxLines;
|
||||
}
|
||||
|
||||
// Don't scroll the cursor if it falls within the screen
|
||||
if(myRemapMenuIndex < myRemapMenuLowIndex ||
|
||||
myRemapMenuIndex > myRemapMenuHighIndex-1)
|
||||
myRemapMenuIndex = myRemapMenuHighIndex - 1;
|
||||
|
||||
break;
|
||||
|
||||
default: // This should never happen
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBuffer::movePageDown()
|
||||
{
|
||||
switch(myCurrentWidget)
|
||||
{
|
||||
case MAIN_MENU:
|
||||
break;
|
||||
|
||||
case REMAP_MENU:
|
||||
if(myRemapMenuHighIndex + myMaxLines >= myRemapMenuItems)
|
||||
{
|
||||
myRemapMenuHighIndex = myRemapMenuItems;
|
||||
myRemapMenuLowIndex = myRemapMenuHighIndex - myMaxLines;
|
||||
}
|
||||
else
|
||||
{
|
||||
myRemapMenuLowIndex += myMaxLines;
|
||||
myRemapMenuHighIndex += myMaxLines;
|
||||
}
|
||||
|
||||
// Don't scroll the cursor if it falls within the screen
|
||||
if(myRemapMenuIndex < myRemapMenuLowIndex ||
|
||||
myRemapMenuIndex > myRemapMenuHighIndex-1)
|
||||
myRemapMenuIndex = myRemapMenuLowIndex;
|
||||
|
||||
break;
|
||||
|
||||
|
@ -589,7 +551,7 @@ void FrameBuffer::movePageDown()
|
|||
void FrameBuffer::loadRemapMenu()
|
||||
{
|
||||
// Fill the remap menu with the current key and joystick mappings
|
||||
for(uInt32 i = 0; i < myRemapMenuItems; ++i)
|
||||
for(Int32 i = 0; i < myRemapMenuItems; ++i)
|
||||
{
|
||||
Event::Type event = ourRemapMenu[i].event;
|
||||
ourRemapMenu[i].key = "None";
|
||||
|
@ -643,7 +605,17 @@ void FrameBuffer::loadRemapMenu()
|
|||
}
|
||||
|
||||
if(key != "")
|
||||
ourRemapMenu[i].key = key;
|
||||
{
|
||||
// 19 is the max size of the event names, and 2 is for the space in between
|
||||
// (this could probably be cleaner ...)
|
||||
uInt32 len = myMaxColumns - 19 - 2;
|
||||
if(key.length() > len)
|
||||
{
|
||||
ourRemapMenu[i].key = key.substr(0, len - 3) + "...";
|
||||
}
|
||||
else
|
||||
ourRemapMenu[i].key = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.3 2003-11-06 22:22:32 stephena Exp $
|
||||
// $Id: FrameBuffer.hxx,v 1.4 2003-11-09 23:53:19 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef FRAMEBUFFER_HXX
|
||||
|
@ -35,7 +35,7 @@ class Console;
|
|||
can be changed.
|
||||
|
||||
@author Stephen Anthony
|
||||
@version $Id: FrameBuffer.hxx,v 1.3 2003-11-06 22:22:32 stephena Exp $
|
||||
@version $Id: FrameBuffer.hxx,v 1.4 2003-11-09 23:53:19 stephena Exp $
|
||||
*/
|
||||
class FrameBuffer
|
||||
{
|
||||
|
@ -147,10 +147,8 @@ class FrameBuffer
|
|||
@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) = 0;
|
||||
virtual void drawBoundedBox(uInt32 x, uInt32 y, uInt32 w, uInt32 h) = 0;
|
||||
|
||||
/**
|
||||
This routine should be called to draw text at the specified coordinates.
|
||||
|
@ -158,9 +156,8 @@ class FrameBuffer
|
|||
@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;
|
||||
virtual void drawText(uInt32 x, uInt32 y, const string& message) = 0;
|
||||
|
||||
/**
|
||||
This routine should be called to draw character 'c' at the specified coordinates.
|
||||
|
@ -168,9 +165,8 @@ class FrameBuffer
|
|||
@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;
|
||||
virtual void drawChar(uInt32 x, uInt32 y, uInt32 c) = 0;
|
||||
|
||||
/**
|
||||
This routine is called before any drawing is done (per-frame).
|
||||
|
@ -208,6 +204,9 @@ class FrameBuffer
|
|||
// Table of bitmapped fonts.
|
||||
static const uInt8 ourFontData[2048];
|
||||
|
||||
// Holds the foreground and background color table indices
|
||||
uInt8 myFGColor, myBGColor;
|
||||
|
||||
private:
|
||||
// Enumeration representing the different types of user interface widgets
|
||||
enum Widget { W_NONE, MAIN_MENU, REMAP_MENU, INFO_MENU };
|
||||
|
@ -234,17 +233,11 @@ class FrameBuffer
|
|||
// Draw the info menu
|
||||
void drawInfoMenu();
|
||||
|
||||
// Move the cursor up 1 line, possibly scrolling the list of items
|
||||
void moveCursorUp();
|
||||
// Move the cursor up 'amt' lines, possibly scrolling the list of items
|
||||
void moveCursorUp(uInt32 amt);
|
||||
|
||||
// Move the cursor down 1 line, possibly scrolling the list of items
|
||||
void moveCursorDown();
|
||||
|
||||
// Move the list up 1 page and put the cursor at the top
|
||||
void movePageUp();
|
||||
|
||||
// Move the list down 1 page and put the cursor at the top
|
||||
void movePageDown();
|
||||
// Move the cursor down 'amt' lines, possibly scrolling the list of items
|
||||
void moveCursorDown(uInt32 amt);
|
||||
|
||||
// scan the mapping arrays and update the remap menu
|
||||
void loadRemapMenu();
|
||||
|
@ -287,14 +280,17 @@ class FrameBuffer
|
|||
bool theMenuChangedIndicator;
|
||||
|
||||
// The maximum number of vertical lines of text that can be onscreen
|
||||
uInt32 myMaxLines;
|
||||
Int32 myMaxRows;
|
||||
|
||||
// The maximum number of characters of text in a row
|
||||
Int32 myMaxColumns;
|
||||
|
||||
// Keep track of current selected main menu item
|
||||
uInt32 myMainMenuIndex, myMainMenuItems;
|
||||
|
||||
// Keep track of current selected remap menu item
|
||||
uInt32 myRemapMenuIndex, myRemapMenuLowIndex, myRemapMenuHighIndex;
|
||||
uInt32 myRemapMenuItems, myRemapMenuMaxLines;
|
||||
Int32 myRemapMenuIndex, myRemapMenuLowIndex, myRemapMenuHighIndex;
|
||||
Int32 myRemapMenuItems, myRemapMenuMaxLines;
|
||||
|
||||
// Message timer
|
||||
Int32 myMessageTime;
|
||||
|
@ -303,7 +299,7 @@ class FrameBuffer
|
|||
string myMessageText;
|
||||
|
||||
// The width of the information menu, determined by the longest string
|
||||
uInt32 myInfoMenuWidth;
|
||||
Int32 myInfoMenuWidth;
|
||||
|
||||
// Holds information about the current selected ROM image
|
||||
string ourPropertiesInfo[9];
|
||||
|
|
|
@ -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: FrameBufferGL.cxx,v 1.1 2003-11-06 22:22:32 stephena Exp $
|
||||
// $Id: FrameBufferGL.cxx,v 1.2 2003-11-09 23:53:20 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <SDL.h>
|
||||
|
@ -22,20 +22,14 @@
|
|||
|
||||
#include "Console.hxx"
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "FrameBufferSDL.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)
|
||||
: myTexture(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -46,6 +40,61 @@ FrameBufferGL::~FrameBufferGL()
|
|||
SDL_FreeSurface(myTexture);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
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;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FrameBufferGL::init()
|
||||
{
|
||||
|
@ -194,6 +243,7 @@ void FrameBufferGL::drawMediaSource() // FIXME - maybe less copying can be done?
|
|||
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);
|
||||
glColor3f(0.0, 0.0, 0.0);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(myTexCoord[0], myTexCoord[1]); glVertex2i(0, 0);
|
||||
|
@ -216,214 +266,14 @@ void FrameBufferGL::postFrameUpdate()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
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)
|
||||
void FrameBufferGL::drawBoundedBox(uInt32 x, uInt32 y, uInt32 w, uInt32 h)
|
||||
{
|
||||
// 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);
|
||||
|
@ -435,8 +285,7 @@ void FrameBufferGL::drawBoundedBox(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferGL::drawText(uInt32 xorig, uInt32 yorig,
|
||||
const string& message, uInt8 fg)
|
||||
void FrameBufferGL::drawText(uInt32 xorig, uInt32 yorig, const string& message)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, myFontTextureID);
|
||||
glEnable(GL_BLEND);
|
||||
|
@ -459,7 +308,7 @@ void FrameBufferGL::drawText(uInt32 xorig, uInt32 yorig,
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferGL::drawChar(uInt32 x, uInt32 y, uInt32 c, uInt8 fg)
|
||||
void FrameBufferGL::drawChar(uInt32 x, uInt32 y, uInt32 c)
|
||||
{
|
||||
if(c >= 256 )
|
||||
return;
|
||||
|
|
|
@ -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: FrameBufferGL.hxx,v 1.1 2003-11-06 22:22:32 stephena Exp $
|
||||
// $Id: FrameBufferGL.hxx,v 1.2 2003-11-09 23:53:20 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef FRAMEBUFFER_GL_HXX
|
||||
|
@ -24,12 +24,19 @@
|
|||
#include <SDL_syswm.h>
|
||||
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "FrameBufferSDL.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
class Console;
|
||||
class MediaSource;
|
||||
|
||||
class FrameBufferGL : public FrameBuffer
|
||||
/**
|
||||
This class implements an SDL OpenGL framebuffer.
|
||||
|
||||
@author Stephen Anthony
|
||||
@version $Id: FrameBufferGL.hxx,v 1.2 2003-11-09 23:53:20 stephena Exp $
|
||||
*/
|
||||
class FrameBufferGL : public FrameBufferSDL
|
||||
{
|
||||
public:
|
||||
/**
|
||||
|
@ -42,6 +49,24 @@ class FrameBufferGL : public FrameBuffer
|
|||
*/
|
||||
virtual ~FrameBufferGL();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// The following methods are derived from FrameBufferSDL.hxx
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
This routine is called whenever the screen needs to be recreated.
|
||||
It updates the global screen variable.
|
||||
*/
|
||||
virtual bool createScreen();
|
||||
|
||||
/**
|
||||
Set up the palette for a screen of any depth > 8.
|
||||
Scales the palette by 'shade'.
|
||||
*/
|
||||
virtual void setupPalette(float shade);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// The following methods are derived from FrameBuffer.hxx
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
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,
|
||||
|
@ -63,10 +88,8 @@ class FrameBufferGL : public FrameBuffer
|
|||
@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);
|
||||
virtual void drawBoundedBox(uInt32 x, uInt32 y, uInt32 w, uInt32 h);
|
||||
|
||||
/**
|
||||
This routine should be called to draw text at the specified coordinates.
|
||||
|
@ -74,9 +97,8 @@ class FrameBufferGL : public FrameBuffer
|
|||
@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);
|
||||
virtual void drawText(uInt32 x, uInt32 y, const string& message);
|
||||
|
||||
/**
|
||||
This routine should be called to draw character 'c' at the specified coordinates.
|
||||
|
@ -84,9 +106,8 @@ class FrameBufferGL : public FrameBuffer
|
|||
@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);
|
||||
virtual void drawChar(uInt32 x, uInt32 y, uInt32 c);
|
||||
|
||||
/**
|
||||
This routine is called before any drawing is done (per-frame).
|
||||
|
@ -98,67 +119,7 @@ class FrameBufferGL : public FrameBuffer
|
|||
*/
|
||||
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();
|
||||
|
||||
|
@ -171,9 +132,6 @@ class FrameBufferGL : public FrameBuffer
|
|||
}
|
||||
|
||||
private:
|
||||
// The SDL video buffer
|
||||
SDL_Surface* myScreen;
|
||||
|
||||
// The main texture buffer
|
||||
SDL_Surface* myTexture;
|
||||
|
||||
|
@ -197,36 +155,6 @@ class FrameBufferGL : public FrameBuffer
|
|||
|
||||
// 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
|
||||
|
|
|
@ -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: FrameBufferSDL.cxx,v 1.2 2003-11-06 22:22:32 stephena Exp $
|
||||
// $Id: FrameBufferSDL.cxx,v 1.3 2003-11-09 23:53:20 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <SDL.h>
|
||||
|
@ -31,7 +31,6 @@ FrameBufferSDL::FrameBufferSDL()
|
|||
: x11Available(false),
|
||||
theZoomLevel(1),
|
||||
theMaxZoomLevel(1),
|
||||
isCentered(false),
|
||||
theGrabMouseIndicator(false),
|
||||
theHideCursorIndicator(false),
|
||||
isFullscreen(false)
|
||||
|
@ -41,299 +40,6 @@ FrameBufferSDL::FrameBufferSDL()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
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;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -352,6 +58,12 @@ void FrameBufferSDL::pause(bool status)
|
|||
void FrameBufferSDL::toggleFullscreen()
|
||||
{
|
||||
isFullscreen = !isFullscreen;
|
||||
|
||||
// Update the settings
|
||||
ostringstream tmp;
|
||||
tmp << isFullscreen;
|
||||
myConsole->settings().set("fullscreen", tmp.str());
|
||||
|
||||
if(isFullscreen)
|
||||
mySDLFlags |= SDL_FULLSCREEN;
|
||||
else
|
||||
|
@ -369,9 +81,6 @@ void FrameBufferSDL::toggleFullscreen()
|
|||
{
|
||||
grabMouse(theGrabMouseIndicator);
|
||||
showCursor(!theHideCursorIndicator);
|
||||
|
||||
if(myConsole->settings().getBool("center"))
|
||||
centerScreen();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -409,13 +118,7 @@ void FrameBufferSDL::resize(int mode)
|
|||
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
|
||||
// Update the settings
|
||||
ostringstream tmp;
|
||||
tmp << theZoomLevel;
|
||||
myConsole->settings().set("zoom", tmp.str());
|
||||
|
@ -431,6 +134,11 @@ void FrameBufferSDL::showCursor(bool show)
|
|||
SDL_ShowCursor(SDL_ENABLE);
|
||||
else
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
|
||||
// Update the settings
|
||||
ostringstream tmp;
|
||||
tmp << !show;
|
||||
myConsole->settings().set("hidecursor", tmp.str());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -443,35 +151,11 @@ void FrameBufferSDL::grabMouse(bool 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;
|
||||
// Update the settings
|
||||
ostringstream tmp;
|
||||
tmp << grab;
|
||||
myConsole->settings().set("grabmouse", tmp.str());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -480,6 +164,7 @@ uInt32 FrameBufferSDL::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;
|
||||
|
@ -507,160 +192,7 @@ uInt32 FrameBufferSDL::maxWindowSizeForScreen()
|
|||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
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;
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -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: FrameBufferSDL.hxx,v 1.2 2003-11-06 22:22:32 stephena Exp $
|
||||
// $Id: FrameBufferSDL.hxx,v 1.3 2003-11-09 23:53:20 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef FRAMEBUFFER_SDL_HXX
|
||||
|
@ -25,15 +25,22 @@
|
|||
#include "FrameBuffer.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
class Console;
|
||||
class MediaSource;
|
||||
class RectList;
|
||||
/**
|
||||
This class is a base class for the SDL framebuffer and is derived from
|
||||
the core FrameBuffer class.
|
||||
|
||||
It defines all common code shared between the software
|
||||
and OpenGL video modes, as well as required methods defined in
|
||||
the core FrameBuffer.
|
||||
|
||||
@author Stephen Anthony
|
||||
@version $Id: FrameBufferSDL.hxx,v 1.3 2003-11-09 23:53:20 stephena Exp $
|
||||
*/
|
||||
class FrameBufferSDL : public FrameBuffer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Creates a new SDL software framebuffer
|
||||
Creates a new SDL framebuffer
|
||||
*/
|
||||
FrameBufferSDL();
|
||||
|
||||
|
@ -42,68 +49,6 @@ class FrameBufferSDL : public FrameBuffer
|
|||
*/
|
||||
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
|
||||
|
@ -141,41 +86,46 @@ class FrameBufferSDL : public FrameBuffer
|
|||
*/
|
||||
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();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// The following methods are derived from FrameBuffer.hxx
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
This routine is called when the emulation has been paused.
|
||||
|
||||
@param status Toggle pause based on status
|
||||
*/
|
||||
void pause(bool status);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// The following methods must be defined in child classes
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
This routine is called whenever the screen needs to be recreated.
|
||||
It updates the global screen variable.
|
||||
*/
|
||||
virtual bool createScreen() = 0;
|
||||
|
||||
/**
|
||||
Set up the palette for a screen of any depth > 8.
|
||||
Scales the palette by 'shade'.
|
||||
*/
|
||||
void setupPalette(float shade);
|
||||
virtual void setupPalette(float shade) = 0;
|
||||
|
||||
private:
|
||||
protected:
|
||||
// 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];
|
||||
Uint32 myPalette[256];
|
||||
|
||||
// Used to get window-manager specifics
|
||||
SDL_SysWMinfo myWMInfo;
|
||||
|
@ -189,9 +139,6 @@ class FrameBufferSDL : public FrameBuffer
|
|||
// 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;
|
||||
|
||||
|
@ -202,25 +149,4 @@ class FrameBufferSDL : public FrameBuffer
|
|||
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
|
||||
|
|
|
@ -0,0 +1,475 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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: FrameBufferSoft.cxx,v 1.1 2003-11-09 23:53:20 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_syswm.h>
|
||||
#include <sstream>
|
||||
|
||||
#include "Console.hxx"
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "FrameBufferSDL.hxx"
|
||||
#include "FrameBufferSoft.hxx"
|
||||
#include "MediaSrc.hxx"
|
||||
#include "Settings.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FrameBufferSoft::FrameBufferSoft()
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FrameBufferSoft::~FrameBufferSoft()
|
||||
{
|
||||
if(myRectList)
|
||||
delete myRectList;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FrameBufferSoft::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 FrameBufferSoft::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:
|
||||
myPalette[i] = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
|
||||
break;
|
||||
|
||||
case 16:
|
||||
myPalette[i] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
|
||||
break;
|
||||
|
||||
case 24:
|
||||
case 32:
|
||||
myPalette[i] = (r << 16) | (g << 8) | b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
theRedrawEntireFrameIndicator = true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FrameBufferSoft::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);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSoft::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, myPalette[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, myPalette[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, myPalette[active.color]);
|
||||
}
|
||||
|
||||
// The frame doesn't need to be completely redrawn anymore
|
||||
theRedrawEntireFrameIndicator = false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSoft::preFrameUpdate()
|
||||
{
|
||||
// Start a new rectlist on each display update
|
||||
myRectList->start();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSoft::postFrameUpdate()
|
||||
{
|
||||
// Now update all the rectangles at once
|
||||
SDL_UpdateRects(myScreen, myRectList->numRects(), myRectList->rects());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSoft::drawBoundedBox(uInt32 x, uInt32 y, uInt32 w, uInt32 h)
|
||||
{
|
||||
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, myPalette[myBGColor]);
|
||||
|
||||
// Now draw the bounding sides
|
||||
tmp.x = x;
|
||||
tmp.y = y;
|
||||
tmp.w = w;
|
||||
tmp.h = theZoomLevel;
|
||||
SDL_FillRect(myScreen, &tmp, myPalette[myFGColor]); // top
|
||||
|
||||
tmp.x = x;
|
||||
tmp.y = y + h - theZoomLevel;
|
||||
tmp.w = w;
|
||||
tmp.h = theZoomLevel;
|
||||
SDL_FillRect(myScreen, &tmp, myPalette[myFGColor]); // bottom
|
||||
|
||||
tmp.x = x;
|
||||
tmp.y = y;
|
||||
tmp.w = theZoomLevel;
|
||||
tmp.h = h;
|
||||
SDL_FillRect(myScreen, &tmp, myPalette[myFGColor]); // left
|
||||
|
||||
tmp.x = x + w - theZoomLevel;
|
||||
tmp.y = y;
|
||||
tmp.w = theZoomLevel;
|
||||
tmp.h = h;
|
||||
SDL_FillRect(myScreen, &tmp, myPalette[myFGColor]); // right
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSoft::drawText(uInt32 xorig, uInt32 yorig, const string& message)
|
||||
{
|
||||
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)
|
||||
{
|
||||
tmp.x = ((x<<3) + z + xorig) * theZoomLevel;
|
||||
tmp.y = (y + yorig) * theZoomLevel;
|
||||
tmp.w = tmp.h = theZoomLevel;
|
||||
SDL_FillRect(myScreen, &tmp, myPalette[myFGColor]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSoft::drawChar(uInt32 xorig, uInt32 yorig, uInt32 c)
|
||||
{
|
||||
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)
|
||||
{
|
||||
tmp.x = (z + xorig) * theZoomLevel;
|
||||
tmp.y = (y + yorig) * theZoomLevel;
|
||||
tmp.w = tmp.h = theZoomLevel;
|
||||
SDL_FillRect(myScreen, &tmp, myPalette[myFGColor]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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: FrameBufferSoft.hxx,v 1.1 2003-11-09 23:53:20 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef FRAMEBUFFER_SOFT_HXX
|
||||
#define FRAMEBUFFER_SOFT_HXX
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_syswm.h>
|
||||
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "FrameBufferSDL.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
class Console;
|
||||
class MediaSource;
|
||||
class RectList;
|
||||
|
||||
|
||||
/**
|
||||
This class implements an SDL software framebuffer.
|
||||
|
||||
@author Stephen Anthony
|
||||
@version $Id: FrameBufferSoft.hxx,v 1.1 2003-11-09 23:53:20 stephena Exp $
|
||||
*/
|
||||
class FrameBufferSoft : public FrameBufferSDL
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Creates a new SDL software framebuffer
|
||||
*/
|
||||
FrameBufferSoft();
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
virtual ~FrameBufferSoft();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// The following methods are derived from FrameBufferSDL.hxx
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
This routine is called whenever the screen needs to be recreated.
|
||||
It updates the global screen variable.
|
||||
*/
|
||||
virtual bool createScreen();
|
||||
|
||||
/**
|
||||
Set up the palette for a screen of any depth > 8.
|
||||
Scales the palette by 'shade'.
|
||||
*/
|
||||
virtual void setupPalette(float shade);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// The following methods are derived from FrameBuffer.hxx
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
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
|
||||
*/
|
||||
virtual void drawBoundedBox(uInt32 x, uInt32 y, uInt32 w, uInt32 h);
|
||||
|
||||
/**
|
||||
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
|
||||
*/
|
||||
virtual void drawText(uInt32 x, uInt32 y, const string& message);
|
||||
|
||||
/**
|
||||
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
|
||||
*/
|
||||
virtual void drawChar(uInt32 x, uInt32 y, uInt32 c);
|
||||
|
||||
/**
|
||||
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();
|
||||
|
||||
private:
|
||||
// Used in the dirty update of the SDL surface
|
||||
RectList* myRectList;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
*/
|
||||
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
|
|
@ -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: SettingsUNIX.cxx,v 1.2 2003-11-06 22:22:32 stephena Exp $
|
||||
// $Id: SettingsUNIX.cxx,v 1.3 2003-11-09 23:53:20 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <cstdlib>
|
||||
|
@ -62,20 +62,21 @@ SettingsUNIX::SettingsUNIX()
|
|||
myStateFile = "";
|
||||
|
||||
// Now create UNIX specific settings
|
||||
set("video", "soft");
|
||||
#ifdef DISPLAY_OPENGL
|
||||
set("gl_filter", "nearest");
|
||||
#endif
|
||||
set("sound", "oss");
|
||||
set("fullscreen", "false");
|
||||
set("grabmouse", "false");
|
||||
set("hidecursor", "false");
|
||||
set("volume", "-1");
|
||||
set("accurate", "true");
|
||||
#ifdef SNAPSHOT_SUPPORT
|
||||
set("ssname", "romname");
|
||||
set("ssdir", "./");
|
||||
set("ssingle", "false");
|
||||
#endif
|
||||
set("fullscreen", "false");
|
||||
set("grabmouse", "false");
|
||||
set("hidecursor", "false");
|
||||
set("accurate", "true");
|
||||
set("volume", "-1");
|
||||
set("sound", "oss");
|
||||
set("joyleft", "0");
|
||||
set("joyright", "1");
|
||||
}
|
||||
|
@ -93,22 +94,26 @@ void SettingsUNIX::usage(string& message)
|
|||
<< endl
|
||||
<< "Valid options are:" << endl
|
||||
<< endl
|
||||
<< " -video <type> Type is one of the following:\n"
|
||||
<< " soft SDL software mode\n"
|
||||
#ifdef DISPLAY_OPENGL
|
||||
<< " gl SDL OpenGL mode\n"
|
||||
<< endl
|
||||
<< " -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"
|
||||
<< " -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"
|
||||
<< " alsa ALSA version 0.9 driver\n"
|
||||
#endif
|
||||
#ifdef SOUND_OSS
|
||||
<< " oss Open Sound System driver\n"
|
||||
<< " oss Open Sound System driver\n"
|
||||
#endif
|
||||
#ifdef SOUND_SDL
|
||||
<< " SDL Native SDL driver\n"
|
||||
<< " sdl Native SDL driver\n"
|
||||
#endif
|
||||
<< endl
|
||||
<< " -framerate <number> Display the given number of frames per second\n"
|
||||
|
@ -116,7 +121,6 @@ void SettingsUNIX::usage(string& message)
|
|||
<< " -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 HAVE_JOYSTICK
|
||||
<< " -paddle <0|1|2|3|real> Indicates which paddle the mouse should emulate\n"
|
||||
|
|
|
@ -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.57 2003-11-06 22:22:32 stephena Exp $
|
||||
// $Id: mainSDL.cxx,v 1.58 2003-11-09 23:53:20 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <fstream>
|
||||
|
@ -35,18 +35,14 @@
|
|||
#include "StellaEvent.hxx"
|
||||
#include "EventHandler.hxx"
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "FrameBufferSDL.hxx"
|
||||
#include "FrameBufferSoft.hxx"
|
||||
#include "PropsSet.hxx"
|
||||
#include "Sound.hxx"
|
||||
#include "Settings.hxx"
|
||||
|
||||
#ifdef DISPLAY_OPENGL
|
||||
#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
|
||||
|
||||
#ifdef SOUND_ALSA
|
||||
|
@ -83,6 +79,9 @@ static bool setupProperties(PropertiesSet& set);
|
|||
// Pointer to the console object or the null pointer
|
||||
static Console* theConsole = (Console*) NULL;
|
||||
|
||||
// Pointer to the display object or the null pointer
|
||||
static FrameBufferSDL* theDisplay = (FrameBufferSDL*) NULL;
|
||||
|
||||
// Pointer to the sound object or the null pointer
|
||||
static Sound* theSound = (Sound*) NULL;
|
||||
|
||||
|
@ -704,15 +703,27 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
|
||||
// Create an SDL window
|
||||
string videodriver = theSettings->getString("video");
|
||||
if(videodriver == "soft")
|
||||
{
|
||||
theDisplay = new FrameBufferSoft();
|
||||
if(theShowInfoFlag)
|
||||
cout << "Using software mode for video.\n";
|
||||
}
|
||||
#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";
|
||||
else if(videodriver == "gl")
|
||||
{
|
||||
theDisplay = new FrameBufferGL();
|
||||
if(theShowInfoFlag)
|
||||
cout << "Using OpenGL mode for video.\n";
|
||||
}
|
||||
#endif
|
||||
else // a driver that doesn't exist was requested, so use software mode
|
||||
{
|
||||
theDisplay = new FrameBufferSoft();
|
||||
if(theShowInfoFlag)
|
||||
cout << "Using software mode for video.\n";
|
||||
}
|
||||
|
||||
if(!theDisplay)
|
||||
{
|
||||
|
@ -722,8 +733,8 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
|
||||
// Create a sound object for playing audio
|
||||
string driver = theSettings->getString("sound");
|
||||
if(driver == "0")
|
||||
string sounddriver = theSettings->getString("sound");
|
||||
if(sounddriver == "0")
|
||||
{
|
||||
// even if sound has been disabled, we still need a sound object
|
||||
theSound = new Sound();
|
||||
|
@ -731,7 +742,7 @@ int main(int argc, char* argv[])
|
|||
cout << "Sound disabled.\n";
|
||||
}
|
||||
#ifdef SOUND_ALSA
|
||||
else if(driver == "alsa")
|
||||
else if(sounddriver == "alsa")
|
||||
{
|
||||
theSound = new SoundALSA();
|
||||
if(theShowInfoFlag)
|
||||
|
@ -739,7 +750,7 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
#endif
|
||||
#ifdef SOUND_OSS
|
||||
else if(driver == "oss")
|
||||
else if(sounddriver == "oss")
|
||||
{
|
||||
theSound = new SoundOSS();
|
||||
if(theShowInfoFlag)
|
||||
|
@ -747,7 +758,7 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
#endif
|
||||
#ifdef SOUND_SDL
|
||||
else if(driver == "sdl")
|
||||
else if(sounddriver == "sdl")
|
||||
{
|
||||
theSound = new SoundSDL();
|
||||
if(theShowInfoFlag)
|
||||
|
@ -756,7 +767,7 @@ int main(int argc, char* argv[])
|
|||
#endif
|
||||
else // a driver that doesn't exist was requested, so disable sound
|
||||
{
|
||||
cerr << "ERROR: Sound support for " << driver << " not available.\n";
|
||||
cerr << "ERROR: Sound support for " << sounddriver << " not available.\n";
|
||||
theSound = new Sound();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue