diff options
-rw-r--r-- | README | 2 | ||||
-rw-r--r-- | backends/sdl/sdl_gl.cpp | 369 |
2 files changed, 305 insertions, 66 deletions
@@ -335,7 +335,7 @@ simon games. Ctrl-Alt 1 - Switch beetwen bilinear and non-linear filtering [OpenGL backend] Ctrl-Alt 2 - Don't fit the game in the whole screen (black borders) [OpenGL backend] Ctrl-Alt 3 - Fit the game in the whole screen (no black borders) [OpenGL backend] - Ctrl-Alt 4-7 - Zoom [OpenGL backend] + Ctrl-Alt 4-7 - Switch between graphics filters [OpenGL backend] Scumm: Ctrl 0-9 and Alt 0-9 - load and save game state diff --git a/backends/sdl/sdl_gl.cpp b/backends/sdl/sdl_gl.cpp index 13dcb90190..e1ff24d891 100644 --- a/backends/sdl/sdl_gl.cpp +++ b/backends/sdl/sdl_gl.cpp @@ -34,11 +34,7 @@ int glGetColorTable(int, int, int, void *) { return 0; } class OSystem_SDL_OpenGL : public OSystem_SDL_Common { public: - OSystem_SDL_OpenGL() { - _glScreenStart = 0; - _glBilinearFilter = true; - _glBottomOfTexture = 256; // height is always 256 - } + OSystem_SDL_OpenGL(); // Set colors of the palette void set_palette(const byte *colors, uint start, uint num); @@ -49,14 +45,24 @@ public: // Set a parameter uint32 property(int param, Property *value); + // Get the next event. + // Returns true if an event was retrieved. +// bool poll_event(Event *event); + protected: FB2GL fb2gl; int _glFlags; int _glScreenStart; bool _glBilinearFilter; + bool _usingOpenGL; SDL_Surface *tmpSurface; // Used for black rectangles blitting - SDL_Rect tmpBlackRect; // Black rectangle at end of the GL screen + SDL_Rect tmpBlackRect; // Black rectangle at end of the GL screen + SDL_Rect _glWindow; // Only uses w and h (for window resizing) int _glBottomOfTexture; + + SDL_Surface *_hwscreen; // hardware screen (=> _usingOpenGL == false) + + ScalerProc *_scaler_proc; virtual void load_gfx_mode(); virtual void unload_gfx_mode(); @@ -67,6 +73,18 @@ OSystem_SDL_Common *OSystem_SDL_Common::create() { return new OSystem_SDL_OpenGL(); } +OSystem_SDL_OpenGL::OSystem_SDL_OpenGL() + : _hwscreen(0), _scaler_proc(0) +{ + _glScreenStart = 0; + _glBilinearFilter = true; + _usingOpenGL = true; // false => Switch to filters used in the sdl.cpp version + _glBottomOfTexture = 256; // height is always 256 + // 640x480 resolution + _glWindow.w = 640; + _glWindow.h = 480; +} + void OSystem_SDL_OpenGL::set_palette(const byte *colors, uint start, uint num) { const byte *b = colors; uint i; @@ -93,13 +111,51 @@ void OSystem_SDL_OpenGL::load_gfx_mode() { Gmask = 0x07E0; // 6 Bmask = 0x001F; // 5 Amask = 0; - + _forceFull = true; _mode_flags = DF_UPDATE_EXPAND_1_PIXEL; - _scaleFactor = 2; _tmpscreen = NULL; _tmpScreenWidth = (_screenWidth + 3); + + switch(_mode) { + case GFX_2XSAI: + _scaleFactor = 2; + _scaler_proc = _2xSaI; + break; + case GFX_SUPER2XSAI: + _scaleFactor = 2; + _scaler_proc = Super2xSaI; + break; + case GFX_SUPEREAGLE: + _scaleFactor = 2; + _scaler_proc = SuperEagle; + break; + case GFX_ADVMAME2X: + _scaleFactor = 2; + _scaler_proc = AdvMame2x; + break; + case GFX_TV2X: + _scaleFactor = 2; + _scaler_proc = TV2x; + break; + case GFX_DOTMATRIX: + _scaleFactor = 2; + _scaler_proc = DotMatrix; + break; + case GFX_NORMAL: + _scaleFactor = 1; + _scaler_proc = Normal1x; + break; + default: +// error("unknown gfx mode"); + _mode = GFX_NORMAL; + _scaleFactor = 1; + _scaler_proc = Normal1x; + } + + if (_mode != GFX_NORMAL) + _usingOpenGL = false; // // Create the surface that contains the 8 bit game data @@ -108,21 +164,37 @@ void OSystem_SDL_OpenGL::load_gfx_mode() { if (_screen == NULL) error("_screen failed"); - // // Create the surface that contains the scaled graphics in 16 bit mode // - - _glFlags = FB2GL_320 | FB2GL_RGBA | FB2GL_16BIT; - if (_full_screen) { - _glFlags |= (FB2GL_FS); - _glScreenStart = 0; + if (_usingOpenGL) { + + _glFlags = FB2GL_320 | FB2GL_RGBA | FB2GL_16BIT; + if (_full_screen) { + _glFlags |= (FB2GL_FS); + _glScreenStart = 0; + } + // _glWindow defines the resolution + fb2gl.init(_glWindow.w, _glWindow.h, 0, _glScreenStart? 15: 70, + _glFlags); + + } + else { // SDL backend + + _hwscreen = SDL_SetVideoMode(_screenWidth * _scaleFactor, _screenHeight * _scaleFactor, 16, + _full_screen ? (SDL_FULLSCREEN|SDL_SWSURFACE) : SDL_SWSURFACE + ); + if (_hwscreen == NULL) + error("_hwscreen failed"); + + // Distinguish 555 and 565 mode + if (_hwscreen->format->Rmask == 0x7C00) + Init_2xSaI(555); + else + Init_2xSaI(565); } - // 640x480 screen resolution - fb2gl.init(640, 480, 0,_glScreenStart? 15: 70,_glFlags); SDL_SetGamma(1.25, 1.25, 1.25); - // // Create the surface used for the graphics in 16 bit before scaling, and also the overlay @@ -130,12 +202,29 @@ void OSystem_SDL_OpenGL::load_gfx_mode() { // Need some extra bytes around when using 2xSaI uint16 *tmp_screen = (uint16 *)calloc(_tmpScreenWidth * (_screenHeight + 3),sizeof(uint16)); - _tmpscreen = SDL_CreateRGBSurfaceFrom(tmp_screen, - _tmpScreenWidth, _screenHeight + 3, 16, _tmpScreenWidth * 2, + + if (_usingOpenGL) { + _tmpscreen = SDL_CreateRGBSurfaceFrom(tmp_screen, + _tmpScreenWidth, + _screenHeight + 3, + 16, + _tmpScreenWidth * 2, Rmask, Gmask, Bmask, Amask); + } + else { // SDL backend + _tmpscreen = SDL_CreateRGBSurfaceFrom(tmp_screen, + _tmpScreenWidth, + _screenHeight + 3, + 16, + _tmpScreenWidth * 2, + _hwscreen->format->Rmask, + _hwscreen->format->Gmask, + _hwscreen->format->Bmask, + _hwscreen->format->Amask); + } tmpSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, _screenWidth, // 320x256 texture (black end) @@ -162,12 +251,17 @@ void OSystem_SDL_OpenGL::load_gfx_mode() { } void OSystem_SDL_OpenGL::unload_gfx_mode() { + SDL_SetGamma(1.0, 1.0, 1.0); + if (_screen) { SDL_FreeSurface(_screen); _screen = NULL; } - + if (_hwscreen) { + SDL_FreeSurface(_hwscreen); + _hwscreen = NULL; + } if (_tmpscreen) { free((uint16 *)_tmpscreen->pixels); SDL_FreeSurface(_tmpscreen); @@ -185,8 +279,14 @@ void OSystem_SDL_OpenGL::hotswap_gfx_mode() { SDL_Surface *old_tmpscreen = _tmpscreen; // Release the HW screen surface - SDL_FreeSurface(fb2gl.getScreen()); - fb2gl.setScreen(NULL); + if (fb2gl.getScreen()) { // _usingOpenGL was true + SDL_FreeSurface(fb2gl.getScreen()); + fb2gl.setScreen(NULL); + } + if (_hwscreen) { + SDL_FreeSurface(_hwscreen); + _hwscreen = NULL; + } // Setup the new GFX mode load_gfx_mode(); @@ -210,10 +310,21 @@ void OSystem_SDL_OpenGL::hotswap_gfx_mode() { void OSystem_SDL_OpenGL::update_screen() { // If the shake position changed, fill the dirty area with blackness if (_currentShakePos != _newShakePos) { - SDL_Rect blackrect = {0, _glScreenStart, _screenWidth, _newShakePos+_glScreenStart}; + if (_usingOpenGL) { + SDL_Rect blackrect = { + 0, + _glScreenStart, + _screenWidth, + _newShakePos + _glScreenStart + }; - SDL_FillRect(tmpSurface, &blackrect, 0); - fb2gl.blit16(tmpSurface, 1, &blackrect, 0, 0); + SDL_FillRect(tmpSurface, &blackrect, 0); + fb2gl.blit16(tmpSurface, 1, &blackrect, 0, 0); + } + else { // SDL backend + SDL_Rect blackrect = {0, 0, _screenWidth * _scaleFactor, _newShakePos * _scaleFactor}; + SDL_FillRect(_hwscreen, &blackrect, 0); + } _currentShakePos = _newShakePos; @@ -249,45 +360,141 @@ void OSystem_SDL_OpenGL::update_screen() { if (_num_dirty_rects > 0) { SDL_Rect *r; + uint32 srcPitch, dstPitch; SDL_Rect *last_rect = _dirty_rect_list + _num_dirty_rects; - + // Convert appropriate parts of the 8bpp image into 16bpp + SDL_Rect dst; if (!_overlayVisible) { - SDL_Rect dst; for(r = _dirty_rect_list; r != last_rect; ++r) { dst = *r; -// dst.x++; // Shift rect by one since 2xSai needs to acces the data around -// dst.y++; // any pixel to scale it, and we want to avoid mem access crashes. - if (SDL_BlitSurface(_screen, r, _tmpscreen, &dst) != 0) + dst.x++; // Shift rect by one since 2xSai needs to acces the data around + dst.y++; // any pixel to scale it, and we want to avoid mem access crashes. + if (_scaler_proc == Normal1x) { + if (_usingOpenGL) { + if (SDL_BlitSurface(_screen, r, _tmpscreen, &dst) != 0) + error("SDL_BlitSurface failed: %s", SDL_GetError()); + } + else { // SDL backend + if (SDL_BlitSurface(_screen, r, _hwscreen, &dst) != 0) + error("SDL_BlitSurface failed: %s", SDL_GetError()); + } + } else { // _scaler_proc != Normal1x + if (SDL_BlitSurface(_screen, r, _tmpscreen, &dst) != 0) + error("SDL_BlitSurface failed: %s", SDL_GetError()); + } + } + } else { + if (!_usingOpenGL) { + for(r = _dirty_rect_list; r != last_rect; ++r) { + dst = *r; + if (SDL_BlitSurface(_tmpscreen, r, _hwscreen, &dst) != 0) error("SDL_BlitSurface failed: %s", SDL_GetError()); } + } } - // Almost the same thing as SDL_UpdateRects - fb2gl.blit16(_tmpscreen, _num_dirty_rects, _dirty_rect_list, 0, - _currentShakePos+_glScreenStart); - - int _glBottomOfGameScreen = _screenHeight + _glScreenStart + _currentShakePos; - // Bottom black border height - tmpBlackRect.h = _glBottomOfTexture - _glBottomOfGameScreen; - if (!(_full_screen) && (tmpBlackRect.h > 0)) { - SDL_FillRect(tmpSurface, &tmpBlackRect, 0); - fb2gl.blit16(tmpSurface, 1, &tmpBlackRect, 0, - _glBottomOfGameScreen); + if (_usingOpenGL) { + // Almost the same thing as SDL_UpdateRects + fb2gl.blit16( + _tmpscreen, + _num_dirty_rects, + _dirty_rect_list, + 0, + _currentShakePos + _glScreenStart + ); + + int _glBottomOfGameScreen = _screenHeight + + _glScreenStart + _currentShakePos; + + // Bottom black border height + tmpBlackRect.h = _glBottomOfTexture - _glBottomOfGameScreen; + if (!(_full_screen) && (tmpBlackRect.h > 0)) { + SDL_FillRect(tmpSurface, &tmpBlackRect, 0); + fb2gl.blit16(tmpSurface, 1, &tmpBlackRect, 0, + _glBottomOfGameScreen); + } + + fb2gl.display(); } + else { // SDL backend + + if (_scaler_proc != Normal1x) { + SDL_LockSurface(_tmpscreen); + SDL_LockSurface(_hwscreen); - fb2gl.display(); - } + srcPitch = _tmpscreen->pitch; + dstPitch = _hwscreen->pitch; + + for(r = _dirty_rect_list; r != last_rect; ++r) { + register int dst_y = r->y + _currentShakePos; + register int dst_h = 0; + if (dst_y < _screenHeight) { + dst_h = r->h; + if (dst_h > _screenHeight - dst_y) + dst_h = _screenHeight - dst_y; + + dst_y *= _scaleFactor; + + _scaler_proc((byte *)_tmpscreen->pixels + (r->x * 2 + 2) + (r->y + 1) * srcPitch, srcPitch, NULL, + (byte *)_hwscreen->pixels + r->x * 2 * _scaleFactor + dst_y * dstPitch, dstPitch, r->w, dst_h); + } + + r->x *= _scaleFactor; + r->y = dst_y; + r->w *= _scaleFactor; + r->h = dst_h * _scaleFactor; + } + + SDL_UnlockSurface(_tmpscreen); + SDL_UnlockSurface(_hwscreen); + } + + // Readjust the dirty rect list in case we are doing a full update. + // This is necessary if shaking is active. + if (_forceFull) { + _dirty_rect_list[0].y = 0; + _dirty_rect_list[0].h = _screenHeight * _scaleFactor; + } + + // Finally, blit all our changes to the screen + SDL_UpdateRects(_hwscreen, _num_dirty_rects, _dirty_rect_list); + } // END OF "SDL backend" + } // if (num_dirty_rects > 0) ... _num_dirty_rects = 0; _forceFull = false; } +/* +bool OSystem_SDL_OpenGL::poll_event(Event *event) { + SDL_Event ev; + ev.type = 0; + + SDL_PeepEvents(&ev, 1, SDL_GETEVENT, SDL_VIDEORESIZEMASK); + + if (ev.type == SDL_VIDEORESIZE) { + int w = ev.resize.w; + int h = ev.resize.h; + glViewport(0, 0, (GLsizei)w, (GLsizei)h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0); + _glWindow.w = w; + _glWindow.h = h; + } + + return OSystem_SDL_Common::poll_event(event); +} +*/ + uint32 OSystem_SDL_OpenGL::property(int param, Property *value) { int i; if (param == PROP_TOGGLE_FULLSCREEN) { + if (!_usingOpenGL) + assert(_hwscreen != 0); _full_screen ^= true; #ifdef MACOSX // On OS X, SDL_WM_ToggleFullScreen is currently not implemented. Worse, @@ -295,7 +502,15 @@ uint32 OSystem_SDL_OpenGL::property(int param, Property *value) { // use hotswap_gfx_mode() directly to switch to fullscreen mode. hotswap_gfx_mode(); #else - if (!SDL_WM_ToggleFullScreen(fb2gl.getScreen())) { + SDL_Surface *_tmpScreen; + if (_usingOpenGL) { + _tmpScreen = fb2gl.getScreen(); + } + else { // SDL backend + _tmpScreen = _hwscreen; + } + + if (!SDL_WM_ToggleFullScreen(_tmpScreen)) { // if ToggleFullScreen fails, achieve the same effect with hotswap gfx mode hotswap_gfx_mode(); } @@ -305,23 +520,46 @@ uint32 OSystem_SDL_OpenGL::property(int param, Property *value) { } else if (param == PROP_SET_GFX_MODE) { SDL_Rect full = {0, 0, _screenWidth, _screenHeight}; - glPopMatrix(); + if (value->gfx_mode < 3) { // OpenGL modes + if (!_usingOpenGL) { + _usingOpenGL = true; + _mode = GFX_NORMAL; + hotswap_gfx_mode(); + } + } + switch(value->gfx_mode) { case 0: // Bilinear Filtering (on/off) _glBilinearFilter ^= true; for (i = 0; i < 2; i++) { glBindTexture(GL_TEXTURE_2D, i); if (_glBilinearFilter) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri( + GL_TEXTURE_2D, + GL_TEXTURE_MAG_FILTER, + GL_LINEAR + ); + glTexParameteri( + GL_TEXTURE_2D, + GL_TEXTURE_MIN_FILTER, + GL_LINEAR + ); } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri( + GL_TEXTURE_2D, + GL_TEXTURE_MAG_FILTER, + GL_NEAREST + ); + glTexParameteri( + GL_TEXTURE_2D, + GL_TEXTURE_MIN_FILTER, + GL_NEAREST + ); } } break; - case 1: // Don't use the whole screen + case 1: // Don't use the whole screen (black borders) fb2gl.init(0, 0, 0, 15, _glFlags); _glScreenStart = 20; SDL_FillRect(tmpSurface, &tmpBlackRect, 0); @@ -331,25 +569,26 @@ uint32 OSystem_SDL_OpenGL::property(int param, Property *value) { fb2gl.init(0, 0, 0, 70, _glFlags); _glScreenStart = 0; break; - default: // Zooming - glPushMatrix(); -/* SDL_FillRect(tmpSurface, &full, 0); - fb2gl.blit16(tmpSurface, 1, &full,0, _glScreenStart); - fb2gl.display(); - double x = (double)((_mouseCurState.x) - - (_screenWidth / 2)) / (_screenWidth / 2); - double y = (double)((_mouseCurState.y) - - (_screenHeight / 2)) / (_screenHeight / 2); - glTranslatef(-x, y, 0); -*/ - glScalef(1.0 + (double)(value->gfx_mode - 1) / 10, - 1.0 + (double)(value->gfx_mode - 1) / 10, 0); + default: // SDL backend + if (value->gfx_mode >= 9) + return 0; + + _mode = value->gfx_mode; + + if (_usingOpenGL) + _usingOpenGL = false; + + hotswap_gfx_mode(); }; - fb2gl.blit16(_tmpscreen, 1, &full, 0, _glScreenStart); - fb2gl.display(); + + if (_usingOpenGL) { + fb2gl.blit16(_tmpscreen, 1, &full, 0, _glScreenStart); + fb2gl.display(); + } return 1; } return OSystem_SDL_Common::property(param, value); } + |