X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=platform%2Fsdlv.cpp;h=98964946a54c982214f12f5bbf08483c4a7ae744;hb=cbe623ccf368fc733eb7a881a423afabe250ce8f;hp=e48c6fa4c5a08ba920b86dfd29585b3e5e75b061;hpb=3fdda1aa0655b9472e00bc34751475de6fa071ca;p=drnoksnes diff --git a/platform/sdlv.cpp b/platform/sdlv.cpp index e48c6fa..9896494 100644 --- a/platform/sdlv.cpp +++ b/platform/sdlv.cpp @@ -5,15 +5,12 @@ #include #include -#if CONF_XSP -# include -#endif - #include "snes9x.h" #include "platform.h" #include "display.h" #include "gfx.h" #include "ppu.h" +#include "sdlv.h" #define DIE(format, ...) do { \ fprintf(stderr, "Died at %s:%d: ", __FILE__, __LINE__ ); \ @@ -23,357 +20,17 @@ struct gui GUI; -static SDL_Surface* screen; +SDL_Surface* screen; static SDL_Rect windowSize, screenSize; static bool gotWindowSize, gotScreenSize; -class Scaler; /** The current scaler object */ -static Scaler* scaler; - -static void centerRectangle(SDL_Rect& result, int areaW, int areaH, int w, int h) -{ - result.x = areaW / 2 - w / 2; - result.w = w; - result.y = areaH / 2 - h / 2; - result.h = h; -} - -class Scaler -{ -public: - Scaler() { }; - virtual ~Scaler() { }; - - virtual const char * getName() const = 0; - - virtual uint8* getDrawBuffer() const = 0; - virtual unsigned int getDrawBufferPitch() const = 0; - virtual void getRenderedGUIArea(unsigned short & x, unsigned short & y, - unsigned short & w, unsigned short & h) - const = 0; - virtual int getRatio() const = 0; - virtual void prepare() = 0; - virtual void finish() = 0; -}; - -class ScalerFactory -{ -public: - ScalerFactory() { }; - virtual ~ScalerFactory() { }; - virtual const char * getName() const = 0; - virtual bool canEnable(int w, int h) const = 0; - virtual Scaler* instantiate(SDL_Surface* screen, int w, int h) const = 0; -}; - -class DummyScaler : public Scaler -{ - SDL_Surface * m_screen; - SDL_Rect m_area; - - DummyScaler(SDL_Surface* screen, int w, int h) - : m_screen(screen) - { - centerRectangle(m_area, GUI.Width, GUI.Height, w, h); - } -public: - - ~DummyScaler() - { - }; - - class Factory : public ScalerFactory - { - const char * getName() const - { - return "none"; - } - - bool canEnable(int w, int h) const - { - return true; - } - - Scaler* instantiate(SDL_Surface* screen, int w, int h) const - { - return new DummyScaler(screen, w, h); - } - }; - - static const Factory factory; - - const char * getName() const - { - return "no scaling"; - } - - uint8* getDrawBuffer() const - { - const int Bpp = screen->format->BitsPerPixel / 8; - const int pitch = screen->pitch; - return ((uint8*) screen->pixels) - + (m_area.x * Bpp) - + (m_area.y * pitch); - }; - - unsigned int getDrawBufferPitch() const - { - return screen->pitch; - }; - - void getRenderedGUIArea(unsigned short & x, unsigned short & y, - unsigned short & w, unsigned short & h) const - { - x = m_area.x; y = m_area.y; w = m_area.w; h = m_area.h; - }; - - int getRatio() const - { - return 1; - }; - - void prepare() { }; - - void finish() - { - SDL_UpdateRects(m_screen, 1, &m_area); - }; -}; -const DummyScaler::Factory DummyScaler::factory; - -class SWScaler : public Scaler -{ - SDL_Surface * m_screen; - SDL_Rect m_area; - uint8 * m_surface; - const int m_w, m_h, m_Bpp; - - SWScaler(SDL_Surface* screen, int w, int h) - : m_screen(screen), m_w(w), m_h(h), - m_Bpp(m_screen->format->BitsPerPixel / 8) - { - centerRectangle(m_area, GUI.Width, GUI.Height, w * 2, h * 2); - m_surface = reinterpret_cast(malloc(w * h * m_Bpp)); - } -public: - ~SWScaler() - { - free(m_surface); - }; - - class Factory : public ScalerFactory - { - const char * getName() const - { - return "2x"; - } - - bool canEnable(int w, int h) const - { - return w * 2 < GUI.Width && h * 2 < GUI.Height; - } - - Scaler* instantiate(SDL_Surface* screen, int w, int h) const - { - return new SWScaler(screen, w, h); - } - }; - - static const Factory factory; - - const char * getName() const - { - return "software 2x scaling"; - } - - uint8* getDrawBuffer() const - { - return m_surface; - }; - - unsigned int getDrawBufferPitch() const - { - return m_w * m_Bpp; - }; - - void getRenderedGUIArea(unsigned short & x, unsigned short & y, - unsigned short & w, unsigned short & h) const - { - x = m_area.x; y = m_area.y; w = m_area.w; h = m_area.h; - }; - - int getRatio() const - { - return 2; - }; - - void prepare() { }; - - void finish() - { - uint16 * src = reinterpret_cast(m_surface); - uint16 * dst = reinterpret_cast( - ((uint8*) m_screen->pixels) - + (m_area.x * m_Bpp) - + (m_area.y * m_screen->pitch)); - const int src_pitch = m_w; - const int dst_pitch = m_screen->pitch / m_Bpp; - int x, y; - - for (y = 0; y < m_h*2; y++) { - for (x = 0; x < m_w*2; x+=2) { - dst[x] = src[x/2]; - dst[x + 1] = src[x/2]; - } - dst += dst_pitch; - if (y&1) src += src_pitch; - } - - SDL_UpdateRects(m_screen, 1, &m_area); - }; -}; -const SWScaler::Factory SWScaler::factory; - -#if CONF_XSP -class XSPScaler : public Scaler -{ - SDL_Surface* m_screen; - SDL_Rect m_area; - SDL_Rect m_real_area; - - static void setDoubling(bool enable) - { - SDL_SysWMinfo wminfo; - SDL_VERSION(&wminfo.version); - if ( SDL_GetWMInfo(&wminfo) ) { - Display *dpy = wminfo.info.x11.display; - XSPSetPixelDoubling(dpy, 0, enable ? 1 : 0); - XFlush(dpy); - } - } - - XSPScaler(SDL_Surface* screen, int w, int h) - : m_screen(screen) - { - centerRectangle(m_area, GUI.Width, GUI.Height, - w * 2, h * 2); - setDoubling(true); - - m_real_area.x = m_area.x; - m_real_area.y = m_area.y; - m_real_area.w = m_area.w / 2; - m_real_area.h = m_area.h / 2; - }; -public: - ~XSPScaler() - { - setDoubling(false); - }; - - class Factory : public ScalerFactory - { - const char * getName() const - { - return "xsp"; - } - - bool canEnable(int w, int h) const - { - return w * 2 < GUI.Width && h * 2 < GUI.Height; - }; - - Scaler* instantiate(SDL_Surface* screen, int w, int h) const - { - return new XSPScaler(screen, w, h); - } - }; - - static const Factory factory; - - const char * getName() const - { - return "XSP pixel doubling"; - } - - uint8* getDrawBuffer() const - { - const int Bpp = screen->format->BitsPerPixel / 8; - const int pitch = screen->pitch; - return ((uint8*) screen->pixels) - + (m_area.x * Bpp) - + (m_area.y * pitch); - }; - - unsigned int getDrawBufferPitch() const - { - return screen->pitch; - }; - - void getRenderedGUIArea(unsigned short & x, unsigned short & y, - unsigned short & w, unsigned short & h) const - { - x = m_area.x; y = m_area.y; w = m_area.w; h = m_area.h; - }; - - int getRatio() const - { - return 2; - }; - - void prepare() { }; - - void finish() - { - SDL_UpdateRects(m_screen, 1, &m_real_area); - }; -}; -const XSPScaler::Factory XSPScaler::factory; -#endif - -static const ScalerFactory* scalers[] = { -#if CONF_XSP - &XSPScaler::factory, -#endif - &SWScaler::factory, - &DummyScaler::factory -}; - -static const ScalerFactory* searchForScaler(int w, int h) -{ - const int n = sizeof(scalers) / sizeof(ScalerFactory*); - int i; - - if (Config.scaler && strcasecmp(Config.scaler, "help") == 0 ) { - // List scalers - printf("Scalers list:\n"); - for (i = 0; i < n; i++) { - printf(" %s\n", scalers[i]->getName()); - } - DIE("End of scalers list"); - } else if (Config.scaler && strcasecmp(Config.scaler, "auto") != 0 ) { - // We prefer a specific scaler - for (i = 0; i < n; i++) { - if (strcasecmp(scalers[i]->getName(), Config.scaler) == 0) { - if (!scalers[i]->canEnable(w, h)) { - DIE("Cannot use selected scaler"); - } - return scalers[i]; - } - } - DIE("Select scaler does not exist"); - } else { - // Just try them all - for (i = 0; i < n; i++) { - if (scalers[i]->canEnable(w, h)) { - return scalers[i]; - } - } - DIE("Can't use any scaler"); - } -} +Scaler* scaler; +/** Use the current window size to calculate screen size. + Useful on "single window" platforms, like Hildon. + */ static void calculateScreenSize() { SDL_SysWMinfo wminfo; @@ -403,8 +60,10 @@ static void calculateScreenSize() } } +/** Sets the main window title */ void S9xSetTitle(const char *title) { + // This is a Maemo specific hack, but works on most platforms. SDL_SysWMinfo info; SDL_VERSION(&info.version); if ( SDL_GetWMInfo(&info) ) { @@ -428,7 +87,7 @@ static void freeVideoSurface() free(GFX.ZBuffer); GFX.ZBuffer = 0; free(GFX.SubZBuffer); GFX.SubZBuffer = 0; - free(scaler); scaler = 0; + delete scaler; scaler = 0; } static void setupVideoSurface() @@ -437,15 +96,14 @@ static void setupVideoSurface() const unsigned gameWidth = IMAGE_WIDTH; const unsigned gameHeight = IMAGE_HEIGHT; - if (scaler) { - delete scaler; - scaler = 0; - } - #ifdef MAEMO + // Under Maemo we know that the window manager will automatically + // resize our windows to fullscreen. + // Thus we can use that to detect the screen size. + // Of course, this causes flicker, so we try to avoid it when + // changing between modes. if ((Config.fullscreen && !gotScreenSize) || (!Config.fullscreen && !gotWindowSize)) { - // Do a first try, in order to get window/screen size screen = SDL_SetVideoMode(gameWidth, gameHeight, 16, SDL_SWSURFACE | SDL_RESIZABLE | (Config.fullscreen ? SDL_FULLSCREEN : 0)); @@ -463,12 +121,16 @@ static void setupVideoSurface() GUI.Width = gameWidth; GUI.Height = gameHeight; #endif +#if CONF_EXIT_BUTTON + ExitBtnReset(); +#endif // Safeguard if (gameHeight > GUI.Height || gameWidth > GUI.Width) DIE("Video is larger than window size!"); - const ScalerFactory* sFactory = searchForScaler(gameWidth, gameHeight); + const ScalerFactory* sFactory = + searchForScaler(Settings.SixteenBit ? 16 : 8, gameWidth, gameHeight); screen = SDL_SetVideoMode(GUI.Width, GUI.Height, Settings.SixteenBit ? 16 : 8, @@ -481,22 +143,23 @@ static void setupVideoSurface() scaler = sFactory->instantiate(screen, gameWidth, gameHeight); - // We get pitch surface values from SDL - GFX.RealPitch = GFX.Pitch = scaler->getDrawBufferPitch(); - GFX.ZPitch = GFX.Pitch / 2; // gfx & tile.cpp depend on this, unfortunately. - GFX.PixSize = screen->format->BitsPerPixel / 8; - + // Each scaler may have its own pitch + GFX.Pitch = scaler->getDrawBufferPitch(); + GFX.ZPitch = GFX.Pitch / 2; + // gfx & tile.cpp depend on the zbuffer pitch being always half of the color buffer pitch. + // Which is a pity, since the color buffer might be much larger. + GFX.Screen = scaler->getDrawBuffer(); GFX.SubScreen = (uint8 *) malloc(GFX.Pitch * IMAGE_HEIGHT); GFX.ZBuffer = (uint8 *) malloc(GFX.ZPitch * IMAGE_HEIGHT); GFX.SubZBuffer = (uint8 *) malloc(GFX.ZPitch * IMAGE_HEIGHT); GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1; - GFX.PPL = GFX.Pitch >> 1; - GFX.PPLx2 = GFX.Pitch; + GFX.DepthDelta = GFX.SubZBuffer - GFX.ZBuffer; + GFX.PPL = GFX.Pitch / (screen->format->BitsPerPixel / 8); scaler->getRenderedGUIArea(GUI.RenderX, GUI.RenderY, GUI.RenderW, GUI.RenderH); - GUI.Scale = scaler->getRatio(); + scaler->getRatio(GUI.ScaleX, GUI.ScaleY); printf("Video: %dx%d (%dx%d output), %hu bits per pixel, %s, %s\n", gameWidth, gameHeight, @@ -509,15 +172,19 @@ static void drawOnscreenControls() { if (Config.touchscreenInput) { S9xInputScreenChanged(); - if (Config.touchscreenShow) { - S9xInputScreenDraw(Settings.SixteenBit ? 2 : 1, - screen->pixels, screen->pitch); - SDL_Flip(screen); - } + } + + if (Config.touchscreenShow) { + scaler->pause(); + SDL_FillRect(screen, NULL, 0); + S9xInputScreenDraw(Settings.SixteenBit ? 2 : 1, + screen->pixels, screen->pitch); + SDL_Flip(screen); + scaler->resume(); } } -void S9xInitDisplay(int argc, const char ** argv) +void S9xInitDisplay(int argc, char ** argv) { if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) DIE("SDL_InitSubSystem(VIDEO): %s", SDL_GetError()); @@ -534,22 +201,32 @@ void S9xDeinitDisplay() void S9xVideoToggleFullscreen() { - Config.fullscreen = !Config.fullscreen; freeVideoSurface(); + Config.fullscreen = !Config.fullscreen; setupVideoSurface(); drawOnscreenControls(); } -void S9xVideoOutputFocus(bool hasFocus) +bool videoEventFilter(const SDL_Event& event) { -#if 0 // TODO - if (Config.xsp) { - setDoubling(hasFocus); - } -#endif + // If we're in power save mode, and this is a defocus event, quit. + if (Config.saver) { + if (event.type == SDL_ACTIVEEVENT && + (event.active.state & SDL_APPINPUTFOCUS) && + !event.active.gain) { + S9xDoAction(kActionQuit); + return true; + } + } + + // Forward video event to the active scaler, if any. + if (scaler) + return scaler->filter(event); + else + return false; } -// This is here for completeness, but palette mode is useless on N8x0 +// This is here for completeness, but palette mode is mostly useless (slow). void S9xSetPalette () { if (Settings.SixteenBit) return; @@ -566,6 +243,11 @@ void S9xSetPalette () SDL_SetColors(screen, colors, 0, 256); } +/** Called before rendering a frame. + This function must ensure GFX.Screen points to something, but we did that + while initializing video output. + @return TRUE if we should render the frame. + */ bool8_32 S9xInitUpdate () { scaler->prepare(); @@ -573,10 +255,30 @@ bool8_32 S9xInitUpdate () return TRUE; } +/** Called once a complete SNES screen has been rendered into the GFX.Screen + memory buffer. + + Now is your chance to copy the SNES rendered screen to the + host computer's screen memory. The problem is that you have to cope with + different sized SNES rendered screens. Width is always 256, unless you're + supporting SNES hi-res. screen modes (Settings.SupportHiRes is TRUE), in + which case it can be 256 or 512. The height parameter can be either 224 or + 239 if you're only supporting SNES lo-res. screen modes, or 224, 239, 448 or + 478 if hi-res. SNES screen modes are being supported. + */ +// TODO Above. bool8_32 S9xDeinitUpdate (int width, int height, bool8_32 sixteenBit) { scaler->finish(); +#if CONF_EXIT_BUTTON + if (ExitBtnRequiresDraw()) { + scaler->pause(); + ExitBtnDraw(screen); + scaler->resume(); + } +#endif + return TRUE; }