diff --git a/stella/src/common/FrameBufferGL.cxx b/stella/src/common/FrameBufferGL.cxx index 1ac0af4e3..a6fde687b 100644 --- a/stella/src/common/FrameBufferGL.cxx +++ b/stella/src/common/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: FrameBufferGL.cxx,v 1.112 2008-12-10 18:11:21 stephena Exp $ +// $Id: FrameBufferGL.cxx,v 1.113 2008-12-12 15:51:06 stephena Exp $ //============================================================================ #ifdef DISPLAY_OPENGL @@ -356,6 +356,10 @@ cerr << "dimensions: " << endl myBaseSurface = new FBSurfaceGL(*this, baseWidth, baseHeight, mode.image_w, mode.image_h); + // Old textures currently in use by various UI items need to be + // refreshed as well (only seems to be required for OSX) + reloadSurfaces(); + // Make sure any old parts of the screen are erased p_glClear(GL_COLOR_BUFFER_BIT); SDL_GL_SwapBuffers(); @@ -528,6 +532,8 @@ FBSurfaceGL::FBSurfaceGL(FrameBufferGL& buffer, uInt32 baseWidth, uInt32 baseHeight, uInt32 scaleWidth, uInt32 scaleHeight) : myFB(buffer), + myTexture(NULL), + myTexID(0), myXOrig(0), myYOrig(0), myWidth(scaleWidth), @@ -558,9 +564,6 @@ cerr << " FBSurfaceGL::FBSurfaceGL: w = " << baseWidth << ", h = " << baseHeigh // Based on experimentation, the following is the fastest 16-bit // format for OpenGL (on all platforms) - // TODO - make sure this is endian-clean - GLenum tex_intformat; - tex_intformat = GL_RGB5; myTexFormat = GL_BGRA; myTexType = GL_UNSIGNED_SHORT_1_5_5_5_REV; myTexture = SDL_CreateRGBSurface(SDL_SWSURFACE, @@ -582,41 +585,15 @@ cerr << " FBSurfaceGL::FBSurfaceGL: w = " << baseWidth << ", h = " << baseHeigh break; } -/* - // Create an OpenGL texture from the SDL texture - const string& filter = myOSystem->settings().getString("gl_filter"); - if(filter == "linear") - { - myBuffer.filter = GL_LINEAR; - myFilterParamName = "GL_LINEAR"; - } - else if(filter == "nearest") - { - myBuffer.filter = GL_NEAREST; - myFilterParamName = "GL_NEAREST"; - } -*/ - - p_glGenTextures(1, &myTexID); - p_glBindTexture(myTexTarget, myTexID); - p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -// p_glTexParameteri(myTexTarget, GL_TEXTURE_MIN_FILTER, myBuffer.filter); -// p_glTexParameteri(myTexTarget, GL_TEXTURE_MAG_FILTER, myBuffer.filter); - p_glTexParameteri(myTexTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - p_glTexParameteri(myTexTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - // Finally, create the texture in the most optimal format - p_glTexImage2D(myTexTarget, 0, tex_intformat, - myTexWidth, myTexHeight, 0, - myTexFormat, myTexType, myTexture->pixels); - - p_glEnable(myTexTarget); + // Associate the SDL surface with a GL texture object + reload(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBSurfaceGL::~FBSurfaceGL() { +cerr << " FBSurfaceGL::~FBSurfaceGL(): " << this << endl; + if(myTexture) SDL_FreeSurface(myTexture); @@ -816,6 +793,53 @@ void FBSurfaceGL::update() } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FBSurfaceGL::reload() +{ + // This does a 'soft' reset of the surface + // It seems that on some system (notably, OSX), creating a new SDL window + // destroys the GL context, requiring a reload of all textures + // However, destroying the entire FBSurfaceGL object is wasteful, since + // it will also regenerate SDL software surfaces (which are not required + // to be regenerated) + // Basically, all that needs to be done is to re-call glTexImage2D with a + // new texture ID, so that's what we do here + +/* + // Create an OpenGL texture from the SDL texture + const string& filter = myOSystem->settings().getString("gl_filter"); + if(filter == "linear") + { + myBuffer.filter = GL_LINEAR; + myFilterParamName = "GL_LINEAR"; + } + else if(filter == "nearest") + { + myBuffer.filter = GL_NEAREST; + myFilterParamName = "GL_NEAREST"; + } +*/ + + p_glDeleteTextures(1, &myTexID); + p_glGenTextures(1, &myTexID); + p_glBindTexture(myTexTarget, myTexID); + p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + p_glTexParameteri(myTexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +// p_glTexParameteri(myTexTarget, GL_TEXTURE_MIN_FILTER, myBuffer.filter); +// p_glTexParameteri(myTexTarget, GL_TEXTURE_MAG_FILTER, myBuffer.filter); + p_glTexParameteri(myTexTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + p_glTexParameteri(myTexTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + // Finally, create the texture in the most optimal format + p_glTexImage2D(myTexTarget, 0, GL_RGB5, + myTexWidth, myTexHeight, 0, + myTexFormat, myTexType, myTexture->pixels); + + p_glEnable(myTexTarget); + +cerr << " ==> FBSurfaceGL::reload(): myTexID = " << myTexID << endl; +} + #if 0 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GUI::Surface* FrameBufferGL::createSurface(int width, int height) const diff --git a/stella/src/common/FrameBufferGL.hxx b/stella/src/common/FrameBufferGL.hxx index 1394829e1..c926dcc8c 100644 --- a/stella/src/common/FrameBufferGL.hxx +++ b/stella/src/common/FrameBufferGL.hxx @@ -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.60 2008-12-10 18:11:21 stephena Exp $ +// $Id: FrameBufferGL.hxx,v 1.61 2008-12-12 15:51:06 stephena Exp $ //============================================================================ #ifndef FRAMEBUFFER_GL_HXX @@ -35,7 +35,7 @@ class FBSurfaceGL; This class implements an SDL OpenGL framebuffer. @author Stephen Anthony - @version $Id: FrameBufferGL.hxx,v 1.60 2008-12-10 18:11:21 stephena Exp $ + @version $Id: FrameBufferGL.hxx,v 1.61 2008-12-12 15:51:06 stephena Exp $ */ class FrameBufferGL : public FrameBuffer { @@ -83,16 +83,6 @@ class FrameBufferGL : public FrameBuffer */ BufferType type() const { return kGLBuffer; } - /** - This method is called to create a surface compatible with the one - currently in use, but having the given dimensions. - - @param w The requested width of the new surface. - @param h The requested height of the new surface. - @param useBase Use the base surface instead of creating a new one - */ - FBSurface* createSurface(int w, int h, bool useBase = false) const; - /** This method is called to get the specified scanline data. @@ -125,6 +115,16 @@ class FrameBufferGL : public FrameBuffer */ bool setVidMode(VideoMode& mode); + /** + This method is called to create a surface compatible with the one + currently in use, but having the given dimensions. + + @param w The requested width of the new surface. + @param h The requested height of the new surface. + @param useBase Use the base surface instead of creating a new one + */ + FBSurface* createSurface(int w, int h, bool useBase = false) const; + /** Switches between the two filtering options in OpenGL. Currently, these are GL_NEAREST and GL_LINEAR. @@ -201,7 +201,7 @@ class FrameBufferGL : public FrameBuffer A surface suitable for OpenGL rendering mode. @author Stephen Anthony - @version $Id: FrameBufferGL.hxx,v 1.60 2008-12-10 18:11:21 stephena Exp $ + @version $Id: FrameBufferGL.hxx,v 1.61 2008-12-12 15:51:06 stephena Exp $ */ class FBSurfaceGL : public FBSurface { @@ -227,6 +227,7 @@ class FBSurfaceGL : public FBSurface void setHeight(uInt32 h); void translateCoords(Int32& x, Int32& y) const; void update(); + void reload(); private: inline void* pixels() const { return myTexture->pixels; } diff --git a/stella/src/common/FrameBufferSoft.hxx b/stella/src/common/FrameBufferSoft.hxx index 9a1f53bda..9a5eca6ca 100644 --- a/stella/src/common/FrameBufferSoft.hxx +++ b/stella/src/common/FrameBufferSoft.hxx @@ -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: FrameBufferSoft.hxx,v 1.55 2008-11-02 16:46:05 stephena Exp $ +// $Id: FrameBufferSoft.hxx,v 1.56 2008-12-12 15:51:06 stephena Exp $ //============================================================================ #ifndef FRAMEBUFFER_SOFT_HXX @@ -32,7 +32,7 @@ class RectList; This class implements an SDL software framebuffer. @author Stephen Anthony - @version $Id: FrameBufferSoft.hxx,v 1.55 2008-11-02 16:46:05 stephena Exp $ + @version $Id: FrameBufferSoft.hxx,v 1.56 2008-12-12 15:51:06 stephena Exp $ */ class FrameBufferSoft : public FrameBuffer { @@ -72,16 +72,6 @@ class FrameBufferSoft : public FrameBuffer */ BufferType type() const { return kSoftBuffer; } - /** - This method is called to create a surface compatible with the one - currently in use, but having the given dimensions. - - @param w The requested width of the new surface. - @param h The requested height of the new surface. - @param useBase Use the base surface instead of creating a new one - */ - FBSurface* createSurface(int w, int h, bool useBase = false) const; - /** This method is called to get the specified scanline data. @@ -114,6 +104,16 @@ class FrameBufferSoft : public FrameBuffer */ bool setVidMode(VideoMode& mode); + /** + This method is called to create a surface compatible with the one + currently in use, but having the given dimensions. + + @param w The requested width of the new surface. + @param h The requested height of the new surface. + @param useBase Use the base surface instead of creating a new one + */ + FBSurface* createSurface(int w, int h, bool useBase = false) const; + /** Switches between the filtering options in software mode. Currently, none exist. @@ -172,7 +172,7 @@ class FrameBufferSoft : public FrameBuffer A surface suitable for software rendering mode. @author Stephen Anthony - @version $Id: FrameBufferSoft.hxx,v 1.55 2008-11-02 16:46:05 stephena Exp $ + @version $Id: FrameBufferSoft.hxx,v 1.56 2008-12-12 15:51:06 stephena Exp $ */ class FBSurfaceSoft : public FBSurface { @@ -195,6 +195,7 @@ class FBSurfaceSoft : public FBSurface void setHeight(uInt32 h); void translateCoords(Int32& x, Int32& y) const; void update(); + void reload() { } // Not required for software mode private: void recalc(); diff --git a/stella/src/emucore/FrameBuffer.cxx b/stella/src/emucore/FrameBuffer.cxx index dceda05a3..de1236ec1 100644 --- a/stella/src/emucore/FrameBuffer.cxx +++ b/stella/src/emucore/FrameBuffer.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.142 2008-12-08 18:56:54 stephena Exp $ +// $Id: FrameBuffer.cxx,v 1.143 2008-12-12 15:51:07 stephena Exp $ //============================================================================ #include @@ -46,17 +46,19 @@ FrameBuffer::FrameBuffer(OSystem* osystem) myUsePhosphor(false), myPhosphorBlend(77), myInitializedCount(0), - myPausedCount(0) + myPausedCount(0), + mySurfaceCount(0) { - myMsg.surface = myStatsMsg.surface = 0; - myMsg.enabled = myStatsMsg.enabled = false; + myMsg.surface = myStatsMsg.surface = 0; + myMsg.surfaceID = myStatsMsg.surfaceID = -1; + myMsg.enabled = myStatsMsg.enabled = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameBuffer::~FrameBuffer(void) { - delete myMsg.surface; - delete myStatsMsg.surface; + freeSurface(myMsg.surfaceID); + freeSurface(myStatsMsg.surfaceID); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -126,10 +128,16 @@ cerr << " <== FrameBuffer::initialize: w = " << width << ", h = " << height << e myStatsMsg.color = kBtnTextColor; myStatsMsg.w = myOSystem->consoleFont().getStringWidth("000 LINES %00.00 FPS"); myStatsMsg.h = myOSystem->consoleFont().getFontHeight(); - if(!myStatsMsg.surface) - myStatsMsg.surface = createSurface(myStatsMsg.w, myStatsMsg.h); + if(myStatsMsg.surfaceID < 0) + { + myStatsMsg.surfaceID = allocateSurface(myStatsMsg.w, myStatsMsg.h); + myStatsMsg.surface = surface(myStatsMsg.surfaceID); + } if(!myMsg.surface) // TODO - change this to the font we'll really use - myMsg.surface = createSurface(320, myOSystem->consoleFont().getFontHeight()+10); + { + myMsg.surfaceID = allocateSurface(320, myOSystem->consoleFont().getFontHeight()+10); + myMsg.surface = surface(myMsg.surfaceID); + } // Finally, show some information about the framebuffer, // but only on the first initialization @@ -373,6 +381,51 @@ void FrameBuffer::refresh() myRedrawEntireFrame = true; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int FrameBuffer::allocateSurface(int w, int h, bool useBase) +{ + // Create a new surface + FBSurface* surface = createSurface(w, h, useBase); + + // Add it to the list + mySurfaceList.insert(make_pair(mySurfaceCount, surface)); + mySurfaceCount++; + + // Return a reference to it + return mySurfaceCount - 1; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int FrameBuffer::freeSurface(int id) +{ + // Really delete the surface this time + // That means actually deleting the FBSurface object, and removing it + // from the list + map::iterator iter = mySurfaceList.find(id); + if(iter != mySurfaceList.end()) + { +cerr << " delete id = " << iter->first << ", " << iter->second << endl; + delete iter->second; + mySurfaceList.erase(iter); + } + return -1; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +FBSurface* FrameBuffer::surface(int id) const +{ + map::const_iterator iter = mySurfaceList.find(id); + return iter != mySurfaceList.end() ? iter->second : NULL; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FrameBuffer::reloadSurfaces() +{ + map::iterator iter; + for(iter = mySurfaceList.begin(); iter != mySurfaceList.end(); ++iter) + iter->second->reload(); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::setTIAPalette(const uInt32* palette) { diff --git a/stella/src/emucore/FrameBuffer.hxx b/stella/src/emucore/FrameBuffer.hxx index ba3a9307b..aa52019e6 100644 --- a/stella/src/emucore/FrameBuffer.hxx +++ b/stella/src/emucore/FrameBuffer.hxx @@ -13,12 +13,13 @@ // 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.104 2008-08-04 11:56:12 stephena Exp $ +// $Id: FrameBuffer.hxx,v 1.105 2008-12-12 15:51:07 stephena Exp $ //============================================================================ #ifndef FRAMEBUFFER_HXX #define FRAMEBUFFER_HXX +#include #include class FBSurface; @@ -90,7 +91,7 @@ enum { turn drawn here as well. @author Stephen Anthony - @version $Id: FrameBuffer.hxx,v 1.104 2008-08-04 11:56:12 stephena Exp $ + @version $Id: FrameBuffer.hxx,v 1.105 2008-12-12 15:51:07 stephena Exp $ */ class FrameBuffer { @@ -150,6 +151,35 @@ class FrameBuffer */ void enableMessages(bool enable); + /** + Allocate a new surface with a unique ID. + + @param w The requested width of the new surface. + @param h The requested height of the new surface. + @param useBase Use the base surface instead of creating a new one + + @return A unique ID used to identify this surface + */ + int allocateSurface(int w, int h, bool useBase = false); + + /** + De-allocate a previously allocated surface. Other classes should + call this method when a surface is no longer needed; it shouldn't + try to manually delete the surface object. + + @param id The ID for the surface to de-allocate. + @return The ID indicating a non-existent surface (-1). + */ + int freeSurface(int id); + + /** + Retrieve the surface associated with the given ID. + + @param id The ID for the surface to retrieve. + @return A pointer to a valid surface object, or NULL. + */ + FBSurface* surface(int id) const; + /** Returns the current dimensions of the framebuffer image. Note that this will take into account the current scaling (if any) @@ -268,16 +298,6 @@ class FrameBuffer */ virtual BufferType type() const = 0; - /** - This method is called to create a surface compatible with the one - currently in use, but having the given dimensions. - - @param w The requested width of the new surface. - @param h The requested height of the new surface. - @param useBase Use the base surface instead of creating a new one - */ - virtual FBSurface* createSurface(int w, int h, bool useBase = false) const = 0; - /** This method is called to get the specified scanline data. @@ -343,6 +363,16 @@ class FrameBuffer */ virtual bool setVidMode(VideoMode& mode) = 0; + /** + This method is called to create a surface compatible with the one + currently in use, but having the given dimensions. + + @param w The requested width of the new surface. + @param h The requested height of the new surface. + @param useBase Use the base surface instead of creating a new one + */ + virtual FBSurface* createSurface(int w, int h, bool useBase = false) const = 0; + /** Switches between the filtering options in the video subsystem. */ @@ -364,6 +394,12 @@ class FrameBuffer */ virtual string about() const = 0; + /** + Issues the 'reload' instruction to all surfaces that the + framebuffer knows about. + */ + void reloadSurfaces(); + protected: // The parent system for the framebuffer OSystem* myOSystem; @@ -492,6 +528,7 @@ class FrameBuffer int x, y, w, h; uInt32 color; FBSurface* surface; + int surfaceID; bool enabled; }; Message myMsg; @@ -502,6 +539,10 @@ class FrameBuffer VideoModeList myFullscreenModeList; VideoModeList* myCurrentModeList; + // Holds a reference to all the surfaces that have been created + map mySurfaceList; + int mySurfaceCount; + // Holds static strings for the remap menu (emulation and menu events) static GraphicsMode ourGraphicsModes[GFX_NumModes]; }; @@ -516,7 +557,7 @@ class FrameBuffer FrameBuffer type. @author Stephen Anthony - @version $Id: FrameBuffer.hxx,v 1.104 2008-08-04 11:56:12 stephena Exp $ + @version $Id: FrameBuffer.hxx,v 1.105 2008-12-12 15:51:07 stephena Exp $ */ // Text alignment modes for drawString() enum TextAlignment { @@ -650,6 +691,11 @@ class FBSurface */ virtual void update() = 0; + /** + This method should be called to reload the surface data/state. + */ + virtual void reload() = 0; + /** This method should be called to draw a rectangular box with sides at the specified coordinates. diff --git a/stella/src/gui/Dialog.cxx b/stella/src/gui/Dialog.cxx index 39bb5c1bf..1e43921ac 100644 --- a/stella/src/gui/Dialog.cxx +++ b/stella/src/gui/Dialog.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: Dialog.cxx,v 1.64 2008-08-01 12:16:00 stephena Exp $ +// $Id: Dialog.cxx,v 1.65 2008-12-12 15:51:07 stephena Exp $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project @@ -47,7 +47,8 @@ Dialog::Dialog(OSystem* instance, DialogContainer* parent, _isBase(isBase), _ourTab(NULL), _surface(NULL), - _focusID(0) + _focusID(0), + _surfaceID(-1) { } @@ -62,7 +63,8 @@ Dialog::~Dialog() _ourButtonGroup.clear(); - delete _surface; + _surfaceID = instance().frameBuffer().freeSurface(_surfaceID); + _surface = NULL; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -77,6 +79,28 @@ void Dialog::open() // Base surfaces are typically large, and will probably cause slow // performance if we update the whole area each frame // Instead, dirty rectangle updates should be performed + // However, this policy is left entirely to the framebuffer + // We suggest the hint here, but specific framebuffers are free to + // ignore it + if(_surfaceID < 0 || _surface == NULL) + { + _surfaceID = instance().frameBuffer().allocateSurface(_w, _h, _isBase); + _surface = instance().frameBuffer().surface(_surfaceID); + } + else if((uInt32)_w > _surface->getWidth() || (uInt32)_h > _surface->getHeight()) + { + _surfaceID = instance().frameBuffer().freeSurface(_surfaceID); + _surfaceID = instance().frameBuffer().allocateSurface(_w, _h, _isBase); + _surface = instance().frameBuffer().surface(_surfaceID); + } + else + { + _surface->setWidth(_w); + _surface->setHeight(_h); + } + + +/* if(_surface == NULL) _surface = instance().frameBuffer().createSurface(_w, _h, _isBase); else if((uInt32)_w > _surface->getWidth() || (uInt32)_h > _surface->getHeight()) @@ -89,6 +113,8 @@ void Dialog::open() _surface->setWidth(_w); _surface->setHeight(_h); } +*/ + center(); diff --git a/stella/src/gui/Dialog.hxx b/stella/src/gui/Dialog.hxx index bebb3c423..439209156 100644 --- a/stella/src/gui/Dialog.hxx +++ b/stella/src/gui/Dialog.hxx @@ -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: Dialog.hxx,v 1.39 2008-06-19 19:15:44 stephena Exp $ +// $Id: Dialog.hxx,v 1.40 2008-12-12 15:51:07 stephena Exp $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project @@ -47,7 +47,7 @@ class TabWidget; This is the base class for all dialog boxes. @author Stephen Anthony - @version $Id: Dialog.hxx,v 1.39 2008-06-19 19:15:44 stephena Exp $ + @version $Id: Dialog.hxx,v 1.40 2008-12-12 15:51:07 stephena Exp $ */ class Dialog : public GuiObject { @@ -135,6 +135,7 @@ class Dialog : public GuiObject int _result; int _focusID; + int _surfaceID; }; #endif