aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Horn2003-06-22 11:55:40 +0000
committerMax Horn2003-06-22 11:55:40 +0000
commit11ff7fe9a347efe37e2bd8fefca7e8c130f81af0 (patch)
tree037c8edce6a559e5816b7733727305ff66cc49cf
parentfa184730af2f2be094aa9f37cd3abf58d10f79ea (diff)
downloadscummvm-rg350-11ff7fe9a347efe37e2bd8fefca7e8c130f81af0.tar.gz
scummvm-rg350-11ff7fe9a347efe37e2bd8fefca7e8c130f81af0.tar.bz2
scummvm-rg350-11ff7fe9a347efe37e2bd8fefca7e8c130f81af0.zip
Patch #757827: Aspect-ratio correction
svn-id: r8605
-rw-r--r--README67
-rw-r--r--backends/sdl/sdl-common.cpp44
-rw-r--r--backends/sdl/sdl-common.h6
-rw-r--r--backends/sdl/sdl.cpp34
-rw-r--r--backends/sdl/sdl_gl.cpp53
-rw-r--r--common/gameDetector.cpp56
-rw-r--r--common/gameDetector.h1
-rw-r--r--common/scaler.cpp102
-rw-r--r--common/scaler.h10
-rw-r--r--common/system.h5
10 files changed, 267 insertions, 111 deletions
diff --git a/README b/README
index 7bba62e258..30f140988c 100644
--- a/README
+++ b/README
@@ -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();