X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=platform%2Fsdlv.cpp;h=750423140a2ed7fb7b2dcdcb0f62a0ec6390c966;hb=9902256814785f0b3f08d336a98c481c296ac7e5;hp=3d1a29cf41c1cc2a17c042cbf1d101638add7401;hpb=eebf58204c59d9b1b778866094141daf54e18b0b;p=drnoksnes diff --git a/platform/sdlv.cpp b/platform/sdlv.cpp index 3d1a29c..7504231 100644 --- a/platform/sdlv.cpp +++ b/platform/sdlv.cpp @@ -2,15 +2,14 @@ #include #include -#include #include #include #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__ ); \ @@ -18,35 +17,19 @@ abort(); \ } while (0); -static SDL_Surface *screen; +struct gui GUI; + +SDL_Surface* screen; static SDL_Rect windowSize, screenSize; static bool gotWindowSize, gotScreenSize; -/** Inside the surface, where are we drawing */ -static SDL_Rect renderArea; - -#ifdef MAEMO -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); - } -} -#endif - -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; -} +/** The current scaler object */ +Scaler* scaler; +/** Use the current window size to calculate screen size. + Useful on "single window" platforms, like Hildon. + */ static void calculateScreenSize() { SDL_SysWMinfo wminfo; @@ -76,8 +59,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) ) { @@ -96,24 +81,28 @@ static void freeVideoSurface() { screen = 0; // There's no need to free the screen surface. GFX.Screen = 0; - + free(GFX.SubScreen); GFX.SubScreen = 0; free(GFX.ZBuffer); GFX.ZBuffer = 0; free(GFX.SubZBuffer); GFX.SubZBuffer = 0; + + delete scaler; scaler = 0; } static void setupVideoSurface() { // Real surface area. - unsigned gameWidth = IMAGE_WIDTH; - unsigned gameHeight = IMAGE_HEIGHT; - // SDL Window/Surface size (bigger, so we can get mouse events there). - unsigned winWidth, winHeight; + const unsigned gameWidth = IMAGE_WIDTH; + const unsigned gameHeight = IMAGE_HEIGHT; #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)); @@ -121,82 +110,83 @@ static void setupVideoSurface() calculateScreenSize(); } if (Config.fullscreen) { - winWidth = screenSize.w; - winHeight = screenSize.h; + GUI.Width = screenSize.w; + GUI.Height = screenSize.h; } else { - winWidth = windowSize.w; - winHeight = windowSize.h; - } - - // So, can we enable Xsp? - if (gameWidth * 2 < winWidth && gameHeight * 2 < winHeight) { - Config.xsp = true; - } else { - Config.xsp = false; - setDoubling(false); // Before switching video modes; avoids flicker. + GUI.Width = windowSize.w; + GUI.Height = windowSize.h; } #else - winWidth = gameWidth; - winHeight = gameHeight; + GUI.Width = gameWidth; + GUI.Height = gameHeight; +#endif +#if CONF_EXIT_BUTTON + ExitBtnReset(); #endif // Safeguard - if (gameHeight > winHeight || gameWidth > winWidth) + if (gameHeight > GUI.Height || gameWidth > GUI.Width) DIE("Video is larger than window size!"); - screen = SDL_SetVideoMode(winWidth, winHeight, - Settings.SixteenBit ? 16 : 8, - SDL_SWSURFACE | - (Config.fullscreen ? SDL_FULLSCREEN : 0)); + const ScalerFactory* sFactory = searchForScaler(16, gameWidth, gameHeight); + + screen = SDL_SetVideoMode(GUI.Width, GUI.Height, 16, + SDL_SWSURFACE | (Config.fullscreen ? SDL_FULLSCREEN : 0)); + if (!screen) DIE("SDL_SetVideoMode: %s", SDL_GetError()); SDL_ShowCursor(SDL_DISABLE); - // We get pitch surface values from SDL - GFX.RealPitch = GFX.Pitch = screen->pitch; - GFX.ZPitch = GFX.Pitch / 2; // gfx & tile.cpp depend on this, unfortunately. - GFX.PixSize = screen->format->BitsPerPixel / 8; + scaler = sFactory->instantiate(screen, gameWidth, gameHeight); - // Ok, calculate renderArea -#ifdef MAEMO - if (Config.xsp) { - setDoubling(true); - centerRectangle(renderArea, winWidth, winHeight, - gameWidth * 2, gameHeight * 2); - renderArea.w /= 2; - renderArea.h /= 2; - } else { - centerRectangle(renderArea, winWidth, winHeight, gameWidth, gameHeight); - } -#else - centerRectangle(renderArea, winWidth, winHeight, gameWidth, gameHeight); -#endif - - GFX.Screen = ((uint8*) screen->pixels) - + (renderArea.x * GFX.PixSize) - + (renderArea.y * GFX.Pitch); + // 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); + scaler->getRatio(GUI.ScaleX, GUI.ScaleY); - printf("Video: %dx%d (%dx%d output), %hu bits per pixel, %s %s\n", + printf("Video: %dx%d (%dx%d output), %hu bits per pixel, %s, %s\n", gameWidth, gameHeight, screen->w, screen->h, screen->format->BitsPerPixel, Config.fullscreen ? "fullscreen" : "windowed", - Config.xsp ? "with pixel doubling" : ""); + scaler->getName()); +} + +static void drawOnscreenControls() +{ + if (Config.touchscreenInput) { + S9xInputScreenChanged(); + } + + if (Config.touchscreenShow) { + scaler->pause(); + SDL_FillRect(screen, NULL, 0); + S9xInputScreenDraw(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()); setupVideoSurface(); + drawOnscreenControls(); } void S9xDeinitDisplay() @@ -207,52 +197,66 @@ void S9xDeinitDisplay() void S9xVideoToggleFullscreen() { - Config.fullscreen = !Config.fullscreen; freeVideoSurface(); + Config.fullscreen = !Config.fullscreen; setupVideoSurface(); + drawOnscreenControls(); } -void S9xVideoOutputFocus(bool hasFocus) -{ - if (Config.xsp) { - setDoubling(hasFocus); - } -} - -// This is here for completeness, but palette mode is useless on N8x0 -void S9xSetPalette () +bool videoEventFilter(const SDL_Event& event) { - if (Settings.SixteenBit) return; - - SDL_Color colors[256]; - int brightness = IPPU.MaxBrightness *138; - for (int i = 0; i < 256; i++) - { - colors[i].r = ((PPU.CGDATA[i] >> 0) & 0x1F) * brightness; - colors[i].g = ((PPU.CGDATA[i] >> 5) & 0x1F) * brightness; - colors[i].b = ((PPU.CGDATA[i] >> 10) & 0x1F) * brightness; + // 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; + } } - - SDL_SetColors(screen, colors, 0, 256); + + // Forward video event to the active scaler, if any. + if (scaler) + return scaler->filter(event); + else + return false; } -bool8_32 S9xInitUpdate () +/** 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 S9xInitUpdate () { - if(SDL_MUSTLOCK(screen)) - { - if(SDL_LockSurface(screen) < 0) { - DIE("Failed to lock SDL surface: %s", SDL_GetError()); - } - } + scaler->prepare(); return TRUE; } -bool8_32 S9xDeinitUpdate (int width, int height, bool8_32 sixteenBit) +/** 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 S9xDeinitUpdate (int width, int height) { - if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen); + scaler->finish(); - SDL_UpdateRects(screen, 1, &renderArea); +#if CONF_EXIT_BUTTON + if (ExitBtnRequiresDraw()) { + scaler->pause(); + ExitBtnDraw(screen); + scaler->resume(); + } +#endif return TRUE; }