diff options
author | Max Horn | 2003-06-22 11:55:40 +0000 |
---|---|---|
committer | Max Horn | 2003-06-22 11:55:40 +0000 |
commit | 11ff7fe9a347efe37e2bd8fefca7e8c130f81af0 (patch) | |
tree | 037c8edce6a559e5816b7733727305ff66cc49cf | |
parent | fa184730af2f2be094aa9f37cd3abf58d10f79ea (diff) | |
download | scummvm-rg350-11ff7fe9a347efe37e2bd8fefca7e8c130f81af0.tar.gz scummvm-rg350-11ff7fe9a347efe37e2bd8fefca7e8c130f81af0.tar.bz2 scummvm-rg350-11ff7fe9a347efe37e2bd8fefca7e8c130f81af0.zip |
Patch #757827: Aspect-ratio correction
svn-id: r8605
-rw-r--r-- | README | 67 | ||||
-rw-r--r-- | backends/sdl/sdl-common.cpp | 44 | ||||
-rw-r--r-- | backends/sdl/sdl-common.h | 6 | ||||
-rw-r--r-- | backends/sdl/sdl.cpp | 34 | ||||
-rw-r--r-- | backends/sdl/sdl_gl.cpp | 53 | ||||
-rw-r--r-- | common/gameDetector.cpp | 56 | ||||
-rw-r--r-- | common/gameDetector.h | 1 | ||||
-rw-r--r-- | common/scaler.cpp | 102 | ||||
-rw-r--r-- | common/scaler.h | 10 | ||||
-rw-r--r-- | common/system.h | 5 |
10 files changed, 267 insertions, 111 deletions
@@ -339,33 +339,36 @@ Command Line Options: scummvm [OPTIONS] [GAME] - [GAME] - Short name of game to load. For example, 'monkey' for - Monkey Island. - - -p<path> - Path to where the game is installed. Default is Cwd. - -x[<num>] - Save game slot to load (default: autosave) - -f - Full-screen mode. - -g<mode> - Select graphics scaler. See below. - -e<mode> - Select sound engine. See below. - -a - Enable amiga pal conversion, for playing Amiga versions - -q<lang> - Select language. See below. - -c<num> - Drive to play cd audio from. E.g., 0 is first drive. - -m<num> - Set the music volume, 0-255. Default is '192' - -o<num> - Set the master volume, 0-255. Default is '192' - -s<num> - Set the sfx volume, 0-255. Default is '192' - -t<num> - Set music tempo. 50-200. Default is '100' (percent) - -n - Disable subtitles. Use with games that have voice. - -y - Set talk speed ('yak option'). Default is '60' - -l<file> - Load alternate configuration file - -w[<file>] - Write configuration file - -v - Show version information and exit - -z - Display list of games - -b<num> - Start in room <num>. - -d[<num>] - Set debug verbosity to <num> - -u - Dump scripts if a directory called 'dumps' exists in - current directory - --multi-midi - enable combination Adlib and native MIDI - --native-mt32 - true Roland MT-32 (disable GM emulation) + [GAME] - Short name of game to load. For example, 'monkey' for + Monkey Island. + + -p<path> - Path to where the game is installed. Default is Cwd. + -x[<num>] - Save game slot to load (default: autosave) + -f - Full-screen mode. + -g<mode> - Select graphics scaler. See below. + -e<mode> - Select sound engine. See below. + -a - Enable amiga pal conversion, for playing Amiga + versions + -q<lang> - Select language. See below. + -c<num> - Drive to play cd audio from. E.g., 0 is first drive. + -m<num> - Set the music volume, 0-255. Default is '192' + -o<num> - Set the master volume, 0-255. Default is '192' + -s<num> - Set the sfx volume, 0-255. Default is '192' + -t<num> - Set music tempo. 50-200. Default is '100' (percent) + -n - Disable subtitles. Use with games that have voice. + -y - Set talk speed ('yak option'). Default is '60' + -l<file> - Load alternate configuration file + -w[<file>] - Write configuration file + -v - Show version information and exit + -z - Display list of games + -b<num> - Start in room <num>. + -d[<num>] - Set debug verbosity to <num> + -u - Dump scripts if a directory called 'dumps' exists in + current directory + --multi-midi - enable combination Adlib and native MIDI + --native-mt32 - true Roland MT-32 (disable GM emulation) + --aspect-ratio - enable aspect ratio correction + Hot Keys: @@ -380,9 +383,13 @@ simon games. Ctrl-Alt 0-9 - Switch between graphics filters Ctrl-Alt b - Switch beetwen bilinear and non-linear filtering [OpenGL backend] - Ctrl-Alt a - Switch between: [OpenGL backend] - - Fit the game in the whole screen (No black borders) - - Don't fit the game in the whole screen (Black borders) + Ctrl-Alt a - Toggle aspect-ratio correction on/off. + Most of the games use a 320x200 pixel + resolution, which may look squashed on + modern monitors. Aspect-ratio correction + stretches the image to use 320x240 pixels + instead, or a multiple thereof. + Scumm: Ctrl 0-9 and Alt 0-9 - load and save game state Ctrl-g - runs in really REALLY fast mode. diff --git a/backends/sdl/sdl-common.cpp b/backends/sdl/sdl-common.cpp index 1095d4b68f..cd3b99430c 100644 --- a/backends/sdl/sdl-common.cpp +++ b/backends/sdl/sdl-common.cpp @@ -41,22 +41,23 @@ #define JOY_BUT_SPACE 4 #define JOY_BUT_F5 5 -OSystem *OSystem_SDL_create(int gfx_mode, bool full_screen) { - return OSystem_SDL_Common::create(gfx_mode, full_screen); +OSystem *OSystem_SDL_create(int gfx_mode, bool full_screen, bool aspect_ratio) { + return OSystem_SDL_Common::create(gfx_mode, full_screen, aspect_ratio); } -OSystem *OSystem_SDL_Common::create(int gfx_mode, bool full_screen) { +OSystem *OSystem_SDL_Common::create(int gfx_mode, bool full_screen, bool aspect_ratio) { OSystem_SDL_Common *syst = OSystem_SDL_Common::create_intern(); - syst->init_intern(gfx_mode, full_screen); + syst->init_intern(gfx_mode, full_screen, aspect_ratio); return syst; } -void OSystem_SDL_Common::init_intern(int gfx_mode, bool full_screen) { +void OSystem_SDL_Common::init_intern(int gfx_mode, bool full_screen, bool aspect_ratio) { _mode = gfx_mode; _full_screen = full_screen; + _adjustAspectRatio = aspect_ratio; if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK) ==-1) { error("Could not initialize SDL: %s.\n", SDL_GetError()); @@ -129,6 +130,10 @@ void OSystem_SDL_Common::init_size(uint w, uint h) { _screenWidth = w; _screenHeight = h; + + if (h != 200) + _adjustAspectRatio = false; + CKSUM_NUM = (_screenWidth * _screenHeight / (8 * 8)); if (_dirty_checksums) free(_dirty_checksums); @@ -576,20 +581,18 @@ bool OSystem_SDL_Common::poll_event(Event *event) { } } - // Ctr-Alt-a will change aspect ratio in OpenGL backend + // Ctr-Alt-a will change aspect ratio if (b == (KBD_CTRL|KBD_ALT) && ev.key.keysym.sym=='a') { - Property prop; - prop.gfx_mode = 11; - property(PROP_SET_GFX_MODE, &prop); - break; + property(PROP_TOGGLE_ASPECT_RATIO, NULL); + break; } // Ctr-Alt-b will change bilinear filtering in OpenGL backend if (b == (KBD_CTRL|KBD_ALT) && ev.key.keysym.sym=='b') { - Property prop; - prop.gfx_mode = 12; - property(PROP_SET_GFX_MODE, &prop); - break; + Property prop; + prop.gfx_mode = GFX_BILINEAR; + property(PROP_SET_GFX_MODE, &prop); + break; } #ifdef QTOPIA @@ -698,6 +701,8 @@ bool OSystem_SDL_Common::poll_event(Event *event) { event->mouse.x /= _scaleFactor; event->mouse.y /= _scaleFactor; + if (_adjustAspectRatio) + event->mouse.y = aspect2Real(event->mouse.y); return true; case SDL_MOUSEBUTTONDOWN: @@ -718,6 +723,9 @@ bool OSystem_SDL_Common::poll_event(Event *event) { event->mouse.x /= _scaleFactor; event->mouse.y /= _scaleFactor; + if (_adjustAspectRatio) + event->mouse.y = aspect2Real(event->mouse.y); + return true; case SDL_MOUSEBUTTONUP: @@ -731,6 +739,10 @@ bool OSystem_SDL_Common::poll_event(Event *event) { event->mouse.y = ev.button.y; event->mouse.x /= _scaleFactor; event->mouse.y /= _scaleFactor; + + if (_adjustAspectRatio) + event->mouse.y = aspect2Real(event->mouse.y); + return true; case SDL_JOYBUTTONDOWN: @@ -835,6 +847,10 @@ bool OSystem_SDL_Common::poll_event(Event *event) { event->mouse.y = km.y; event->mouse.x /= _scaleFactor; event->mouse.y /= _scaleFactor; + + if (_adjustAspectRatio) + event->mouse.y = aspect2Real(event->mouse.y); + return true; case SDL_VIDEOEXPOSE: diff --git a/backends/sdl/sdl-common.h b/backends/sdl/sdl-common.h index c5e6847ffa..9c4bf91ab7 100644 --- a/backends/sdl/sdl-common.h +++ b/backends/sdl/sdl-common.h @@ -123,7 +123,7 @@ public: virtual int16 RGBToColor(uint8 r, uint8 g, uint8 b); virtual void colorToRGB(int16 color, uint8 &r, uint8 &g, uint8 &b); - static OSystem *create(int gfx_mode, bool full_screen); + static OSystem *create(int gfx_mode, bool full_screenm, bool aspect_ratio); protected: OSystem_SDL_Common(); @@ -131,7 +131,7 @@ protected: static OSystem_SDL_Common *create_intern(); - void init_intern(int gfx_mode, bool full_screen); + void init_intern(int gfx_mode, bool full_screen, bool aspect_ratio); // unseen game screen SDL_Surface *_screen; @@ -142,6 +142,8 @@ protected: int _tmpScreenWidth; bool _overlayVisible; + bool _adjustAspectRatio; + // CD Audio SDL_CD *_cdrom; int cd_track, cd_num_loops, cd_start_frame, cd_end_frame; diff --git a/backends/sdl/sdl.cpp b/backends/sdl/sdl.cpp index 2caa4d2d67..ecb00cd2d8 100644 --- a/backends/sdl/sdl.cpp +++ b/backends/sdl/sdl.cpp @@ -147,12 +147,13 @@ normal_mode:; // // Create the surface that contains the scaled graphics in 16 bit mode // - _hwscreen = SDL_SetVideoMode(_screenWidth * _scaleFactor, _screenHeight * _scaleFactor, 16, + + _hwscreen = SDL_SetVideoMode(_screenWidth * _scaleFactor, (_adjustAspectRatio ? 240 : _screenHeight) * _scaleFactor, 16, _full_screen ? (SDL_FULLSCREEN|SDL_SWSURFACE) : SDL_SWSURFACE ); if (_hwscreen == NULL) error("_hwscreen failed"); - + // // Create the surface used for the graphics in 16 bit before scaling, and also the overlay // @@ -192,7 +193,7 @@ void OSystem_SDL::unload_gfx_mode() { SDL_FreeSurface(_hwscreen); _hwscreen = NULL; } - + if (_tmpscreen) { free(_tmpscreen->pixels); SDL_FreeSurface(_tmpscreen); @@ -281,7 +282,7 @@ void OSystem_SDL::update_screen() { uint32 srcPitch, dstPitch; SDL_Rect *last_rect = _dirty_rect_list + _num_dirty_rects; - if (_scaler_proc == Normal1x) { + if (_scaler_proc == Normal1x && !_adjustAspectRatio) { SDL_Surface *target = _overlayVisible ? _tmpscreen : _screen; for (r = _dirty_rect_list; r != last_rect; ++r) { dst = *r; @@ -314,23 +315,32 @@ void OSystem_SDL::update_screen() { for (r = _dirty_rect_list; r != last_rect; ++r) { register int dst_y = r->y + _currentShakePos; register int dst_h = 0; + register int orig_dst_y = 0; + if (dst_y < _screenHeight) { dst_h = r->h; if (dst_h > _screenHeight - dst_y) dst_h = _screenHeight - dst_y; - dst_y *= _scaleFactor; + dst_y *= _scaleFactor; - _scaler_proc((byte *)_tmpscreen->pixels + (r->x * 2 + 2) + (r->y + 1) * srcPitch, srcPitch, + if (_adjustAspectRatio) { + orig_dst_y = dst_y; + dst_y = real2Aspect(dst_y); + } + + _scaler_proc((byte *)_tmpscreen->pixels + (r->x * 2 + 2) + (r->y + 1) * srcPitch, srcPitch, (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; - } + if (_adjustAspectRatio && orig_dst_y / _scaleFactor < _screenHeight) + r->h = stretch200To240((uint8 *) _hwscreen->pixels, dstPitch, r->w, r->h, r->x, r->y, orig_dst_y); + } SDL_UnlockSurface(_tmpscreen); SDL_UnlockSurface(_hwscreen); } @@ -339,7 +349,7 @@ void OSystem_SDL::update_screen() { // This is necessary if shaking is active. if (_forceFull) { _dirty_rect_list[0].y = 0; - _dirty_rect_list[0].h = _screenHeight * _scaleFactor; + _dirty_rect_list[0].h = (_adjustAspectRatio ? 240 : _screenHeight) * _scaleFactor; } // Finally, blit all our changes to the screen @@ -374,6 +384,12 @@ uint32 OSystem_SDL::property(int param, Property *value) { hotswap_gfx_mode(); return 1; + } else if (param == PROP_TOGGLE_ASPECT_RATIO) { + if (_screenHeight == 200) { + assert(_hwscreen != 0); + _adjustAspectRatio ^= true; + hotswap_gfx_mode(); + } } return OSystem_SDL_Common::property(param, value); diff --git a/backends/sdl/sdl_gl.cpp b/backends/sdl/sdl_gl.cpp index d29029ddfe..949baf7b1d 100644 --- a/backends/sdl/sdl_gl.cpp +++ b/backends/sdl/sdl_gl.cpp @@ -54,7 +54,6 @@ protected: int _glFlags; int _glScreenStart; bool _glBilinearFilter; - bool _glAspectRatio; bool _usingOpenGL; SDL_Surface *tmpSurface; // Used for black rectangles blitting SDL_Rect tmpBlackRect; // Black rectangle at end of the GL screen @@ -79,7 +78,6 @@ OSystem_SDL_OpenGL::OSystem_SDL_OpenGL() { _glScreenStart = 0; _glBilinearFilter = true; - _glAspectRatio = false; _usingOpenGL = false; // false => Switch to filters used in the sdl.cpp version _glBottomOfTexture = 256; // height is always 256 // 640x480 resolution @@ -165,7 +163,7 @@ void OSystem_SDL_OpenGL::load_gfx_mode() { case GFX_NORMAL: normal_mode:; - _scaleFactor = 1; + _scaleFactor = _usingOpenGL ? 2 : 1; _scaler_proc = Normal1x; break; default: @@ -199,8 +197,7 @@ normal_mode:; fb2gl.init(_glWindow.w, _glWindow.h, 0, _glScreenStart? 15: 70, _glFlags); - } - else { // SDL backend + } else { // SDL backend _hwscreen = SDL_SetVideoMode(_screenWidth * _scaleFactor, _screenHeight * _scaleFactor, 16, _full_screen ? (SDL_FULLSCREEN|SDL_SWSURFACE) : SDL_SWSURFACE @@ -234,8 +231,7 @@ normal_mode:; Gmask, Bmask, Amask); - } - else { // SDL backend + } else { // SDL backend _tmpscreen = SDL_CreateRGBSurfaceFrom(tmp_screen, _tmpScreenWidth, _screenHeight + 3, @@ -346,8 +342,7 @@ void OSystem_SDL_OpenGL::update_screen() { SDL_FillRect(tmpSurface, &blackrect, 0); fb2gl.blit16(tmpSurface, 1, &blackrect, 0, 0); - } - else { // SDL backend + } else { // SDL backend SDL_Rect blackrect = {0, 0, _screenWidth * _scaleFactor, _newShakePos * _scaleFactor}; SDL_FillRect(_hwscreen, &blackrect, 0); } @@ -545,9 +540,30 @@ uint32 OSystem_SDL_OpenGL::property(int param, Property *value) { #endif return 1; - } - else if (param == PROP_SET_GFX_MODE) { + } else if (param == PROP_TOGGLE_ASPECT_RATIO) { + if (!_usingOpenGL) { + _usingOpenGL = true; + _mode = GFX_NORMAL; + hotswap_gfx_mode(); + } + + _adjustAspectRatio ^= true; + if (_adjustAspectRatio) { + // Don't use the whole screen (black borders) + fb2gl.init(0, 0, 0, 15, _glFlags); + _glScreenStart = 20; + SDL_FillRect(tmpSurface, &tmpBlackRect, 0); + fb2gl.blit16(tmpSurface, 1, &tmpBlackRect, 0, 0); + } else { + // Use the whole screen + fb2gl.init(0, 0, 0, 70, _glFlags); + _glScreenStart = 0; + } + SDL_Rect full = {0, 0, _screenWidth, _screenHeight}; + fb2gl.blit16(_tmpscreen, 1, &full, 0, _glScreenStart); + fb2gl.display(); + } else if (param == PROP_SET_GFX_MODE) { if (value->gfx_mode > 10) { // OpenGL modes if (!_usingOpenGL) { @@ -562,20 +578,6 @@ uint32 OSystem_SDL_OpenGL::property(int param, Property *value) { _glBilinearFilter ^= true; fb2gl.setBilinearMode(_glBilinearFilter); break; - case GFX_ASPECTRATIO: - _glAspectRatio ^= true; - if (_glAspectRatio) { - // Don't use the whole screen (black borders) - fb2gl.init(0, 0, 0, 15, _glFlags); - _glScreenStart = 20; - SDL_FillRect(tmpSurface, &tmpBlackRect, 0); - fb2gl.blit16(tmpSurface, 1, &tmpBlackRect, 0, 0); - } else { - // Use the whole screen - fb2gl.init(0, 0, 0, 70, _glFlags); - _glScreenStart = 0; - } - break; default: // SDL backend if (value->gfx_mode >= 10) return 0; @@ -589,6 +591,7 @@ uint32 OSystem_SDL_OpenGL::property(int param, Property *value) { }; if (_usingOpenGL) { + SDL_Rect full = {0, 0, _screenWidth, _screenHeight}; fb2gl.blit16(_tmpscreen, 1, &full, 0, _glScreenStart); fb2gl.display(); } diff --git a/common/gameDetector.cpp b/common/gameDetector.cpp index 3cd1a742cb..a4841ed72b 100644 --- a/common/gameDetector.cpp +++ b/common/gameDetector.cpp @@ -50,38 +50,39 @@ static const char USAGE_STRING[] = "Syntax:\n" "\tscummvm [-v] [-d[<num>]] [-n] [-b<num>] [-t<num>] [-s<num>] [-p<path>] [-m<num>] [-f] game\n" "Flags:\n" - "\t-p<path> - look for game in <path>\n" - "\t-x[<num>] - load this savegame (default: 0 - autosave)\n" - "\t-f - fullscreen mode\n" - "\t-g<mode> - graphics mode (normal,2x,3x,2xsai,super2xsai,supereagle,advmame2x,advmame3x,tv2x,dotmatrix)\n" - "\t-e<mode> - set music engine (see README for details)\n" - "\t-a - specify game is amiga version\n" - "\t-q<lang> - specify language (en,de,fr,it,pt,es,jp,zh,kr,hb)\n" + "\t-p<path> - look for game in <path>\n" + "\t-x[<num>] - load this savegame (default: 0 - autosave)\n" + "\t-f - fullscreen mode\n" + "\t-g<mode> - graphics mode (normal,2x,3x,2xsai,super2xsai,supereagle,advmame2x,advmame3x,tv2x,dotmatrix)\n" + "\t-e<mode> - set music engine (see README for details)\n" + "\t-a - specify game is amiga version\n" + "\t-q<lang> - specify language (en,de,fr,it,pt,es,jp,zh,kr,hb)\n" "\n" - "\t-c<num> - use cdrom <num> for cd audio\n" - "\t-m<num> - set music volume to <num> (0-255)\n" - "\t-o<num> - set master volume to <num> (0-255)\n" - "\t-s<num> - set sfx volume to <num> (0-255)\n" - "\t-t<num> - set music tempo (50-200, default 100%%)\n" + "\t-c<num> - use cdrom <num> for cd audio\n" + "\t-m<num> - set music volume to <num> (0-255)\n" + "\t-o<num> - set master volume to <num> (0-255)\n" + "\t-s<num> - set sfx volume to <num> (0-255)\n" + "\t-t<num> - set music tempo (50-200, default 100%%)\n" "\n" - "\t-n - no subtitles for speech\n" - "\t-y - set text speed (default: 60)\n" + "\t-n - no subtitles for speech\n" + "\t-y - set text speed (default: 60)\n" "\n" - "\t-l<file> - load config file instead of default\n" + "\t-l<file> - load config file instead of default\n" #if defined(UNIX) - "\t-w[<file>] - write to config file [~/.scummvmrc]\n" + "\t-w[<file>] - write to config file [~/.scummvmrc]\n" #else - "\t-w[<file>] - write to config file [scummvm.ini]\n" + "\t-w[<file>] - write to config file [scummvm.ini]\n" #endif - "\t-v - show version info and exit\n" - "\t-z - display list of games\n" + "\t-v - show version info and exit\n" + "\t-z - display list of games\n" "\n" - "\t-b<num> - start in room <num>\n" - "\t-d[<num>] - enable debug output (debug level [1])\n" - "\t-u - dump scripts\n" + "\t-b<num> - start in room <num>\n" + "\t-d[<num>] - enable debug output (debug level [1])\n" + "\t-u - dump scripts\n" "\n" - "\t--multi-midi - enable combination Adlib and native MIDI\n" - "\t--native-mt32 - true Roland MT-32 (disable GM emulation)\n" + "\t--multi-midi - enable combination Adlib and native MIDI\n" + "\t--native-mt32 - true Roland MT-32 (disable GM emulation)\n" + "\t--aspect-ratio - enable aspect ratio correction\n" ; #endif // This contains a pointer to a list of all supported games. @@ -148,6 +149,7 @@ static int countVersions(const VersionSettings *v) { GameDetector::GameDetector() { _fullScreen = false; + _aspectRatio = false; _use_adlib = false; @@ -245,6 +247,7 @@ void GameDetector::updateconfig() { } _fullScreen = g_config->getBool("fullscreen", _fullScreen); + _aspectRatio = g_config->getBool("aspect_ratio", _aspectRatio); if ((val = g_config->get("gfx_mode"))) if ((_gfx_mode = parseGraphicsMode(val)) == -1) { @@ -453,6 +456,9 @@ void GameDetector::parseCommandLine(int argc, char **argv) { } else if (!strcmp (s, "native-mt32")) { _native_mt32 = true; g_config->setBool ("native_mt32", true); + } else if (!strcmp (s, "aspect-ratio")) { + _aspectRatio = true; + g_config->setBool ("aspect_ratio", true); } else { goto ShowHelpAndExit; } @@ -673,7 +679,7 @@ OSystem *GameDetector::createSystem() { return OSystem_PALMOS_create(_gfx_mode); #else /* SDL is the default driver for now */ - return OSystem_SDL_create(_gfx_mode, _fullScreen); + return OSystem_SDL_create(_gfx_mode, _fullScreen, _aspectRatio); #endif } diff --git a/common/gameDetector.h b/common/gameDetector.h index f73f20cd56..d9e5b104a5 100644 --- a/common/gameDetector.h +++ b/common/gameDetector.h @@ -110,6 +110,7 @@ public: const String& getGameName(void); bool _fullScreen; + bool _aspectRatio; bool _use_adlib; diff --git a/common/scaler.cpp b/common/scaler.cpp index 1607fef214..0d952110c1 100644 --- a/common/scaler.cpp +++ b/common/scaler.cpp @@ -30,7 +30,9 @@ static uint32 lowPixelMask = 0x08210821; static uint32 qcolorMask = 0xE79CE79C; static uint32 qlowpixelMask = 0x18631863; static uint32 redblueMask = 0xF81F; -static uint32 greenMask = 0x7E0; +static uint32 redMask = 0xF800; +static uint32 greenMask = 0x07E0; +static uint32 blueMask = 0x001F; static const uint16 dotmatrix_565[16] = { 0x01E0, 0x0007, 0x3800, 0x0000, @@ -53,7 +55,9 @@ int Init_2xSaI(uint32 BitFormat) { qcolorMask = 0xE79CE79C; qlowpixelMask = 0x18631863; redblueMask = 0xF81F; - greenMask = 0x7E0; + redMask = 0xF800; + greenMask = 0x07E0; + blueMask = 0x001F; dotmatrix = dotmatrix_565; } else if (BitFormat == 555) { colorMask = 0x7BDE7BDE; @@ -61,7 +65,9 @@ int Init_2xSaI(uint32 BitFormat) { qcolorMask = 0x739C739C; qlowpixelMask = 0x0C630C63; redblueMask = 0x7C1F; - greenMask = 0x3E0; + redMask = 0x7C00; + greenMask = 0x03E0; + blueMask = 0x001F; dotmatrix = dotmatrix_555; } else { return 0; @@ -634,3 +640,93 @@ void DotMatrix(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPi q += nextlineDst << 1; } } + + +static inline uint32 interpolate5(uint16 A, uint16 B, int scale) { + uint16 r = ((A & redMask) * scale + (B & redMask) * (5 - scale)) / 5; + uint16 g = ((A & greenMask) * scale + (B & greenMask) * (5 - scale)) / 5; + uint16 b = ((A & blueMask) * scale + (B & blueMask) * (5 - scale)) / 5; + + return (r & redMask) | (g & greenMask) | (b & blueMask); +} + +static inline void interpolate5Line(uint16 *dst, const uint16 *srcA, const uint16 *srcB, int scale, int width) { +#if 1 + // Accurate but slightly slower code + while (width--) { + *dst++ = interpolate5(*srcA++, *srcB++, scale); + } +#else + // Not fully accurate, but a bit faster + width /= 2; + const uint32 *sA = (const uint32 *)srcA; + const uint32 *sB = (const uint32 *)srcB; + uint32 *d = (uint32 *)dst; + if (scale == 1) { + while (width--) { + uint32 B = *sB++; + *d++ = Q_INTERPOLATE(*sA++, B, B, B); + } + } else { + while (width--) { + *d++ = INTERPOLATE(*sA++, *sB++); + } + } +#endif +} + +/** + * Stretch a 16bpp image vertically by factor 1.2. Used to correct the + * aspect-ratio in games using 320x200 pixel graphics with non-qudratic + * pixels. Applying this method effectively turns that into 320x240, which + * provides the correct aspect-ratio on modern displays. + * + * The image would normally have occupied y coordinates origSrcY through + * origSrcY + height - 1. + * + * However, we have already placed it at srcY - the aspect-corrected y + * coordinate - to allow in-place stretching. + * + * Therefore, the source image now occupies Y coordinates srcY through + * srcY + height - 1, and it should be stretched to Y coordinates srcY + * through real2Aspect(srcY + height - 1). + */ +int stretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY) { + int maxDstY = real2Aspect(origSrcY + height - 1); + int off = srcY - origSrcY; + int y; + + uint8 *dstPtr = buf + srcX * 2 + maxDstY * pitch; + + for (y = maxDstY; y >= srcY; y--) { + uint8 *srcPtr = buf + srcX * 2 + (aspect2Real(y) + off) * pitch; + + if (srcPtr == dstPtr) + break; + +#if 0 + // Don't use bilinear filtering, rather just duplicate pixel lines: + // a little bit faster, but looks ugly + memcpy(dstPtr, srcPtr, width * 2); +#else + // Bilinear filter + switch (y % 6) { + case 0: + case 5: + memcpy(dstPtr, srcPtr, width * 2); + break; + case 1: + case 4: + interpolate5Line((uint16 *)dstPtr, (uint16 *)(srcPtr - pitch), (uint16 *)srcPtr, 1, width); + break; + case 2: + case 3: + interpolate5Line((uint16 *)dstPtr, (uint16 *)(srcPtr - pitch), (uint16 *)srcPtr, 2, width); + break; + } +#endif + dstPtr -= pitch; + } + + return 1 + maxDstY - srcY; +} diff --git a/common/scaler.h b/common/scaler.h index e3246587c9..b8000ddccd 100644 --- a/common/scaler.h +++ b/common/scaler.h @@ -41,6 +41,15 @@ DECLARE_SCALER(Normal3x); DECLARE_SCALER(TV2x); DECLARE_SCALER(DotMatrix); +FORCEINLINE int real2Aspect(int y) { + return y + (y + 1) / 5; +} + +FORCEINLINE int aspect2Real(int y) { + return (y * 5 + 3) / 6; +} + +extern int stretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY); enum { GFX_NORMAL = 0, @@ -54,7 +63,6 @@ enum { GFX_TV2X = 8, GFX_DOTMATRIX = 9, - GFX_ASPECTRATIO = 11, // OpenGL backend GFX_BILINEAR = 12, // OpenGL backend GFX_FLIPPING = 100, // Palmos diff --git a/common/system.h b/common/system.h index 68408a6a13..32e55e4879 100644 --- a/common/system.h +++ b/common/system.h @@ -94,7 +94,8 @@ public: PROP_GET_SAMPLE_RATE = 6, PROP_GET_FULLSCREEN = 7, PROP_GET_FMOPL_ENV_BITS = 8, - PROP_GET_FMOPL_EG_ENT = 9 + PROP_GET_FMOPL_EG_ENT = 9, + PROP_TOGGLE_ASPECT_RATIO = 10 }; union Property { const char *caption; @@ -363,7 +364,7 @@ public: /* Factory functions. This means we don't have to include the headers for * all backends. */ -extern OSystem *OSystem_SDL_create(int gfx_driver, bool full_screen); +extern OSystem *OSystem_SDL_create(int gfx_driver, bool full_screen, bool aspect_ratio); extern OSystem *OSystem_NULL_create(); extern OSystem *OSystem_MorphOS_create(int game_id, int gfx_driver, bool full_screen); extern OSystem *OSystem_Dreamcast_create(); |