Ticket #8711: backends-lib.v2.patch

File backends-lib.v2.patch, 92.8 KB (added by SF/sbatyuk, 17 years ago)

common backend class patch v2

  • D:/programming/projects/gsoc/scummvm/backends/platform/common/common-system.h

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 */
     22
     23#ifndef SDL_COMMON_H
     24#define SDL_COMMON_H
     25
     26#include <SDL.h>
     27
     28#include "common/stdafx.h"
     29#include "common/scummsys.h"
     30#include "common/system.h"
     31#include "graphics/scaler.h"
     32#include "backends/intern.h"
     33
     34
     35namespace Audio {
     36        class Mixer;
     37}
     38
     39namespace Common {
     40        class SaveFileManager;
     41        class TimerManager;
     42}
     43
     44#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
     45// Uncomment this to enable the 'on screen display' code.
     46#define USE_OSD 1
     47#endif
     48
     49
     50enum {
     51        GFX_NORMAL = 0,
     52        GFX_DOUBLESIZE = 1,
     53        GFX_TRIPLESIZE = 2,
     54        GFX_2XSAI = 3,
     55        GFX_SUPER2XSAI = 4,
     56        GFX_SUPEREAGLE = 5,
     57        GFX_ADVMAME2X = 6,
     58        GFX_ADVMAME3X = 7,
     59        GFX_HQ2X = 8,
     60        GFX_HQ3X = 9,
     61        GFX_TV2X = 10,
     62        GFX_DOTMATRIX = 11
     63};
     64
     65
     66class OSystem_Common : public OSystem {
     67public:
     68        OSystem_Common();
     69        virtual ~OSystem_Common();
     70
     71        virtual void initBackend();
     72
     73        void beginGFXTransaction(void);
     74        void endGFXTransaction(void);
     75
     76        // Set the size of the video bitmap.
     77        // Typically, 320x200
     78        virtual void initSize(uint w, uint h); // overloaded by CE backend
     79
     80        virtual int getScreenChangeID() const { return _screenChangeCount; }
     81
     82        // Set colors of the palette
     83        void setPalette(const byte *colors, uint start, uint num);
     84
     85        // Get colors of the palette
     86        void grabPalette(byte *colors, uint start, uint num);
     87
     88        // Draw a bitmap to screen.
     89        // The screen will not be updated to reflect the new bitmap
     90        virtual void copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h); // overloaded by CE backend (FIXME)
     91
     92        virtual Graphics::Surface *lockScreen();
     93        virtual void unlockScreen();
     94
     95        // Update the dirty areas of the screen
     96        void updateScreen();
     97
     98        // Either show or hide the mouse cursor
     99        bool showMouse(bool visible);
     100
     101        // Warp the mouse cursor. Where set_mouse_pos() only informs the
     102        // backend of the mouse cursor's current position, this function
     103        // actually moves the cursor to the specified position.
     104        virtual void warpMouse(int x, int y); // overloaded by CE backend (FIXME)
     105
     106        // Set the bitmap that's used when drawing the cursor.
     107        virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale); // overloaded by CE backend (FIXME)
     108
     109        // Set colors of cursor palette
     110        void setCursorPalette(const byte *colors, uint start, uint num);
     111
     112        // Disables or enables cursor palette
     113        void disableCursorPalette(bool disable) {
     114                _cursorPaletteDisabled = disable;
     115                blitCursor();
     116        }
     117
     118        // Shaking is used in SCUMM. Set current shake position.
     119        void setShakePos(int shake_pos);
     120
     121        // Get the number of milliseconds since the program was started.
     122        uint32 getMillis();
     123
     124        // Delay for a specified amount of milliseconds
     125        void delayMillis(uint msecs);
     126
     127        // Get the next event.
     128        // Returns true if an event was retrieved.
     129        virtual bool pollEvent(Common::Event &event); // overloaded by CE backend
     130
     131        // Set function that generates samples
     132        typedef void (*SoundProc)(void *param, byte *buf, int len);
     133        virtual bool setSoundCallback(SoundProc proc, void *param); // overloaded by CE backend
     134        virtual Audio::Mixer *getMixer();
     135
     136        // Poll CD status
     137        // Returns true if cd audio is playing
     138        bool pollCD();
     139
     140        // Play CD audio track
     141        void playCD(int track, int num_loops, int start_frame, int duration);
     142
     143        // Stop CD audio track
     144        void stopCD();
     145
     146        // Update CD audio status
     147        void updateCD();
     148
     149        // Quit
     150        virtual void quit(); // overloaded by CE backend
     151
     152        virtual Common::TimerManager *getTimerManager();
     153
     154        // Mutex handling
     155        MutexRef createMutex();
     156        void lockMutex(MutexRef mutex);
     157        void unlockMutex(MutexRef mutex);
     158        void deleteMutex(MutexRef mutex);
     159
     160        // Overlay
     161        virtual void showOverlay(); // WinCE FIXME
     162        virtual void hideOverlay(); // WinCE FIXME
     163        virtual void clearOverlay();
     164        virtual void grabOverlay(OverlayColor *buf, int pitch);
     165        virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h); // WinCE FIXME
     166        virtual int16 getHeight();
     167        virtual int16 getWidth();
     168        virtual int16 getOverlayHeight()  { return _overlayHeight; }
     169        virtual int16 getOverlayWidth()   { return _overlayWidth; }
     170
     171        // Methods that convert RGB to/from colors suitable for the overlay.
     172        virtual OverlayColor RGBToColor(uint8 r, uint8 g, uint8 b);
     173        virtual void colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b);
     174
     175
     176        virtual const GraphicsMode *getSupportedGraphicsModes() const;
     177        virtual int getDefaultGraphicsMode() const;
     178        virtual bool setGraphicsMode(int mode);
     179        virtual int getGraphicsMode() const;
     180
     181        virtual void setWindowCaption(const char *caption);
     182        virtual bool openCD(int drive);
     183        virtual int getOutputSampleRate() const;
     184
     185        virtual bool hasFeature(Feature f);
     186        virtual void setFeatureState(Feature f, bool enable);
     187        virtual bool getFeatureState(Feature f);
     188
     189#ifdef USE_OSD
     190        void displayMessageOnOSD(const char *msg);
     191#endif
     192
     193        virtual Common::SaveFileManager *getSavefileManager();
     194
     195protected:
     196        bool _inited;
     197
     198#ifdef USE_OSD
     199        SDL_Surface *_osdSurface;
     200        Uint8 _osdAlpha;                        // Transparency level of the OSD
     201        uint32 _osdFadeStartTime;       // When to start the fade out
     202        enum {
     203                kOSDFadeOutDelay = 2 * 1000,    // Delay before the OSD is faded out (in milliseconds)
     204                kOSDFadeOutDuration = 500,              // Duration of the OSD fade out (in milliseconds)
     205                kOSDColorKey = 1,
     206                kOSDInitialAlpha = 80                   // Initial alpha level, in percent
     207        };
     208#endif
     209
     210        // hardware screen
     211        SDL_Surface *_hwscreen;
     212
     213        // unseen game screen
     214        SDL_Surface *_screen;
     215       
     216        // TODO: We could get rid of the following two vars and just use _screen instead
     217        int _screenWidth, _screenHeight;
     218
     219        // temporary screen (for scalers)
     220        SDL_Surface *_tmpscreen;
     221        SDL_Surface *_tmpscreen2;
     222
     223        // overlay
     224        SDL_Surface *_overlayscreen;
     225        int _overlayWidth, _overlayHeight;
     226        bool _overlayVisible;
     227
     228        // Audio
     229        int _samplesPerSec;
     230
     231        // CD Audio
     232        SDL_CD *_cdrom;
     233        int _cdTrack, _cdNumLoops, _cdStartFrame, _cdDuration;
     234        uint32 _cdEndTime, _cdStopTime;
     235
     236        enum {
     237                DF_WANT_RECT_OPTIM                      = 1 << 0,
     238                DF_UPDATE_EXPAND_1_PIXEL        = 1 << 1
     239        };
     240
     241        enum {
     242                kTransactionNone = 0,
     243                kTransactionCommit = 1,
     244                kTransactionActive = 2
     245        };
     246
     247        struct TransactionDetails {
     248                int mode;
     249                bool modeChanged;
     250                int w;
     251                int h;
     252                bool sizeChanged;
     253                bool fs;
     254                bool fsChanged;
     255                bool ar;
     256                bool arChanged;
     257                bool needHotswap;
     258                bool needUpdatescreen;
     259                bool needUnload;
     260                bool needToggle;
     261                bool normal1xScaler;
     262        };
     263        TransactionDetails _transactionDetails;
     264
     265        /** Force full redraw on next updateScreen */
     266        bool _forceFull;
     267        ScalerProc *_scalerProc;
     268        int _scalerType;
     269        int _scaleFactor;
     270        int _mode;
     271        int _transactionMode;
     272        bool _fullscreen;
     273       
     274        bool _screenIsLocked;
     275        Graphics::Surface _framebuffer;
     276
     277        /** Current video mode flags (see DF_* constants) */
     278        uint32 _modeFlags;
     279        bool _modeChanged;
     280        int _screenChangeCount;
     281
     282        /** True if aspect ratio correction is enabled. */
     283        bool _adjustAspectRatio;
     284
     285        enum {
     286                NUM_DIRTY_RECT = 100,
     287                MAX_SCALING = 3
     288        };
     289
     290        // Dirty rect management
     291        SDL_Rect _dirtyRectList[NUM_DIRTY_RECT];
     292        int _numDirtyRects;
     293        uint32 *_dirtyChecksums;
     294        bool _cksumValid;
     295        int _cksumNum;
     296
     297        // Keyboard mouse emulation.  Disabled by fingolfin 2004-12-18.
     298        // I am keeping the rest of the code in for now, since the joystick
     299        // code (or rather, "hack") uses it, too.
     300        struct KbdMouse {
     301                int16 x, y, x_vel, y_vel, x_max, y_max, x_down_count, y_down_count;
     302                uint32 last_time, delay_time, x_down_time, y_down_time;
     303        };
     304
     305        struct MousePos {
     306                // The mouse position, using either virtual (game) or real
     307                // (overlay) coordinates.
     308                int16 x, y;
     309
     310                // The size and hotspot of the original cursor image.
     311                int16 w, h;
     312                int16 hotX, hotY;
     313
     314                // The size and hotspot of the pre-scaled cursor image, in real
     315                // coordinates.
     316                int16 rW, rH;
     317                int16 rHotX, rHotY;
     318
     319                // The size and hotspot of the pre-scaled cursor image, in game
     320                // coordinates.
     321                int16 vW, vH;
     322                int16 vHotX, vHotY;
     323
     324                MousePos() : x(0), y(0), w(0), h(0), hotX(0), hotY(0),
     325                             rW(0), rH(0), rHotX(0), rHotY(0), vW(0), vH(0),
     326                             vHotX(0), vHotY(0)
     327                        { }
     328        };
     329
     330        // mouse
     331        KbdMouse _km;
     332        bool _mouseVisible;
     333        bool _mouseDrawn;
     334        byte *_mouseData;
     335        SDL_Rect _mouseBackup;
     336        MousePos _mouseCurState;
     337        byte _mouseKeyColor;
     338        int _cursorTargetScale;
     339        bool _cursorPaletteDisabled;
     340        SDL_Surface *_mouseOrigSurface;
     341        SDL_Surface *_mouseSurface;
     342        enum {
     343                kMouseColorKey = 1
     344        };
     345
     346        // joystick
     347        SDL_Joystick *_joystick;
     348
     349        // Shake mode
     350        int _currentShakePos;
     351        int _newShakePos;
     352
     353        // Palette data
     354        SDL_Color *_currentPalette;
     355        uint _paletteDirtyStart, _paletteDirtyEnd;
     356
     357        // Cursor palette data
     358        SDL_Color *_cursorPalette;
     359
     360        /**
     361         * Mutex which prevents multiple threads from interfering with each other
     362         * when accessing the screen.
     363         */
     364        MutexRef _graphicsMutex;
     365
     366
     367        Common::SaveFileManager *_savefile;
     368        Audio::Mixer *_mixer;
     369       
     370        SDL_TimerID _timerID;
     371        Common::TimerManager *_timer;
     372
     373
     374
     375        void addDirtyRgnAuto(const byte *buf);
     376        void makeChecksums(const byte *buf);
     377
     378        virtual void addDirtyRect(int x, int y, int w, int h, bool realCoordinates = false); // overloaded by CE backend
     379
     380        virtual void drawMouse(); // overloaded by CE backend
     381        virtual void undrawMouse(); // overloaded by CE backend (FIXME)
     382        virtual void blitCursor(); // overloaded by CE backend (FIXME)
     383 
     384        /** Set the position of the virtual mouse cursor. */
     385        void setMousePos(int x, int y);
     386        virtual void fillMouseEvent(Common::Event &event, int x, int y); // overloaded by CE backend
     387        void toggleMouseGrab();
     388
     389        virtual void internUpdateScreen(); // overloaded by CE backend
     390
     391        virtual void loadGFXMode(); // overloaded by CE backend
     392        virtual void unloadGFXMode(); // overloaded by CE backend
     393        virtual void hotswapGFXMode(); // overloaded by CE backend
     394
     395        void setFullscreenMode(bool enable);
     396        void setAspectRatioCorrection(bool enable);
     397
     398        virtual bool saveScreenshot(const char *filename); // overloaded by CE backend
     399
     400        int effectiveScreenHeight() const {
     401                return (_adjustAspectRatio ? real2Aspect(_screenHeight) : _screenHeight)
     402                        * _scaleFactor;
     403        }
     404
     405        void setupIcon();
     406        void handleKbdMouse();
     407
     408        virtual bool remapKey(SDL_Event &ev, Common::Event &event);
     409
     410        void handleScalerHotkeys(const SDL_KeyboardEvent &key);
     411};
     412
     413#endif
  • D:/programming/projects/gsoc/scummvm/backends/platform/common/common-graphics.cpp

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/sdl/graphics.cpp $
     22 * $Id: graphics.cpp 27548 2007-06-19 22:39:59Z fingolfin $
     23 *
     24 */
     25
     26#include "backends/platform/common/common-system.h"
     27#include "common/util.h"
     28#include "graphics/font.h"
     29#include "graphics/fontman.h"
     30#include "graphics/scaler.h"
     31#include "graphics/surface.h"
     32
     33static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
     34        {"1x", "Normal (no scaling)", GFX_NORMAL},
     35        {"2x", "2x", GFX_DOUBLESIZE},
     36        {"3x", "3x", GFX_TRIPLESIZE},
     37        {"2xsai", "2xSAI", GFX_2XSAI},
     38        {"super2xsai", "Super2xSAI", GFX_SUPER2XSAI},
     39        {"supereagle", "SuperEagle", GFX_SUPEREAGLE},
     40        {"advmame2x", "AdvMAME2x", GFX_ADVMAME2X},
     41        {"advmame3x", "AdvMAME3x", GFX_ADVMAME3X},
     42#ifndef DISABLE_HQ_SCALERS
     43        {"hq2x", "HQ2x", GFX_HQ2X},
     44        {"hq3x", "HQ3x", GFX_HQ3X},
     45#endif
     46        {"tv2x", "TV2x", GFX_TV2X},
     47        {"dotmatrix", "DotMatrix", GFX_DOTMATRIX},
     48        {0, 0, 0}
     49};
     50
     51// Table of relative scalers magnitudes
     52// [definedScale - 1][_scaleFactor - 1]
     53static ScalerProc *scalersMagn[3][3] = {
     54#ifndef DISABLE_SCALERS
     55        { Normal1x, AdvMame2x, AdvMame3x },
     56        { Normal1x, Normal1x, Normal1o5x },
     57        { Normal1x, Normal1x, Normal1x }
     58#else // remove dependencies on other scalers
     59        { Normal1x, Normal1x, Normal1x },
     60        { Normal1x, Normal1x, Normal1x },
     61        { Normal1x, Normal1x, Normal1x }
     62#endif
     63};
     64
     65static const int s_gfxModeSwitchTable[][4] = {
     66                { GFX_NORMAL, GFX_DOUBLESIZE, GFX_TRIPLESIZE, -1 },
     67                { GFX_NORMAL, GFX_ADVMAME2X, GFX_ADVMAME3X, -1 },
     68                { GFX_NORMAL, GFX_HQ2X, GFX_HQ3X, -1 },
     69                { GFX_NORMAL, GFX_2XSAI, -1, -1 },
     70                { GFX_NORMAL, GFX_SUPER2XSAI, -1, -1 },
     71                { GFX_NORMAL, GFX_SUPEREAGLE, -1, -1 },
     72                { GFX_NORMAL, GFX_TV2X, -1, -1 },
     73                { GFX_NORMAL, GFX_DOTMATRIX, -1, -1 }
     74        };
     75
     76#ifndef DISABLE_SCALERS
     77static int cursorStretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY);
     78#endif
     79
     80const OSystem::GraphicsMode *OSystem_Common::getSupportedGraphicsModes() const {
     81        return s_supportedGraphicsModes;
     82}
     83
     84int OSystem_Common::getDefaultGraphicsMode() const {
     85        return GFX_DOUBLESIZE;
     86}
     87
     88void OSystem_Common::beginGFXTransaction(void) {
     89        assert (_transactionMode == kTransactionNone);
     90
     91        _transactionMode = kTransactionActive;
     92
     93        _transactionDetails.modeChanged = false;
     94        _transactionDetails.sizeChanged = false;
     95        _transactionDetails.arChanged = false;
     96        _transactionDetails.fsChanged = false;
     97
     98        _transactionDetails.needHotswap = false;
     99        _transactionDetails.needUpdatescreen = false;
     100        _transactionDetails.needUnload = false;
     101
     102        _transactionDetails.normal1xScaler = false;
     103}
     104
     105void OSystem_Common::endGFXTransaction(void) {
     106        // for each engine we run initCommonGFX() as first thing in the transaction
     107        // and initSize() is called later. If user runs launcher at 320x200 with
     108        // 2x overlay, setting to Nomral1x sclaler in that case will be suppressed
     109        // and backend is forced to 2x
     110        //
     111        // This leads to bad results such as 1280x960 window for 640x480 engines.
     112        // To prevent that we rerun setGraphicsMode() if there was 1x scaler request
     113        if (_transactionDetails.normal1xScaler)
     114                setGraphicsMode(GFX_NORMAL);
     115
     116        assert (_transactionMode == kTransactionActive);
     117
     118        _transactionMode = kTransactionCommit;
     119        if (_transactionDetails.modeChanged)
     120                setGraphicsMode(_transactionDetails.mode);
     121
     122        if (_transactionDetails.sizeChanged)
     123                initSize(_transactionDetails.w, _transactionDetails.h);
     124
     125        if (_transactionDetails.arChanged)
     126                setAspectRatioCorrection(_transactionDetails.ar);
     127
     128        if (_transactionDetails.needUnload) {
     129                unloadGFXMode();
     130                loadGFXMode();
     131                clearOverlay();
     132        } else {
     133                if (!_transactionDetails.fsChanged) {
     134                        if (_transactionDetails.needHotswap)
     135                                hotswapGFXMode();
     136                        else if (_transactionDetails.needUpdatescreen)
     137                                internUpdateScreen();
     138                }
     139        }
     140
     141        if (_transactionDetails.fsChanged)
     142                setFullscreenMode(_transactionDetails.fs);
     143
     144        _transactionMode = kTransactionNone;
     145}
     146
     147bool OSystem_Common::setGraphicsMode(int mode) {
     148        Common::StackLock lock(_graphicsMutex);
     149
     150        int newScaleFactor = 1;
     151        ScalerProc *newScalerProc;
     152
     153        switch(mode) {
     154        case GFX_NORMAL:
     155                newScaleFactor = 1;
     156                newScalerProc = Normal1x;
     157                break;
     158#ifndef DISABLE_SCALERS
     159        case GFX_DOUBLESIZE:
     160                newScaleFactor = 2;
     161                newScalerProc = Normal2x;
     162                break;
     163        case GFX_TRIPLESIZE:
     164                newScaleFactor = 3;
     165                newScalerProc = Normal3x;
     166                break;
     167
     168        case GFX_2XSAI:
     169                newScaleFactor = 2;
     170                newScalerProc = _2xSaI;
     171                break;
     172        case GFX_SUPER2XSAI:
     173                newScaleFactor = 2;
     174                newScalerProc = Super2xSaI;
     175                break;
     176        case GFX_SUPEREAGLE:
     177                newScaleFactor = 2;
     178                newScalerProc = SuperEagle;
     179                break;
     180        case GFX_ADVMAME2X:
     181                newScaleFactor = 2;
     182                newScalerProc = AdvMame2x;
     183                break;
     184        case GFX_ADVMAME3X:
     185                newScaleFactor = 3;
     186                newScalerProc = AdvMame3x;
     187                break;
     188#ifndef DISABLE_HQ_SCALERS
     189        case GFX_HQ2X:
     190                newScaleFactor = 2;
     191                newScalerProc = HQ2x;
     192                break;
     193        case GFX_HQ3X:
     194                newScaleFactor = 3;
     195                newScalerProc = HQ3x;
     196                break;
     197#endif
     198        case GFX_TV2X:
     199                newScaleFactor = 2;
     200                newScalerProc = TV2x;
     201                break;
     202        case GFX_DOTMATRIX:
     203                newScaleFactor = 2;
     204                newScalerProc = DotMatrix;
     205                break;
     206#endif // DISABLE_SCALERS
     207
     208        default:
     209                warning("unknown gfx mode %d", mode);
     210                return false;
     211        }
     212
     213        _transactionDetails.normal1xScaler = (mode == GFX_NORMAL);
     214
     215        _mode = mode;
     216        _scalerProc = newScalerProc;
     217
     218        if (_transactionMode == kTransactionActive) {
     219                _transactionDetails.mode = mode;
     220                _transactionDetails.modeChanged = true;
     221
     222                if (newScaleFactor != _scaleFactor) {
     223                        _transactionDetails.needHotswap = true;
     224                        _scaleFactor = newScaleFactor;
     225                }
     226
     227                _transactionDetails.needUpdatescreen = true;
     228
     229                return true;
     230        }
     231
     232        // NOTE: This should not be executed at transaction commit
     233        //   Otherwise there is some unsolicited setGraphicsMode() call
     234        //   which should be properly removed
     235        if (newScaleFactor != _scaleFactor) {
     236                assert(_transactionMode != kTransactionCommit);
     237
     238                _scaleFactor = newScaleFactor;
     239                hotswapGFXMode();
     240        }
     241
     242        // Determine the "scaler type", i.e. essentially an index into the
     243        // s_gfxModeSwitchTable array defined in events.cpp.
     244        if (_mode != GFX_NORMAL) {
     245                for (int i = 0; i < ARRAYSIZE(s_gfxModeSwitchTable); i++) {
     246                        if (s_gfxModeSwitchTable[i][1] == _mode || s_gfxModeSwitchTable[i][2] == _mode) {
     247                                _scalerType = i;
     248                                break;
     249                        }
     250                }
     251        }
     252
     253        if (!_screen)
     254                return true;
     255
     256        // Blit everything to the screen
     257        _forceFull = true;
     258
     259        // Even if the old and new scale factors are the same, we may have a
     260        // different scaler for the cursor now.
     261        blitCursor();
     262
     263        if (_transactionMode != kTransactionCommit)
     264                internUpdateScreen();
     265
     266        // Make sure that an Common::EVENT_SCREEN_CHANGED gets sent later
     267        _modeChanged = true;
     268
     269        return true;
     270}
     271
     272int OSystem_Common::getGraphicsMode() const {
     273        assert (_transactionMode == kTransactionNone);
     274        return _mode;
     275}
     276
     277void OSystem_Common::initSize(uint w, uint h) {
     278        // Avoid redundant res changes
     279        if ((int)w == _screenWidth && (int)h == _screenHeight &&
     280                _transactionMode != kTransactionCommit)
     281                return;
     282
     283        _screenWidth = w;
     284        _screenHeight = h;
     285
     286        _cksumNum = (_screenWidth * _screenHeight / (8 * 8));
     287
     288        if (_transactionMode == kTransactionActive) {
     289                _transactionDetails.w = w;
     290                _transactionDetails.h = h;
     291                _transactionDetails.sizeChanged = true;
     292
     293                _transactionDetails.needUnload = true;
     294
     295                return;
     296        }
     297
     298        free(_dirtyChecksums);
     299        _dirtyChecksums = (uint32 *)calloc(_cksumNum * 2, sizeof(uint32));
     300
     301        if (_transactionMode != kTransactionCommit) {
     302                unloadGFXMode();
     303                loadGFXMode();
     304
     305                // if initSize() gets called in the middle, overlay is not transparent
     306                clearOverlay();
     307        }
     308}
     309
     310void OSystem_Common::loadGFXMode() {
     311        assert(_inited);
     312        _forceFull = true;
     313        _modeFlags |= DF_UPDATE_EXPAND_1_PIXEL;
     314
     315        int hwW, hwH;
     316
     317#ifndef __MAEMO__
     318        _overlayWidth = _screenWidth * _scaleFactor;
     319        _overlayHeight = _screenHeight * _scaleFactor;
     320
     321        if (_screenHeight != 200 && _screenHeight != 400)
     322                _adjustAspectRatio = false;
     323
     324        if (_adjustAspectRatio)
     325                _overlayHeight = real2Aspect(_overlayHeight);
     326
     327        hwW = _screenWidth * _scaleFactor;
     328        hwH = effectiveScreenHeight();
     329#else
     330        hwW = _overlayWidth;
     331        hwH = _overlayHeight;
     332#endif
     333
     334        //
     335        // Create the surface that contains the 8 bit game data
     336        //
     337        _screen = SDL_CreateRGBSurface(SDL_SWSURFACE, _screenWidth, _screenHeight, 8, 0, 0, 0, 0);
     338        if (_screen == NULL)
     339                error("allocating _screen failed");
     340
     341        //
     342        // Create the surface that contains the scaled graphics in 16 bit mode
     343        //
     344
     345        _hwscreen = SDL_SetVideoMode(hwW, hwH, 16,
     346                _fullscreen ? (SDL_FULLSCREEN|SDL_SWSURFACE) : SDL_SWSURFACE
     347        );
     348        if (_hwscreen == NULL) {
     349                // DON'T use error(), as this tries to bring up the debug
     350                // console, which WON'T WORK now that _hwscreen is hosed.
     351
     352                // FIXME: We should be able to continue the game without
     353                // shutting down or bringing up the debug console, but at
     354                // this point we've already screwed up all our member vars.
     355                // We need to find a way to call SDL_SetVideoMode *before*
     356                // that happens and revert to all the old settings if we
     357                // can't pull off the switch to the new settings.
     358                //
     359                // Fingolfin says: the "easy" way to do that is not to modify
     360                // the member vars before we are sure everything is fine. Think
     361                // of "transactions, commit, rollback" style... we use local vars
     362                // in place of the member vars, do everything etc. etc.. In case
     363                // of a failure, rollback is trivial. Only if everything worked fine
     364                // do we "commit" the changed values to the member vars.
     365                warning("SDL_SetVideoMode says we can't switch to that mode (%s)", SDL_GetError());
     366                quit();
     367        }
     368
     369        //
     370        // Create the surface used for the graphics in 16 bit before scaling, and also the overlay
     371        //
     372
     373        // Distinguish 555 and 565 mode
     374        if (_hwscreen->format->Rmask == 0x7C00)
     375                InitScalers(555);
     376        else
     377                InitScalers(565);
     378
     379        // Need some extra bytes around when using 2xSaI
     380        _tmpscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _screenWidth + 3, _screenHeight + 3,
     381                                                16,
     382                                                _hwscreen->format->Rmask,
     383                                                _hwscreen->format->Gmask,
     384                                                _hwscreen->format->Bmask,
     385                                                _hwscreen->format->Amask);
     386
     387        if (_tmpscreen == NULL)
     388                error("allocating _tmpscreen failed");
     389
     390        _overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _overlayWidth, _overlayHeight,
     391                                                16,
     392                                                _hwscreen->format->Rmask,
     393                                                _hwscreen->format->Gmask,
     394                                                _hwscreen->format->Bmask,
     395                                                _hwscreen->format->Amask);
     396
     397        if (_overlayscreen == NULL)
     398                error("allocating _overlayscreen failed");
     399
     400        _tmpscreen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, _overlayWidth + 3, _overlayHeight + 3,
     401                                                16,
     402                                                _hwscreen->format->Rmask,
     403                                                _hwscreen->format->Gmask,
     404                                                _hwscreen->format->Bmask,
     405                                                _hwscreen->format->Amask);
     406
     407        if (_tmpscreen2 == NULL)
     408                error("allocating _tmpscreen2 failed");
     409
     410#ifdef USE_OSD
     411        _osdSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA,
     412                                                _hwscreen->w,
     413                                                _hwscreen->h,
     414                                                16,
     415                                                _hwscreen->format->Rmask,
     416                                                _hwscreen->format->Gmask,
     417                                                _hwscreen->format->Bmask,
     418                                                _hwscreen->format->Amask);
     419        if (_osdSurface == NULL)
     420                error("allocating _osdSurface failed");
     421        SDL_SetColorKey(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kOSDColorKey);
     422#endif
     423
     424        // keyboard cursor control, some other better place for it?
     425        _km.x_max = _screenWidth * _scaleFactor - 1;
     426        _km.y_max = effectiveScreenHeight() - 1;
     427        _km.delay_time = 25;
     428        _km.last_time = 0;
     429}
     430
     431void OSystem_Common::unloadGFXMode() {
     432        if (_screen) {
     433                SDL_FreeSurface(_screen);
     434                _screen = NULL;
     435        }
     436
     437        if (_hwscreen) {
     438                SDL_FreeSurface(_hwscreen);
     439                _hwscreen = NULL;
     440        }
     441
     442        if (_tmpscreen) {
     443                SDL_FreeSurface(_tmpscreen);
     444                _tmpscreen = NULL;
     445        }
     446
     447        if (_tmpscreen2) {
     448                SDL_FreeSurface(_tmpscreen2);
     449                _tmpscreen2 = NULL;
     450        }
     451
     452        if (_overlayscreen) {
     453                SDL_FreeSurface(_overlayscreen);
     454                _overlayscreen = NULL;
     455        }
     456
     457#ifdef USE_OSD
     458        if (_osdSurface) {
     459                SDL_FreeSurface(_osdSurface);
     460                _osdSurface = NULL;
     461        }
     462#endif
     463}
     464
     465void OSystem_Common::hotswapGFXMode() {
     466        if (!_screen)
     467                return;
     468
     469        // Keep around the old _screen & _overlayscreen so we can restore the screen data
     470        // after the mode switch.
     471        SDL_Surface *old_screen = _screen;
     472        SDL_Surface *old_overlayscreen = _overlayscreen;
     473
     474        // Release the HW screen surface
     475        SDL_FreeSurface(_hwscreen);
     476
     477        SDL_FreeSurface(_tmpscreen);
     478        SDL_FreeSurface(_tmpscreen2);
     479
     480#ifdef USE_OSD
     481        // Release the OSD surface
     482        SDL_FreeSurface(_osdSurface);
     483#endif
     484
     485        // Setup the new GFX mode
     486        loadGFXMode();
     487
     488        // reset palette
     489        SDL_SetColors(_screen, _currentPalette, 0, 256);
     490
     491        // Restore old screen content
     492        SDL_BlitSurface(old_screen, NULL, _screen, NULL);
     493        SDL_BlitSurface(old_overlayscreen, NULL, _overlayscreen, NULL);
     494
     495        // Free the old surfaces
     496        SDL_FreeSurface(old_screen);
     497        SDL_FreeSurface(old_overlayscreen);
     498
     499        // Update cursor to new scale
     500        blitCursor();
     501
     502        // Blit everything to the screen
     503        internUpdateScreen();
     504
     505        // Make sure that an Common::EVENT_SCREEN_CHANGED gets sent later
     506        _modeChanged = true;
     507}
     508
     509void OSystem_Common::updateScreen() {
     510        assert (_transactionMode == kTransactionNone);
     511
     512        Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
     513
     514        internUpdateScreen();
     515}
     516
     517void OSystem_Common::internUpdateScreen() {
     518        SDL_Surface *srcSurf, *origSurf;
     519        int height, width;
     520        ScalerProc *scalerProc;
     521        int scale1;
     522
     523#if defined (DEBUG) && ! defined(_WIN32_WCE) // definitions not available for non-DEBUG here. (needed this to compile in SYMBIAN32 & linux?)
     524        assert(_hwscreen != NULL);
     525        assert(_hwscreen->map->sw_data != NULL);
     526#endif
     527
     528        // If the shake position changed, fill the dirty area with blackness
     529        if (_currentShakePos != _newShakePos) {
     530                SDL_Rect blackrect = {0, 0, _screenWidth * _scaleFactor, _newShakePos * _scaleFactor};
     531
     532                if (_adjustAspectRatio && !_overlayVisible)
     533                        blackrect.h = real2Aspect(blackrect.h - 1) + 1;
     534
     535                SDL_FillRect(_hwscreen, &blackrect, 0);
     536
     537                _currentShakePos = _newShakePos;
     538
     539                _forceFull = true;
     540        }
     541
     542        // Check whether the palette was changed in the meantime and update the
     543        // screen surface accordingly.
     544        if (_screen && _paletteDirtyEnd != 0) {
     545                SDL_SetColors(_screen, _currentPalette + _paletteDirtyStart,
     546                        _paletteDirtyStart,
     547                        _paletteDirtyEnd - _paletteDirtyStart);
     548
     549                _paletteDirtyEnd = 0;
     550
     551                _forceFull = true;
     552        }
     553
     554#ifdef USE_OSD
     555        // OSD visible (i.e. non-transparent)?
     556        if (_osdAlpha != SDL_ALPHA_TRANSPARENT) {
     557                // Updated alpha value
     558                const int diff = SDL_GetTicks() - _osdFadeStartTime;
     559                if (diff > 0) {
     560                        if (diff >= kOSDFadeOutDuration) {
     561                                // Back to full transparency
     562                                _osdAlpha = SDL_ALPHA_TRANSPARENT;
     563                        } else {
     564                                // Do a linear fade out...
     565                                const int startAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100;
     566                                _osdAlpha = startAlpha + diff * (SDL_ALPHA_TRANSPARENT - startAlpha) / kOSDFadeOutDuration;
     567                        }
     568                        SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha);
     569                        _forceFull = true;
     570                }
     571        }
     572#endif
     573
     574        if (!_overlayVisible) {
     575                origSurf = _screen;
     576                srcSurf = _tmpscreen;
     577                width = _screenWidth;
     578                height = _screenHeight;
     579                scalerProc = _scalerProc;
     580                scale1 = _scaleFactor;
     581        } else {
     582                origSurf = _overlayscreen;
     583                srcSurf = _tmpscreen2;
     584                width = _overlayWidth;
     585                height = _overlayHeight;
     586                scalerProc = Normal1x;
     587
     588                scale1 = 1;
     589        }
     590
     591        // Force a full redraw if requested
     592        if (_forceFull) {
     593                _numDirtyRects = 1;
     594                _dirtyRectList[0].x = 0;
     595                _dirtyRectList[0].y = 0;
     596                _dirtyRectList[0].w = width;
     597                _dirtyRectList[0].h = height;
     598        } else
     599                undrawMouse();
     600
     601        // Only draw anything if necessary
     602        if (_numDirtyRects > 0) {
     603
     604                SDL_Rect *r;
     605                SDL_Rect dst;
     606                uint32 srcPitch, dstPitch;
     607                SDL_Rect *lastRect = _dirtyRectList + _numDirtyRects;
     608
     609                if (scalerProc == Normal1x && !_adjustAspectRatio && 0) {
     610                        for (r = _dirtyRectList; r != lastRect; ++r) {
     611                                dst = *r;
     612
     613                                dst.y += _currentShakePos;
     614                                if (SDL_BlitSurface(origSurf, r, _hwscreen, &dst) != 0)
     615                                        error("SDL_BlitSurface failed: %s", SDL_GetError());
     616                        }
     617                } else {
     618                        for (r = _dirtyRectList; r != lastRect; ++r) {
     619                                dst = *r;
     620                                dst.x++;        // Shift rect by one since 2xSai needs to acces the data around
     621                                dst.y++;        // any pixel to scale it, and we want to avoid mem access crashes.
     622
     623                                if (SDL_BlitSurface(origSurf, r, srcSurf, &dst) != 0)
     624                                        error("SDL_BlitSurface failed: %s", SDL_GetError());
     625                        }
     626
     627                        SDL_LockSurface(srcSurf);
     628                        SDL_LockSurface(_hwscreen);
     629
     630                        srcPitch = srcSurf->pitch;
     631                        dstPitch = _hwscreen->pitch;
     632
     633                        for (r = _dirtyRectList; r != lastRect; ++r) {
     634                                register int dst_y = r->y + _currentShakePos;
     635                                register int dst_h = 0;
     636                                register int orig_dst_y = 0;
     637                                register int rx1 = r->x * scale1;
     638
     639                                if (dst_y < height) {
     640                                        dst_h = r->h;
     641                                        if (dst_h > height - dst_y)
     642                                                dst_h = height - dst_y;
     643
     644                                        orig_dst_y = dst_y;
     645                                        dst_y = dst_y * scale1;
     646
     647                                        if (_adjustAspectRatio && !_overlayVisible)
     648                                                dst_y = real2Aspect(dst_y);
     649
     650                                        assert(scalerProc != NULL);
     651                                        scalerProc((byte *)srcSurf->pixels + (r->x * 2 + 2) + (r->y + 1) * srcPitch, srcPitch,
     652                                                           (byte *)_hwscreen->pixels + rx1 * 2 + dst_y * dstPitch, dstPitch, r->w, dst_h);
     653                                }
     654
     655                                r->x = rx1;
     656                                r->y = dst_y;
     657                                r->w = r->w * scale1;
     658                                r->h = dst_h * scale1;
     659
     660#ifndef DISABLE_SCALERS
     661                                if (_adjustAspectRatio && orig_dst_y < height && !_overlayVisible)
     662                                        r->h = stretch200To240((uint8 *) _hwscreen->pixels, dstPitch, r->w, r->h, r->x, r->y, orig_dst_y * scale1);
     663#endif
     664                        }
     665                        SDL_UnlockSurface(srcSurf);
     666                        SDL_UnlockSurface(_hwscreen);
     667                }
     668
     669                // Readjust the dirty rect list in case we are doing a full update.
     670                // This is necessary if shaking is active.
     671                if (_forceFull) {
     672                        _dirtyRectList[0].y = 0;
     673                        _dirtyRectList[0].h = effectiveScreenHeight();
     674                }
     675
     676                drawMouse();
     677
     678#ifdef USE_OSD
     679                if (_osdAlpha != SDL_ALPHA_TRANSPARENT) {
     680                        SDL_BlitSurface(_osdSurface, 0, _hwscreen, 0);
     681                }
     682#endif
     683                // Finally, blit all our changes to the screen
     684                SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList);
     685        } else {
     686                drawMouse();
     687                if (_numDirtyRects)
     688                        SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList);
     689        }
     690
     691        _numDirtyRects = 0;
     692        _forceFull = false;
     693}
     694
     695bool OSystem_Common::saveScreenshot(const char *filename) {
     696        assert(_hwscreen != NULL);
     697
     698        Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
     699        return SDL_SaveBMP(_hwscreen, filename) == 0;
     700}
     701
     702void OSystem_Common::setFullscreenMode(bool enable) {
     703        Common::StackLock lock(_graphicsMutex);
     704
     705        if (_fullscreen != enable || _transactionMode == kTransactionCommit) {
     706                assert(_hwscreen != 0);
     707                _fullscreen = enable;
     708
     709                if (_transactionMode == kTransactionActive) {
     710                        _transactionDetails.fs = enable;
     711                        _transactionDetails.fsChanged = true;
     712
     713                        _transactionDetails.needHotswap = true;
     714
     715                        return;
     716                }
     717
     718#if (defined(MACOSX) && !SDL_VERSION_ATLEAST(1, 2, 6)) || defined(__MAEMO__)
     719                // On OS X, SDL_WM_ToggleFullScreen is currently not implemented. Worse,
     720                // before SDL 1.2.6 it always returned -1 (which would indicate a
     721                // successful switch). So we simply don't call it at all and use
     722                // hotswapGFXMode() directly to switch to fullscreen mode.
     723                hotswapGFXMode();
     724#else
     725                if (!SDL_WM_ToggleFullScreen(_hwscreen)) {
     726                        // if ToggleFullScreen fails, achieve the same effect with hotswap gfx mode
     727                        hotswapGFXMode();
     728                } else {
     729                        // Blit everything to the screen
     730                        internUpdateScreen();
     731
     732                        // Make sure that an Common::EVENT_SCREEN_CHANGED gets sent later
     733                        _modeChanged = true;
     734                }
     735#endif
     736        }
     737}
     738
     739void OSystem_Common::setAspectRatioCorrection(bool enable) {
     740        if (((_screenHeight == 200 || _screenHeight == 400) && _adjustAspectRatio != enable) ||
     741                _transactionMode == kTransactionCommit) {
     742                Common::StackLock lock(_graphicsMutex);
     743
     744                //assert(_hwscreen != 0);
     745                _adjustAspectRatio = enable;
     746
     747                if (_transactionMode == kTransactionActive) {
     748                        _transactionDetails.ar = enable;
     749                        _transactionDetails.arChanged = true;
     750
     751                        _transactionDetails.needHotswap = true;
     752
     753                        return;
     754                } else {
     755                        if (_transactionMode != kTransactionCommit)
     756                                hotswapGFXMode();
     757                }
     758
     759                // Make sure that an Common::EVENT_SCREEN_CHANGED gets sent later
     760                _modeChanged = true;
     761        }
     762}
     763
     764void OSystem_Common::copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h) {
     765        assert (_transactionMode == kTransactionNone);
     766        assert(src);
     767
     768        if (_screen == NULL) {
     769                warning("OSystem_Common::copyRectToScreen: _screen == NULL");
     770                return;
     771        }
     772
     773        Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
     774
     775        assert(x >= 0 && x < _screenWidth);
     776        assert(y >= 0 && y < _screenHeight);
     777        assert(h > 0 && y + h <= _screenHeight);
     778        assert(w > 0 && x + w <= _screenWidth);
     779
     780        if (((long)src & 3) == 0 && pitch == _screenWidth && x == 0 && y == 0 &&
     781                        w == _screenWidth && h == _screenHeight && _modeFlags & DF_WANT_RECT_OPTIM) {
     782                /* Special, optimized case for full screen updates.
     783                 * It tries to determine what areas were actually changed,
     784                 * and just updates those, on the actual display. */
     785                addDirtyRgnAuto(src);
     786        } else {
     787                /* Clip the coordinates */
     788                if (x < 0) {
     789                        w += x;
     790                        src -= x;
     791                        x = 0;
     792                }
     793
     794                if (y < 0) {
     795                        h += y;
     796                        src -= y * pitch;
     797                        y = 0;
     798                }
     799
     800                if (w > _screenWidth - x) {
     801                        w = _screenWidth - x;
     802                }
     803
     804                if (h > _screenHeight - y) {
     805                        h = _screenHeight - y;
     806                }
     807
     808                if (w <= 0 || h <= 0)
     809                        return;
     810
     811                _cksumValid = false;
     812                addDirtyRect(x, y, w, h);
     813        }
     814
     815        // Try to lock the screen surface
     816        if (SDL_LockSurface(_screen) == -1)
     817                error("SDL_LockSurface failed: %s", SDL_GetError());
     818
     819        byte *dst = (byte *)_screen->pixels + y * _screenWidth + x;
     820
     821        if (_screenWidth == pitch && pitch == w) {
     822                memcpy(dst, src, h*w);
     823        } else {
     824                do {
     825                        memcpy(dst, src, w);
     826                        src += pitch;
     827                        dst += _screenWidth;
     828                } while (--h);
     829        }
     830
     831        // Unlock the screen surface
     832        SDL_UnlockSurface(_screen);
     833}
     834
     835Graphics::Surface *OSystem_Common::lockScreen() {
     836        assert (_transactionMode == kTransactionNone);
     837
     838        // Lock the graphics mutex
     839        lockMutex(_graphicsMutex);
     840
     841        // paranoia check
     842        assert(!_screenIsLocked);
     843        _screenIsLocked = true;
     844
     845        // Try to lock the screen surface
     846        if (SDL_LockSurface(_screen) == -1)
     847                error("SDL_LockSurface failed: %s", SDL_GetError());
     848
     849        _framebuffer.pixels = _screen->pixels;
     850        _framebuffer.w = _screen->w;
     851        _framebuffer.h = _screen->h;
     852        _framebuffer.pitch = _screen->pitch;
     853        _framebuffer.bytesPerPixel = 1;
     854
     855        return &_framebuffer;
     856}
     857
     858void OSystem_Common::unlockScreen() {
     859        assert (_transactionMode == kTransactionNone);
     860
     861        // paranoia check
     862        assert(_screenIsLocked);
     863        _screenIsLocked = false;
     864
     865        // Unlock the screen surface
     866        SDL_UnlockSurface(_screen);
     867
     868        // Trigger a full screen update
     869        _forceFull = true;
     870
     871        // Finally unlock the graphics mutex
     872        unlockMutex(_graphicsMutex);
     873}
     874
     875void OSystem_Common::addDirtyRect(int x, int y, int w, int h, bool realCoordinates) {
     876        if (_forceFull)
     877                return;
     878
     879        if (_numDirtyRects == NUM_DIRTY_RECT) {
     880                _forceFull = true;
     881                return;
     882        }
     883
     884        int height, width;
     885
     886        if (!_overlayVisible && !realCoordinates) {
     887                width = _screenWidth;
     888                height = _screenHeight;
     889        } else {
     890                width = _overlayWidth;
     891                height = _overlayHeight;
     892        }
     893
     894        // Extend the dirty region by 1 pixel for scalers
     895        // that "smear" the screen, e.g. 2xSAI
     896        if ((_modeFlags & DF_UPDATE_EXPAND_1_PIXEL) && !realCoordinates) {
     897                x--;
     898                y--;
     899                w+=2;
     900                h+=2;
     901        }
     902
     903        // clip
     904        if (x < 0) {
     905                w += x;
     906                x = 0;
     907        }
     908
     909        if (y < 0) {
     910                h += y;
     911                y=0;
     912        }
     913
     914        if (w > width - x) {
     915                w = width - x;
     916        }
     917
     918        if (h > height - y) {
     919                h = height - y;
     920        }
     921
     922#ifndef DISABLE_SCALERS
     923        if (_adjustAspectRatio && !_overlayVisible && !realCoordinates) {
     924                makeRectStretchable(x, y, w, h);
     925        }
     926#endif
     927
     928        if (w == width && h == height) {
     929                _forceFull = true;
     930                return;
     931        }
     932
     933        if (w > 0 && h > 0) {
     934                SDL_Rect *r = &_dirtyRectList[_numDirtyRects++];
     935
     936                r->x = x;
     937                r->y = y;
     938                r->w = w;
     939                r->h = h;
     940        }
     941}
     942
     943
     944void OSystem_Common::makeChecksums(const byte *buf) {
     945        assert(buf);
     946        uint32 *sums = _dirtyChecksums;
     947        uint x,y;
     948        const uint last_x = (uint)_screenWidth / 8;
     949        const uint last_y = (uint)_screenHeight / 8;
     950
     951        const uint BASE = 65521; /* largest prime smaller than 65536 */
     952
     953        /* the 8x8 blocks in buf are enumerated starting in the top left corner and
     954         * reading each line at a time from left to right */
     955        for (y = 0; y != last_y; y++, buf += _screenWidth * (8 - 1))
     956                for (x = 0; x != last_x; x++, buf += 8) {
     957                        // Adler32 checksum algorithm (from RFC1950, used by gzip and zlib).
     958                        // This computes the Adler32 checksum of a 8x8 pixel block. Note
     959                        // that we can do the modulo operation (which is the slowest part)
     960                        // of the algorithm) at the end, instead of doing each iteration,
     961                        // since we only have 64 iterations in total - and thus s1 and
     962                        // s2 can't overflow anyway.
     963                        uint32 s1 = 1;
     964                        uint32 s2 = 0;
     965                        const byte *ptr = buf;
     966                        for (int subY = 0; subY < 8; subY++) {
     967                                for (int subX = 0; subX < 8; subX++) {
     968                                        s1 += ptr[subX];
     969                                        s2 += s1;
     970                                }
     971                                ptr += _screenWidth;
     972                        }
     973
     974                        s1 %= BASE;
     975                        s2 %= BASE;
     976
     977                        /* output the checksum for this block */
     978                        *sums++ =  (s2 << 16) + s1;
     979        }
     980}
     981
     982void OSystem_Common::addDirtyRgnAuto(const byte *buf) {
     983        assert(buf);
     984        assert(((long)buf & 3) == 0);
     985
     986        /* generate a table of the checksums */
     987        makeChecksums(buf);
     988
     989        if (!_cksumValid) {
     990                _forceFull = true;
     991                _cksumValid = true;
     992        }
     993
     994        /* go through the checksum list, compare it with the previous checksums,
     995                 and add all dirty rectangles to a list. try to combine small rectangles
     996                 into bigger ones in a simple way */
     997        if (!_forceFull) {
     998                int x, y, w;
     999                uint32 *ck = _dirtyChecksums;
     1000
     1001                for (y = 0; y != _screenHeight / 8; y++) {
     1002                        for (x = 0; x != _screenWidth / 8; x++, ck++) {
     1003                                if (ck[0] != ck[_cksumNum]) {
     1004                                        /* found a dirty 8x8 block, now go as far to the right as possible,
     1005                                                 and at the same time, unmark the dirty status by setting old to new. */
     1006                                        w=0;
     1007                                        do {
     1008                                                ck[w + _cksumNum] = ck[w];
     1009                                                w++;
     1010                                        } while (x + w != _screenWidth / 8 && ck[w] != ck[w + _cksumNum]);
     1011
     1012                                        addDirtyRect(x * 8, y * 8, w * 8, 8);
     1013
     1014                                        if (_forceFull)
     1015                                                goto get_out;
     1016                                }
     1017                        }
     1018                }
     1019        } else {
     1020                get_out:;
     1021                /* Copy old checksums to new */
     1022                memcpy(_dirtyChecksums + _cksumNum, _dirtyChecksums, _cksumNum * sizeof(uint32));
     1023        }
     1024}
     1025
     1026int16 OSystem_Common::getHeight() {
     1027        return _screenHeight;
     1028}
     1029
     1030int16 OSystem_Common::getWidth() {
     1031        return _screenWidth;
     1032}
     1033
     1034void OSystem_Common::setPalette(const byte *colors, uint start, uint num) {
     1035        assert(colors);
     1036
     1037        // Setting the palette before _screen is created is allowed - for now -
     1038        // since we don't actually set the palette until the screen is updated.
     1039        // But it could indicate a programming error, so let's warn about it.
     1040
     1041        if (!_screen)
     1042                warning("OSystem_Common::setPalette: _screen == NULL");
     1043
     1044        const byte *b = colors;
     1045        uint i;
     1046        SDL_Color *base = _currentPalette + start;
     1047        for (i = 0; i < num; i++) {
     1048                base[i].r = b[0];
     1049                base[i].g = b[1];
     1050                base[i].b = b[2];
     1051                b += 4;
     1052        }
     1053
     1054        if (start < _paletteDirtyStart)
     1055                _paletteDirtyStart = start;
     1056
     1057        if (start + num > _paletteDirtyEnd)
     1058                _paletteDirtyEnd = start + num;
     1059
     1060        // Some games blink cursors with palette
     1061        if (_cursorPaletteDisabled)
     1062                blitCursor();
     1063}
     1064
     1065void OSystem_Common::grabPalette(byte *colors, uint start, uint num) {
     1066        assert(colors);
     1067        const SDL_Color *base = _currentPalette + start;
     1068
     1069        for (uint i = 0; i < num; ++i) {
     1070                colors[i * 4] = base[i].r;
     1071                colors[i * 4 + 1] = base[i].g;
     1072                colors[i * 4 + 2] = base[i].b;
     1073                colors[i * 4 + 3] = 0xFF;
     1074        }
     1075}
     1076
     1077void OSystem_Common::setCursorPalette(const byte *colors, uint start, uint num) {
     1078        assert(colors);
     1079        const byte *b = colors;
     1080        uint i;
     1081        SDL_Color *base = _cursorPalette + start;
     1082        for (i = 0; i < num; i++) {
     1083                base[i].r = b[0];
     1084                base[i].g = b[1];
     1085                base[i].b = b[2];
     1086                b += 4;
     1087        }
     1088
     1089        _cursorPaletteDisabled = false;
     1090
     1091        blitCursor();
     1092}
     1093
     1094void OSystem_Common::setShakePos(int shake_pos) {
     1095        assert (_transactionMode == kTransactionNone);
     1096
     1097        _newShakePos = shake_pos;
     1098}
     1099
     1100
     1101#pragma mark -
     1102#pragma mark --- Overlays ---
     1103#pragma mark -
     1104
     1105void OSystem_Common::showOverlay() {
     1106        assert (_transactionMode == kTransactionNone);
     1107
     1108        int x, y;
     1109
     1110        if (_overlayVisible)
     1111                return;
     1112
     1113        _overlayVisible = true;
     1114
     1115        // Since resolution could change, put mouse to adjusted position
     1116        // Fixes bug #1349059
     1117        x = _mouseCurState.x * _scaleFactor;
     1118        if (_adjustAspectRatio)
     1119                y = real2Aspect(_mouseCurState.y) * _scaleFactor;
     1120        else
     1121                y = _mouseCurState.y * _scaleFactor;
     1122
     1123        warpMouse(x, y);
     1124
     1125        clearOverlay();
     1126}
     1127
     1128void OSystem_Common::hideOverlay() {
     1129        assert (_transactionMode == kTransactionNone);
     1130
     1131        if (!_overlayVisible)
     1132                return;
     1133
     1134        int x, y;
     1135
     1136        _overlayVisible = false;
     1137
     1138        // Since resolution could change, put mouse to adjusted position
     1139        // Fixes bug #1349059
     1140        x = _mouseCurState.x / _scaleFactor;
     1141        y = _mouseCurState.y / _scaleFactor;
     1142        if (_adjustAspectRatio)
     1143                y = aspect2Real(y);
     1144
     1145        warpMouse(x, y);
     1146
     1147        clearOverlay();
     1148
     1149        _forceFull = true;
     1150}
     1151
     1152void OSystem_Common::clearOverlay() {
     1153        //assert (_transactionMode == kTransactionNone);
     1154
     1155        Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
     1156
     1157        if (!_overlayVisible)
     1158                return;
     1159
     1160        // Clear the overlay by making the game screen "look through" everywhere.
     1161        SDL_Rect src, dst;
     1162        src.x = src.y = 0;
     1163        dst.x = dst.y = 1;
     1164        src.w = dst.w = _screenWidth;
     1165        src.h = dst.h = _screenHeight;
     1166        if (SDL_BlitSurface(_screen, &src, _tmpscreen, &dst) != 0)
     1167                error("SDL_BlitSurface failed: %s", SDL_GetError());
     1168
     1169        SDL_LockSurface(_tmpscreen);
     1170        SDL_LockSurface(_overlayscreen);
     1171        _scalerProc((byte *)(_tmpscreen->pixels) + _tmpscreen->pitch + 2, _tmpscreen->pitch,
     1172        (byte *)_overlayscreen->pixels, _overlayscreen->pitch, _screenWidth, _screenHeight);
     1173
     1174#ifndef DISABLE_SCALERS
     1175        if (_adjustAspectRatio)
     1176                stretch200To240((uint8 *)_overlayscreen->pixels, _overlayscreen->pitch,
     1177                                                _overlayWidth, _screenHeight * _scaleFactor, 0, 0, 0);
     1178#endif
     1179        SDL_UnlockSurface(_tmpscreen);
     1180        SDL_UnlockSurface(_overlayscreen);
     1181
     1182        _forceFull = true;
     1183}
     1184
     1185void OSystem_Common::grabOverlay(OverlayColor *buf, int pitch) {
     1186        assert (_transactionMode == kTransactionNone);
     1187
     1188        if (_overlayscreen == NULL)
     1189                return;
     1190
     1191        if (SDL_LockSurface(_overlayscreen) == -1)
     1192                error("SDL_LockSurface failed: %s", SDL_GetError());
     1193
     1194        byte *src = (byte *)_overlayscreen->pixels;
     1195        int h = _overlayHeight;
     1196        do {
     1197                memcpy(buf, src, _overlayWidth * 2);
     1198                src += _overlayscreen->pitch;
     1199                buf += pitch;
     1200        } while (--h);
     1201
     1202        SDL_UnlockSurface(_overlayscreen);
     1203}
     1204
     1205void OSystem_Common::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) {
     1206        assert (_transactionMode == kTransactionNone);
     1207
     1208        if (_overlayscreen == NULL)
     1209                return;
     1210
     1211        // Clip the coordinates
     1212        if (x < 0) {
     1213                w += x;
     1214                buf -= x;
     1215                x = 0;
     1216        }
     1217
     1218        if (y < 0) {
     1219                h += y; buf -= y * pitch;
     1220                y = 0;
     1221        }
     1222
     1223        if (w > _overlayWidth - x) {
     1224                w = _overlayWidth - x;
     1225        }
     1226
     1227        if (h > _overlayHeight - y) {
     1228                h = _overlayHeight - y;
     1229        }
     1230
     1231        if (w <= 0 || h <= 0)
     1232                return;
     1233
     1234        // Mark the modified region as dirty
     1235        _cksumValid = false;
     1236        addDirtyRect(x, y, w, h);
     1237
     1238        if (SDL_LockSurface(_overlayscreen) == -1)
     1239                error("SDL_LockSurface failed: %s", SDL_GetError());
     1240
     1241        byte *dst = (byte *)_overlayscreen->pixels + y * _overlayscreen->pitch + x * 2;
     1242        do {
     1243                memcpy(dst, buf, w * 2);
     1244                dst += _overlayscreen->pitch;
     1245                buf += pitch;
     1246        } while (--h);
     1247
     1248        SDL_UnlockSurface(_overlayscreen);
     1249}
     1250
     1251OverlayColor OSystem_Common::RGBToColor(uint8 r, uint8 g, uint8 b) {
     1252        return SDL_MapRGB(_overlayscreen->format, r, g, b);
     1253}
     1254
     1255void OSystem_Common::colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b) {
     1256        SDL_GetRGB(color, _overlayscreen->format, &r, &g, &b);
     1257}
     1258
     1259
     1260#pragma mark -
     1261#pragma mark --- Mouse ---
     1262#pragma mark -
     1263
     1264bool OSystem_Common::showMouse(bool visible) {
     1265        if (_mouseVisible == visible)
     1266                return visible;
     1267
     1268        bool last = _mouseVisible;
     1269        _mouseVisible = visible;
     1270
     1271        return last;
     1272}
     1273
     1274void OSystem_Common::setMousePos(int x, int y) {
     1275        if (x != _mouseCurState.x || y != _mouseCurState.y) {
     1276                _mouseCurState.x = x;
     1277                _mouseCurState.y = y;
     1278        }
     1279}
     1280
     1281void OSystem_Common::warpMouse(int x, int y) {
     1282        int y1 = y;
     1283
     1284        if (_adjustAspectRatio && !_overlayVisible)
     1285                y1 = real2Aspect(y);
     1286
     1287        if (_mouseCurState.x != x || _mouseCurState.y != y) {
     1288                if (!_overlayVisible)
     1289                        SDL_WarpMouse(x * _scaleFactor, y1 * _scaleFactor);
     1290                else
     1291                        SDL_WarpMouse(x, y1);
     1292
     1293                // SDL_WarpMouse() generates a mouse movement event, so
     1294                // setMousePos() would be called eventually. However, the
     1295                // cannon script in CoMI calls this function twice each time
     1296                // the cannon is reloaded. Unless we update the mouse position
     1297                // immediately the second call is ignored, causing the cannon
     1298                // to change its aim.
     1299
     1300                setMousePos(x, y);
     1301        }
     1302}
     1303
     1304void OSystem_Common::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale) {
     1305        if (w == 0 || h == 0)
     1306                return;
     1307
     1308        _mouseCurState.hotX = hotspot_x;
     1309        _mouseCurState.hotY = hotspot_y;
     1310
     1311        _mouseKeyColor = keycolor;
     1312
     1313        _cursorTargetScale = cursorTargetScale;
     1314
     1315        if (_mouseCurState.w != (int)w || _mouseCurState.h != (int)h) {
     1316                _mouseCurState.w = w;
     1317                _mouseCurState.h = h;
     1318
     1319                if (_mouseOrigSurface)
     1320                        SDL_FreeSurface(_mouseOrigSurface);
     1321
     1322                // Allocate bigger surface because AdvMame2x adds black pixel at [0,0]
     1323                _mouseOrigSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA,
     1324                                                _mouseCurState.w + 2,
     1325                                                _mouseCurState.h + 2,
     1326                                                16,
     1327                                                _hwscreen->format->Rmask,
     1328                                                _hwscreen->format->Gmask,
     1329                                                _hwscreen->format->Bmask,
     1330                                                _hwscreen->format->Amask);
     1331
     1332                if (_mouseOrigSurface == NULL)
     1333                        error("allocating _mouseOrigSurface failed");
     1334                SDL_SetColorKey(_mouseOrigSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kMouseColorKey);
     1335        }
     1336
     1337        free(_mouseData);
     1338
     1339        _mouseData = (byte *)malloc(w * h);
     1340        memcpy(_mouseData, buf, w * h);
     1341        blitCursor();
     1342}
     1343
     1344void OSystem_Common::blitCursor() {
     1345        byte *dstPtr;
     1346        const byte *srcPtr = _mouseData;
     1347        byte color;
     1348        int w, h, i, j;
     1349
     1350        if (!_mouseOrigSurface || !_mouseData)
     1351                return;
     1352
     1353        w = _mouseCurState.w;
     1354        h = _mouseCurState.h;
     1355
     1356        SDL_LockSurface(_mouseOrigSurface);
     1357
     1358        // Make whole surface transparent
     1359        for (i = 0; i < h + 2; i++) {
     1360                dstPtr = (byte *)_mouseOrigSurface->pixels + _mouseOrigSurface->pitch * i;
     1361                for (j = 0; j < w + 2; j++) {
     1362                        *(uint16 *)dstPtr = kMouseColorKey;
     1363                        dstPtr += 2;
     1364                }
     1365        }
     1366
     1367        // Draw from [1,1] since AdvMame2x adds artefact at 0,0
     1368        dstPtr = (byte *)_mouseOrigSurface->pixels + _mouseOrigSurface->pitch + 2;
     1369
     1370        SDL_Color *palette;
     1371
     1372        if (_cursorPaletteDisabled)
     1373                palette = _currentPalette;
     1374        else
     1375                palette = _cursorPalette;
     1376       
     1377        for (i = 0; i < h; i++) {
     1378                for (j = 0; j < w; j++) {
     1379                        color = *srcPtr;
     1380                        if (color != _mouseKeyColor) {  // transparent, don't draw
     1381                                *(uint16 *)dstPtr = SDL_MapRGB(_mouseOrigSurface->format,
     1382                                        palette[color].r, palette[color].g, palette[color].b);
     1383                        }
     1384                        dstPtr += 2;
     1385                        srcPtr++;
     1386                }
     1387                dstPtr += _mouseOrigSurface->pitch - w * 2;
     1388        }
     1389
     1390        int rW, rH;
     1391
     1392        if (_cursorTargetScale >= _scaleFactor) {
     1393                // The cursor target scale is greater or equal to the scale at
     1394                // which the rest of the screen is drawn. We do not downscale
     1395                // the cursor image, we draw it at its original size. It will
     1396                // appear too large on screen.
     1397
     1398                rW = w;
     1399                rH = h;
     1400                _mouseCurState.rHotX = _mouseCurState.hotX;
     1401                _mouseCurState.rHotY = _mouseCurState.hotY;
     1402
     1403                // The virtual dimensions may be larger than the original.
     1404
     1405                _mouseCurState.vW = w * _cursorTargetScale / _scaleFactor;
     1406                _mouseCurState.vH = h * _cursorTargetScale / _scaleFactor;
     1407                _mouseCurState.vHotX = _mouseCurState.hotX * _cursorTargetScale /
     1408                        _scaleFactor;
     1409                _mouseCurState.vHotY = _mouseCurState.hotY * _cursorTargetScale /
     1410                        _scaleFactor;
     1411        } else {
     1412                // The cursor target scale is smaller than the scale at which
     1413                // the rest of the screen is drawn. We scale up the cursor
     1414                // image to make it appear correct.
     1415
     1416                rW = w * _scaleFactor / _cursorTargetScale;
     1417                rH = h * _scaleFactor / _cursorTargetScale;
     1418                _mouseCurState.rHotX = _mouseCurState.hotX * _scaleFactor /
     1419                        _cursorTargetScale;
     1420                _mouseCurState.rHotY = _mouseCurState.hotY * _scaleFactor /
     1421                        _cursorTargetScale;
     1422
     1423                // The virtual dimensions will be the same as the original.
     1424
     1425                _mouseCurState.vW = w;
     1426                _mouseCurState.vH = h;
     1427                _mouseCurState.vHotX = _mouseCurState.hotX;
     1428                _mouseCurState.vHotY = _mouseCurState.hotY;
     1429        }
     1430
     1431        int rH1 = rH; // store original to pass to aspect-correction function later
     1432        if (_adjustAspectRatio && _cursorTargetScale == 1) {
     1433                rH = real2Aspect(rH - 1) + 1;
     1434                _mouseCurState.rHotY = real2Aspect(_mouseCurState.rHotY);
     1435        }
     1436
     1437        if (_mouseCurState.rW != rW || _mouseCurState.rH != rH) {
     1438                _mouseCurState.rW = rW;
     1439                _mouseCurState.rH = rH;
     1440
     1441                if (_mouseSurface)
     1442                        SDL_FreeSurface(_mouseSurface);
     1443
     1444                _mouseSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA,
     1445                                                _mouseCurState.rW,
     1446                                                _mouseCurState.rH,
     1447                                                16,
     1448                                                _hwscreen->format->Rmask,
     1449                                                _hwscreen->format->Gmask,
     1450                                                _hwscreen->format->Bmask,
     1451                                                _hwscreen->format->Amask);
     1452
     1453                if (_mouseSurface == NULL)
     1454                        error("allocating _mouseSurface failed");
     1455
     1456                SDL_SetColorKey(_mouseSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kMouseColorKey);
     1457        }
     1458
     1459        SDL_LockSurface(_mouseSurface);
     1460
     1461        ScalerProc *scalerProc;
     1462
     1463        // If possible, use the same scaler for the cursor as for the rest of
     1464        // the game. This only works well with the non-blurring scalers so we
     1465        // actually only use the 1x, 1.5x, 2x and AdvMame scalers.
     1466
     1467        if (_cursorTargetScale == 1 && (_mode == GFX_DOUBLESIZE || _mode == GFX_TRIPLESIZE))
     1468                scalerProc = _scalerProc;
     1469        else
     1470                scalerProc = scalersMagn[_cursorTargetScale - 1][_scaleFactor - 1];
     1471
     1472        scalerProc((byte *)_mouseOrigSurface->pixels + _mouseOrigSurface->pitch + 2,
     1473                _mouseOrigSurface->pitch, (byte *)_mouseSurface->pixels, _mouseSurface->pitch,
     1474                _mouseCurState.w, _mouseCurState.h);
     1475
     1476#ifndef DISABLE_SCALERS
     1477        if (_adjustAspectRatio && _cursorTargetScale == 1)
     1478                cursorStretch200To240((uint8 *)_mouseSurface->pixels, _mouseSurface->pitch, rW, rH1, 0, 0, 0);
     1479#endif
     1480
     1481        SDL_UnlockSurface(_mouseSurface);
     1482        SDL_UnlockSurface(_mouseOrigSurface);
     1483}
     1484
     1485#ifndef DISABLE_SCALERS
     1486// Basically it is kVeryFastAndUglyAspectMode of stretch200To240 from
     1487// common/scale/aspect.cpp
     1488static int cursorStretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY) {
     1489        int maxDstY = real2Aspect(origSrcY + height - 1);
     1490        int y;
     1491        const uint8 *startSrcPtr = buf + srcX * 2 + (srcY - origSrcY) * pitch;
     1492        uint8 *dstPtr = buf + srcX * 2 + maxDstY * pitch;
     1493
     1494        for (y = maxDstY; y >= srcY; y--) {
     1495                const uint8 *srcPtr = startSrcPtr + aspect2Real(y) * pitch;
     1496
     1497                if (srcPtr == dstPtr)
     1498                        break;
     1499                memcpy(dstPtr, srcPtr, width * 2);
     1500                dstPtr -= pitch;
     1501        }
     1502
     1503        return 1 + maxDstY - srcY;
     1504}
     1505#endif
     1506
     1507void OSystem_Common::toggleMouseGrab() {
     1508        if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF)
     1509                SDL_WM_GrabInput(SDL_GRAB_ON);
     1510        else
     1511                SDL_WM_GrabInput(SDL_GRAB_OFF);
     1512}
     1513
     1514void OSystem_Common::undrawMouse() {
     1515        const int x = _mouseBackup.x;
     1516        const int y = _mouseBackup.y;
     1517
     1518        // When we switch bigger overlay off mouse jumps. Argh!
     1519        // This is intended to prevent undrawing offscreen mouse
     1520        if (!_overlayVisible && (x >= _screenWidth || y >= _screenHeight)) {
     1521                return;
     1522        }
     1523
     1524        if (_mouseBackup.w != 0 && _mouseBackup.h != 0)
     1525                addDirtyRect(x, y, _mouseBackup.w, _mouseBackup.h);
     1526}
     1527
     1528void OSystem_Common::drawMouse() {
     1529        if (!_mouseVisible || !_mouseSurface) {
     1530                _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0;
     1531                return;
     1532        }
     1533
     1534        SDL_Rect dst;
     1535        int scale;
     1536        int width, height;
     1537        int hotX, hotY;
     1538
     1539        dst.x = _mouseCurState.x;
     1540        dst.y = _mouseCurState.y;
     1541
     1542        if (!_overlayVisible) {
     1543                scale = _scaleFactor;
     1544                width = _screenWidth;
     1545                height = _screenHeight;
     1546                dst.w = _mouseCurState.vW;
     1547                dst.h = _mouseCurState.vH;
     1548                hotX = _mouseCurState.vHotX;
     1549                hotY = _mouseCurState.vHotY;
     1550        } else {
     1551                scale = 1;
     1552                width = _overlayWidth;
     1553                height = _overlayHeight;
     1554                dst.w = _mouseCurState.rW;
     1555                dst.h = _mouseCurState.rH;
     1556                hotX = _mouseCurState.rHotX;
     1557                hotY = _mouseCurState.rHotY;
     1558        }
     1559
     1560        // The mouse is undrawn using virtual coordinates, i.e. they may be
     1561        // scaled and aspect-ratio corrected.
     1562
     1563        _mouseBackup.x = dst.x - hotX;
     1564        _mouseBackup.y = dst.y - hotY;
     1565        _mouseBackup.w = dst.w;
     1566        _mouseBackup.h = dst.h;
     1567
     1568        // We draw the pre-scaled cursor image, so now we need to adjust for
     1569        // scaling, shake position and aspect ratio correction manually.
     1570
     1571        if (!_overlayVisible) {
     1572                dst.y += _currentShakePos;
     1573        }
     1574
     1575        if (_adjustAspectRatio && !_overlayVisible)
     1576                dst.y = real2Aspect(dst.y);
     1577 
     1578        dst.x = scale * dst.x - _mouseCurState.rHotX;
     1579        dst.y = scale * dst.y - _mouseCurState.rHotY;
     1580        dst.w = _mouseCurState.rW;
     1581        dst.h = _mouseCurState.rH;
     1582
     1583        // Note that SDL_BlitSurface() and addDirtyRect() will both perform any
     1584        // clipping necessary
     1585
     1586        if (SDL_BlitSurface(_mouseSurface, NULL, _hwscreen, &dst) != 0)
     1587                error("SDL_BlitSurface failed: %s", SDL_GetError());
     1588
     1589        // The screen will be updated using real surface coordinates, i.e.
     1590        // they will not be scaled or aspect-ratio corrected.
     1591
     1592        addDirtyRect(dst.x, dst.y, dst.w, dst.h, true);
     1593}
     1594
     1595#pragma mark -
     1596#pragma mark --- On Screen Display ---
     1597#pragma mark -
     1598
     1599#ifdef USE_OSD
     1600void OSystem_Common::displayMessageOnOSD(const char *msg) {
     1601        assert (_transactionMode == kTransactionNone);
     1602        assert(msg);
     1603
     1604        Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
     1605
     1606        uint i;
     1607
     1608        // Lock the OSD surface for drawing
     1609        if (SDL_LockSurface(_osdSurface))
     1610                error("displayMessageOnOSD: SDL_LockSurface failed: %s", SDL_GetError());
     1611
     1612        Graphics::Surface dst;
     1613        dst.pixels = _osdSurface->pixels;
     1614        dst.w = _osdSurface->w;
     1615        dst.h = _osdSurface->h;
     1616        dst.pitch = _osdSurface->pitch;
     1617        dst.bytesPerPixel = _osdSurface->format->BytesPerPixel;
     1618
     1619        // The font we are going to use:
     1620        const Graphics::Font *font = FontMan.getFontByUsage(Graphics::FontManager::kOSDFont);
     1621
     1622        // Clear everything with the "transparent" color, i.e. the colorkey
     1623        SDL_FillRect(_osdSurface, 0, kOSDColorKey);
     1624
     1625        // Split the message into separate lines.
     1626        Common::StringList lines;
     1627        const char *ptr;
     1628        for (ptr = msg; *ptr; ++ptr) {
     1629                if (*ptr == '\n') {
     1630                        lines.push_back(Common::String(msg, ptr - msg));
     1631                        msg = ptr + 1;
     1632                }
     1633        }
     1634        lines.push_back(Common::String(msg, ptr - msg));
     1635
     1636        // Determine a rect which would contain the message string (clipped to the
     1637        // screen dimensions).
     1638        const int vOffset = 6;
     1639        const int lineSpacing = 1;
     1640        const int lineHeight = font->getFontHeight() + 2 * lineSpacing;
     1641        int width = 0;
     1642        int height = lineHeight * lines.size() + 2 * vOffset;
     1643        for (i = 0; i < lines.size(); i++) {
     1644                width = MAX(width, font->getStringWidth(lines[i]) + 14);
     1645        }
     1646
     1647        // Clip the rect
     1648        if (width > dst.w)
     1649                width = dst.w;
     1650        if (height > dst.h)
     1651                height = dst.h;
     1652
     1653        // Draw a dark gray rect
     1654        // TODO: Rounded corners ? Border?
     1655        SDL_Rect osdRect;
     1656        osdRect.x = (dst.w - width) / 2;
     1657        osdRect.y = (dst.h - height) / 2;
     1658        osdRect.w = width;
     1659        osdRect.h = height;
     1660        SDL_FillRect(_osdSurface, &osdRect, SDL_MapRGB(_osdSurface->format, 64, 64, 64));
     1661
     1662        // Render the message, centered, and in white
     1663        for (i = 0; i < lines.size(); i++) {
     1664                font->drawString(&dst, lines[i],
     1665                                                        osdRect.x, osdRect.y + i * lineHeight + vOffset + lineSpacing, osdRect.w,
     1666                                                        SDL_MapRGB(_osdSurface->format, 255, 255, 255),
     1667                                                        Graphics::kTextAlignCenter);
     1668        }
     1669
     1670        // Finished drawing, so unlock the OSD surface again
     1671        SDL_UnlockSurface(_osdSurface);
     1672
     1673        // Init the OSD display parameters, and the fade out
     1674        _osdAlpha = SDL_ALPHA_TRANSPARENT +  kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100;
     1675        _osdFadeStartTime = SDL_GetTicks() + kOSDFadeOutDelay;
     1676        SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha);
     1677
     1678        // Ensure a full redraw takes place next time the screen is updated
     1679        _forceFull = true;
     1680}
     1681#endif
     1682
     1683
     1684#pragma mark -
     1685#pragma mark --- Misc ---
     1686#pragma mark -
     1687
     1688void OSystem_Common::handleScalerHotkeys(const SDL_KeyboardEvent &key) {
     1689        // Ctrl-Alt-a toggles aspect ratio correction
     1690        if (key.keysym.sym == 'a') {
     1691                setFeatureState(kFeatureAspectRatioCorrection, !_adjustAspectRatio);
     1692#ifdef USE_OSD
     1693                char buffer[128];
     1694                if (_adjustAspectRatio)
     1695                        sprintf(buffer, "Enabled aspect ratio correction\n%d x %d -> %d x %d",
     1696                                _screenWidth, _screenHeight,
     1697                                _hwscreen->w, _hwscreen->h
     1698                                );
     1699                else
     1700                        sprintf(buffer, "Disabled aspect ratio correction\n%d x %d -> %d x %d",
     1701                                _screenWidth, _screenHeight,
     1702                                _hwscreen->w, _hwscreen->h
     1703                                );
     1704                displayMessageOnOSD(buffer);
     1705#endif
     1706
     1707                return;
     1708        }
     1709
     1710        int newMode = -1;
     1711        int factor = _scaleFactor - 1;
     1712
     1713        // Increase/decrease the scale factor
     1714        if (key.keysym.sym == SDLK_EQUALS || key.keysym.sym == SDLK_PLUS || key.keysym.sym == SDLK_MINUS ||
     1715                key.keysym.sym == SDLK_KP_PLUS || key.keysym.sym == SDLK_KP_MINUS) {
     1716                factor += (key.keysym.sym == SDLK_MINUS || key.keysym.sym == SDLK_KP_MINUS) ? -1 : +1;
     1717                if (0 <= factor && factor <= 3) {
     1718                        newMode = s_gfxModeSwitchTable[_scalerType][factor];
     1719                }
     1720        }
     1721
     1722        const bool isNormalNumber = (SDLK_1 <= key.keysym.sym && key.keysym.sym <= SDLK_9);
     1723        const bool isKeypadNumber = (SDLK_KP1 <= key.keysym.sym && key.keysym.sym <= SDLK_KP9);
     1724        if (isNormalNumber || isKeypadNumber) {
     1725                _scalerType = key.keysym.sym - (isNormalNumber ? SDLK_1 : SDLK_KP1);
     1726                if (_scalerType >= ARRAYSIZE(s_gfxModeSwitchTable))
     1727                        return;
     1728
     1729                while (s_gfxModeSwitchTable[_scalerType][factor] < 0) {
     1730                        assert(factor > 0);
     1731                        factor--;
     1732                }
     1733                newMode = s_gfxModeSwitchTable[_scalerType][factor];
     1734        }
     1735
     1736        if (newMode >= 0) {
     1737                setGraphicsMode(newMode);
     1738#ifdef USE_OSD
     1739                if (_osdSurface) {
     1740                        const char *newScalerName = 0;
     1741                        const GraphicsMode *g = getSupportedGraphicsModes();
     1742                        while (g->name) {
     1743                                if (g->id == _mode) {
     1744                                        newScalerName = g->description;
     1745                                        break;
     1746                                }
     1747                                g++;
     1748                        }
     1749                        if (newScalerName) {
     1750                                char buffer[128];
     1751                                sprintf(buffer, "Active graphics filter: %s\n%d x %d -> %d x %d",
     1752                                        newScalerName,
     1753                                        _screenWidth, _screenHeight,
     1754                                        _hwscreen->w, _hwscreen->h
     1755                                        );
     1756                                displayMessageOnOSD(buffer);
     1757                        }
     1758                }
     1759#endif
     1760
     1761        }
     1762
     1763}
  • D:/programming/projects/gsoc/scummvm/backends/platform/common/module.mk

     
     1MODULE := backends/platform/common
     2
     3MODULE_OBJS := \
     4        common-events.o \
     5        common-graphics.o \
     6        common-system.o
     7
     8MODULE_DIRS += \
     9        backends/platform/common/
     10
     11# We don't use the rules.mk here on purpose
     12OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) $(OBJS)
  • D:/programming/projects/gsoc/scummvm/backends/platform/common/common-events.cpp

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/sdl/events.cpp $
     22 * $Id: events.cpp 27787 2007-06-30 12:39:12Z fingolfin $
     23 *
     24 */
     25
     26#include "backends/platform/common/common-system.h"
     27#include "common/util.h"
     28#include "common/events.h"
     29
     30// FIXME move joystick defines out and replace with confile file options
     31// we should really allow users to map any key to a joystick button
     32#define JOY_DEADZONE 3200
     33
     34#ifndef __SYMBIAN32__ // Symbian wants dialog joystick i.e cursor for movement/selection
     35        #define JOY_ANALOG
     36#endif
     37
     38// #define JOY_INVERT_Y
     39#define JOY_XAXIS 0
     40#define JOY_YAXIS 1
     41// buttons
     42#define JOY_BUT_LMOUSE 0
     43#define JOY_BUT_RMOUSE 2
     44#define JOY_BUT_ESCAPE 3
     45#define JOY_BUT_PERIOD 1
     46#define JOY_BUT_SPACE 4
     47#define JOY_BUT_F5 5
     48
     49
     50
     51
     52static int mapKey(SDLKey key, SDLMod mod, Uint16 unicode)
     53{
     54        if (key >= SDLK_F1 && key <= SDLK_F9) {
     55                return key - SDLK_F1 + Common::ASCII_F1;
     56        } else if (key >= SDLK_KP0 && key <= SDLK_KP9) {
     57                return key - SDLK_KP0 + '0';
     58        } else if (key >= SDLK_UP && key <= SDLK_PAGEDOWN) {
     59                return key;
     60        } else if (unicode) {
     61                return unicode;
     62        } else if (key >= 'a' && key <= 'z' && (mod & KMOD_SHIFT)) {
     63                return key & ~0x20;
     64        } else if (key >= SDLK_NUMLOCK && key <= SDLK_EURO) {
     65                return 0;
     66        }
     67        return key;
     68}
     69
     70void OSystem_Common::fillMouseEvent(Common::Event &event, int x, int y) {
     71        event.mouse.x = x;
     72        event.mouse.y = y;
     73
     74        // Update the "keyboard mouse" coords
     75        _km.x = x;
     76        _km.y = y;
     77
     78        // Adjust for the screen scaling
     79        if (!_overlayVisible) {
     80                event.mouse.x /= _scaleFactor;
     81                event.mouse.y /= _scaleFactor;
     82                if (_adjustAspectRatio)
     83                        event.mouse.y = aspect2Real(event.mouse.y);
     84        }
     85}
     86
     87void OSystem_Common::handleKbdMouse() {
     88        uint32 curTime = getMillis();
     89        if (curTime >= _km.last_time + _km.delay_time) {
     90                _km.last_time = curTime;
     91                if (_km.x_down_count == 1) {
     92                        _km.x_down_time = curTime;
     93                        _km.x_down_count = 2;
     94                }
     95                if (_km.y_down_count == 1) {
     96                        _km.y_down_time = curTime;
     97                        _km.y_down_count = 2;
     98                }
     99
     100                if (_km.x_vel || _km.y_vel) {
     101                        if (_km.x_down_count) {
     102                                if (curTime > _km.x_down_time + _km.delay_time * 12) {
     103                                        if (_km.x_vel > 0)
     104                                                _km.x_vel++;
     105                                        else
     106                                                _km.x_vel--;
     107                                } else if (curTime > _km.x_down_time + _km.delay_time * 8) {
     108                                        if (_km.x_vel > 0)
     109                                                _km.x_vel = 5;
     110                                        else
     111                                                _km.x_vel = -5;
     112                                }
     113                        }
     114                        if (_km.y_down_count) {
     115                                if (curTime > _km.y_down_time + _km.delay_time * 12) {
     116                                        if (_km.y_vel > 0)
     117                                                _km.y_vel++;
     118                                        else
     119                                                _km.y_vel--;
     120                                } else if (curTime > _km.y_down_time + _km.delay_time * 8) {
     121                                        if (_km.y_vel > 0)
     122                                                _km.y_vel = 5;
     123                                        else
     124                                                _km.y_vel = -5;
     125                                }
     126                        }
     127
     128                        _km.x += _km.x_vel;
     129                        _km.y += _km.y_vel;
     130
     131                        if (_km.x < 0) {
     132                                _km.x = 0;
     133                                _km.x_vel = -1;
     134                                _km.x_down_count = 1;
     135                        } else if (_km.x > _km.x_max) {
     136                                _km.x = _km.x_max;
     137                                _km.x_vel = 1;
     138                                _km.x_down_count = 1;
     139                        }
     140
     141                        if (_km.y < 0) {
     142                                _km.y = 0;
     143                                _km.y_vel = -1;
     144                                _km.y_down_count = 1;
     145                        } else if (_km.y > _km.y_max) {
     146                                _km.y = _km.y_max;
     147                                _km.y_vel = 1;
     148                                _km.y_down_count = 1;
     149                        }
     150
     151                        SDL_WarpMouse(_km.x, _km.y);
     152                }
     153        }
     154}
     155
     156static byte SDLModToOSystemKeyFlags(SDLMod mod) {
     157        byte b = 0;
     158#ifdef LINUPY
     159        // Yopy has no ALT key, steal the SHIFT key
     160        // (which isn't used much anyway)
     161        if (mod & KMOD_SHIFT)
     162                b |= Common::KBD_ALT;
     163#else
     164        if (mod & KMOD_SHIFT)
     165                b |= Common::KBD_SHIFT;
     166        if (mod & KMOD_ALT)
     167                b |= Common::KBD_ALT;
     168#endif
     169        if (mod & KMOD_CTRL)
     170                b |= Common::KBD_CTRL;
     171
     172        return b;
     173}
     174
     175bool OSystem_Common::pollEvent(Common::Event &event) {
     176        SDL_Event ev;
     177        int axis;
     178        byte b = 0;
     179
     180        handleKbdMouse();
     181
     182        // If the screen mode changed, send an Common::EVENT_SCREEN_CHANGED
     183        if (_modeChanged) {
     184                _modeChanged = false;
     185                event.type = Common::EVENT_SCREEN_CHANGED;
     186                _screenChangeCount++;
     187                return true;
     188        }
     189
     190        while (SDL_PollEvent(&ev)) {
     191                switch (ev.type) {
     192                case SDL_KEYDOWN:{
     193                        b = event.kbd.flags = SDLModToOSystemKeyFlags(SDL_GetModState());
     194
     195                        // Alt-Return and Alt-Enter toggle full screen mode
     196                        if (b == Common::KBD_ALT && (ev.key.keysym.sym == SDLK_RETURN
     197                                          || ev.key.keysym.sym == SDLK_KP_ENTER)) {
     198                                setFullscreenMode(!_fullscreen);
     199#ifdef USE_OSD
     200                                if (_fullscreen)
     201                                        displayMessageOnOSD("Fullscreen mode");
     202                                else
     203                                        displayMessageOnOSD("Windowed mode");
     204#endif
     205
     206                                break;
     207                        }
     208
     209                        // Alt-S: Create a screenshot
     210                        if (b == Common::KBD_ALT && ev.key.keysym.sym == 's') {
     211                                char filename[20];
     212
     213                                for (int n = 0;; n++) {
     214                                        SDL_RWops *file;
     215
     216                                        sprintf(filename, "scummvm%05d.bmp", n);
     217                                        file = SDL_RWFromFile(filename, "r");
     218                                        if (!file)
     219                                                break;
     220                                        SDL_RWclose(file);
     221                                }
     222                                if (saveScreenshot(filename))
     223                                        printf("Saved '%s'\n", filename);
     224                                else
     225                                        printf("Could not save screenshot!\n");
     226                                break;
     227                        }
     228
     229                        // Ctrl-m toggles mouse capture
     230                        if (b == Common::KBD_CTRL && ev.key.keysym.sym == 'm') {
     231                                toggleMouseGrab();
     232                                break;
     233                        }
     234
     235#if defined(MACOSX) || defined(__AMIGA__)
     236                        // On Macintosh', Cmd-Q quits
     237                        // On Amigas, Amiga-Q quits
     238                        if ((ev.key.keysym.mod & KMOD_META) && ev.key.keysym.sym == 'q') {
     239                                event.type = Common::EVENT_QUIT;
     240                                return true;
     241                        }
     242#elif defined(UNIX)
     243                        // On other unices, Control-Q quits
     244                        if ((ev.key.keysym.mod & KMOD_CTRL) && ev.key.keysym.sym == 'q') {
     245                                event.type = Common::EVENT_QUIT;
     246                                return true;
     247                        }
     248#else
     249                        // Ctrl-z and Alt-X quit
     250                        if ((b == Common::KBD_CTRL && ev.key.keysym.sym == 'z') || (b == Common::KBD_ALT && ev.key.keysym.sym == 'x')) {
     251                                event.type = Common::EVENT_QUIT;
     252                                return true;
     253                        }
     254#endif
     255
     256                        // Ctrl-Alt-<key> will change the GFX mode
     257                        if ((b & (Common::KBD_CTRL|Common::KBD_ALT)) == (Common::KBD_CTRL|Common::KBD_ALT)) {
     258
     259                                handleScalerHotkeys(ev.key);
     260                                break;
     261                        }
     262                        const bool event_complete = remapKey(ev, event);
     263
     264                        if (event_complete)
     265                                return true;
     266
     267                        event.type = Common::EVENT_KEYDOWN;
     268                        event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym;
     269                        event.kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode);
     270
     271                        return true;
     272                        }
     273                case SDL_KEYUP:
     274                        {
     275                        const bool event_complete = remapKey(ev,event);
     276
     277                        if (event_complete)
     278                                return true;
     279
     280                        event.type = Common::EVENT_KEYUP;
     281                        event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym;
     282                        event.kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode);
     283                        b = event.kbd.flags = SDLModToOSystemKeyFlags(SDL_GetModState());
     284
     285                        // Ctrl-Alt-<key> will change the GFX mode
     286                        if ((b & (Common::KBD_CTRL|Common::KBD_ALT)) == (Common::KBD_CTRL|Common::KBD_ALT)) {
     287                                // Swallow these key up events
     288                                break;
     289                        }
     290
     291                        return true;
     292                        }
     293                case SDL_MOUSEMOTION:
     294                        event.type = Common::EVENT_MOUSEMOVE;
     295                        fillMouseEvent(event, ev.motion.x, ev.motion.y);
     296
     297                        setMousePos(event.mouse.x, event.mouse.y);
     298                        return true;
     299
     300                case SDL_MOUSEBUTTONDOWN:
     301                        if (ev.button.button == SDL_BUTTON_LEFT)
     302                                event.type = Common::EVENT_LBUTTONDOWN;
     303                        else if (ev.button.button == SDL_BUTTON_RIGHT)
     304                                event.type = Common::EVENT_RBUTTONDOWN;
     305#if defined(SDL_BUTTON_WHEELUP) && defined(SDL_BUTTON_WHEELDOWN)
     306                        else if (ev.button.button == SDL_BUTTON_WHEELUP)
     307                                event.type = Common::EVENT_WHEELUP;
     308                        else if (ev.button.button == SDL_BUTTON_WHEELDOWN)
     309                                event.type = Common::EVENT_WHEELDOWN;
     310#endif
     311                        else
     312                                break;
     313
     314                        fillMouseEvent(event, ev.button.x, ev.button.y);
     315
     316                        return true;
     317
     318                case SDL_MOUSEBUTTONUP:
     319                        if (ev.button.button == SDL_BUTTON_LEFT)
     320                                event.type = Common::EVENT_LBUTTONUP;
     321                        else if (ev.button.button == SDL_BUTTON_RIGHT)
     322                                event.type = Common::EVENT_RBUTTONUP;
     323                        else
     324                                break;
     325                        fillMouseEvent(event, ev.button.x, ev.button.y);
     326
     327                        return true;
     328
     329                case SDL_JOYBUTTONDOWN:
     330                        if (ev.jbutton.button == JOY_BUT_LMOUSE) {
     331                                event.type = Common::EVENT_LBUTTONDOWN;
     332                                fillMouseEvent(event, _km.x, _km.y);
     333                        } else if (ev.jbutton.button == JOY_BUT_RMOUSE) {
     334                                event.type = Common::EVENT_RBUTTONDOWN;
     335                                fillMouseEvent(event, _km.x, _km.y);
     336                        } else {
     337                                event.type = Common::EVENT_KEYDOWN;
     338                                switch (ev.jbutton.button) {
     339                                case JOY_BUT_ESCAPE:
     340                                        event.kbd.keycode = Common::KEYCODE_ESCAPE;
     341                                        event.kbd.ascii = mapKey(SDLK_ESCAPE, ev.key.keysym.mod, 0);
     342                                        break;
     343                                case JOY_BUT_PERIOD:
     344                                        event.kbd.keycode = Common::KEYCODE_PERIOD;
     345                                        event.kbd.ascii = mapKey(SDLK_PERIOD, ev.key.keysym.mod, 0);
     346                                        break;
     347                                case JOY_BUT_SPACE:
     348                                        event.kbd.keycode = Common::KEYCODE_SPACE;
     349                                        event.kbd.ascii = mapKey(SDLK_SPACE, ev.key.keysym.mod, 0);
     350                                        break;
     351                                case JOY_BUT_F5:
     352                                        event.kbd.keycode = Common::KEYCODE_F5;
     353                                        event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0);
     354                                        break;
     355                                }
     356                        }
     357                        return true;
     358
     359                case SDL_JOYBUTTONUP:
     360                        if (ev.jbutton.button == JOY_BUT_LMOUSE) {
     361                                event.type = Common::EVENT_LBUTTONUP;
     362                                fillMouseEvent(event, _km.x, _km.y);
     363                        } else if (ev.jbutton.button == JOY_BUT_RMOUSE) {
     364                                event.type = Common::EVENT_RBUTTONUP;
     365                                fillMouseEvent(event, _km.x, _km.y);
     366                        } else {
     367                                event.type = Common::EVENT_KEYUP;
     368                                switch (ev.jbutton.button) {
     369                                case JOY_BUT_ESCAPE:
     370                                        event.kbd.keycode = Common::KEYCODE_ESCAPE;
     371                                        event.kbd.ascii = mapKey(SDLK_ESCAPE, ev.key.keysym.mod, 0);
     372                                        break;
     373                                case JOY_BUT_PERIOD:
     374                                        event.kbd.keycode = Common::KEYCODE_PERIOD;
     375                                        event.kbd.ascii = mapKey(SDLK_PERIOD, ev.key.keysym.mod, 0);
     376                                        break;
     377                                case JOY_BUT_SPACE:
     378                                        event.kbd.keycode = Common::KEYCODE_SPACE;
     379                                        event.kbd.ascii = mapKey(SDLK_SPACE, ev.key.keysym.mod, 0);
     380                                        break;
     381                                case JOY_BUT_F5:
     382                                        event.kbd.keycode = Common::KEYCODE_F5;
     383                                        event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0);
     384                                        break;
     385                                }
     386                        }
     387                        return true;
     388
     389                case SDL_JOYAXISMOTION:
     390                        axis = ev.jaxis.value;
     391                        if ( axis > JOY_DEADZONE) {
     392                                axis -= JOY_DEADZONE;
     393                                event.type = Common::EVENT_MOUSEMOVE;
     394                        } else if ( axis < -JOY_DEADZONE ) {
     395                                axis += JOY_DEADZONE;
     396                                event.type = Common::EVENT_MOUSEMOVE;
     397                        } else
     398                                axis = 0;
     399
     400                        if ( ev.jaxis.axis == JOY_XAXIS) {
     401#ifdef JOY_ANALOG
     402                                _km.x_vel = axis/2000;
     403                                _km.x_down_count = 0;
     404#else
     405                                if (axis != 0) {
     406                                        _km.x_vel = (axis > 0) ? 1:-1;
     407                                        _km.x_down_count = 1;
     408                                } else {
     409                                        _km.x_vel = 0;
     410                                        _km.x_down_count = 0;
     411                                }
     412#endif
     413
     414                        } else if (ev.jaxis.axis == JOY_YAXIS) {
     415#ifndef JOY_INVERT_Y
     416                                axis = -axis;
     417#endif
     418#ifdef JOY_ANALOG
     419                                _km.y_vel = -axis / 2000;
     420                                _km.y_down_count = 0;
     421#else
     422                                if (axis != 0) {
     423                                        _km.y_vel = (-axis > 0) ? 1: -1;
     424                                        _km.y_down_count = 1;
     425                                } else {
     426                                        _km.y_vel = 0;
     427                                        _km.y_down_count = 0;
     428                                }
     429#endif
     430                        }
     431
     432                        fillMouseEvent(event, _km.x, _km.y);
     433
     434                        return true;
     435
     436                case SDL_VIDEOEXPOSE:
     437                        _forceFull = true;
     438                        break;
     439
     440                case SDL_QUIT:
     441                        event.type = Common::EVENT_QUIT;
     442                        return true;
     443                }
     444        }
     445        return false;
     446}
     447
     448bool OSystem_Common::remapKey(SDL_Event &ev, Common::Event &event) {
     449#ifdef LINUPY
     450        // On Yopy map the End button to quit
     451        if ((ev.key.keysym.sym == 293)) {
     452                event.type = Common::EVENT_QUIT;
     453                return true;
     454        }
     455        // Map menu key to f5 (scumm menu)
     456        if (ev.key.keysym.sym == 306) {
     457                event.type = Common::EVENT_KEYDOWN;
     458                event.kbd.keycode = Common::KEYCODE_F5;
     459                event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0);
     460                return true;
     461        }
     462        // Map action key to action
     463        if (ev.key.keysym.sym == 291) {
     464                event.type = Common::EVENT_KEYDOWN;
     465                event.kbd.keycode = Common::KEYCODE_TAB;
     466                event.kbd.ascii = mapKey(SDLK_TAB, ev.key.keysym.mod, 0);
     467                return true;
     468        }
     469        // Map OK key to skip cinematic
     470        if (ev.key.keysym.sym == 292) {
     471                event.type = Common::EVENT_KEYDOWN;
     472                event.kbd.keycode = Common::KEYCODE_ESCAPE;
     473                event.kbd.ascii = mapKey(SDLK_ESCAPE, ev.key.keysym.mod, 0);
     474                return true;
     475        }
     476#endif
     477
     478#ifdef QTOPIA
     479        // Quit on fn+backspace on zaurus
     480        if (ev.key.keysym.sym == 127) {
     481                event.type = Common::EVENT_QUIT;
     482                return true;
     483        }
     484
     485        // Map menu key (f11) to f5 (scumm menu)
     486        if (ev.key.keysym.sym == SDLK_F11) {
     487                event.type = Common::EVENT_KEYDOWN;
     488                event.kbd.keycode = Common::KEYCODE_F5;
     489                event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0);
     490        }
     491        // Nap center (space) to tab (default action )
     492        // I wanted to map the calendar button but the calendar comes up
     493        //
     494        else if (ev.key.keysym.sym == SDLK_SPACE) {
     495                event.type = Common::EVENT_KEYDOWN;
     496                event.kbd.keycode = Common::KEYCODE_TAB;
     497                event.kbd.ascii = mapKey(SDLK_TAB, ev.key.keysym.mod, 0);
     498        }
     499        // Since we stole space (pause) above we'll rebind it to the tab key on the keyboard
     500        else if (ev.key.keysym.sym == SDLK_TAB) {
     501                event.type = Common::EVENT_KEYDOWN;
     502                event.kbd.keycode = Common::KEYCODE_SPACE;
     503                event.kbd.ascii = mapKey(SDLK_SPACE, ev.key.keysym.mod, 0);
     504        } else {
     505        // Let the events fall through if we didn't change them, this may not be the best way to
     506        // set it up, but i'm not sure how sdl would like it if we let if fall through then redid it though.
     507        // and yes i have an huge terminal size so i dont wrap soon enough.
     508                event.type = Common::EVENT_KEYDOWN;
     509                event.kbd.keycode = ev.key.keysym.sym;
     510                event.kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode);
     511        }
     512#endif
     513        return false;
     514}
     515
  • D:/programming/projects/gsoc/scummvm/backends/platform/common/common-system.cpp

     
     1/* ScummVM - Graphic Adventure Engine
     2 *
     3 * ScummVM is the legal property of its developers, whose names
     4 * are too numerous to list here. Please refer to the COPYRIGHT
     5 * file distributed with this source distribution.
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 *
     21 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/sdl/sdl.cpp $
     22 * $Id: sdl.cpp 27548 2007-06-19 22:39:59Z fingolfin $
     23 *
     24 */
     25
     26#if defined(WIN32)
     27#include <windows.h>
     28// winnt.h defines ARRAYSIZE, but we want our own one...
     29#undef ARRAYSIZE
     30#endif
     31
     32#include "backends/platform/common/common-system.h"
     33#include "backends/plugins/sdl/sdl-provider.h"
     34#include "common/config-manager.h"
     35#include "common/util.h"
     36#include "base/main.h"
     37
     38#include "backends/saves/default/default-saves.h"
     39#include "backends/timer/default/default-timer.h"
     40#include "sound/mixer.h"
     41
     42#include "icons/scummvm.xpm"
     43
     44#if defined(__SYMBIAN32__)
     45#include "SymbianOs.h"
     46#endif
     47
     48#ifndef __MAEMO__
     49
     50static Uint32 timer_handler(Uint32 interval, void *param) {
     51        ((DefaultTimerManager *)param)->handler();
     52        return interval;
     53}
     54
     55#ifndef _WIN32_WCE
     56
     57#if defined (WIN32)
     58int __stdcall WinMain(HINSTANCE /*hInst*/, HINSTANCE /*hPrevInst*/,  LPSTR /*lpCmdLine*/, int /*iShowCmd*/) {
     59        SDL_SetModuleHandle(GetModuleHandle(NULL));
     60        return main(__argc, __argv);
     61}
     62#endif
     63
     64int main(int argc, char *argv[]) {
     65
     66#if defined(__SYMBIAN32__)
     67        //
     68        // Set up redirects for stdout/stderr under Windows and Symbian.
     69        // Code copied from SDL_main.
     70        //
     71       
     72        // Symbian does not like any output to the console through any *print* function
     73        char STDOUT_FILE[256], STDERR_FILE[256]; // shhh, don't tell anybody :)
     74        strcpy(STDOUT_FILE, Symbian::GetExecutablePath());
     75        strcpy(STDERR_FILE, Symbian::GetExecutablePath());
     76        strcat(STDOUT_FILE, "scummvm.stdout.txt");
     77        strcat(STDERR_FILE, "scummvm.stderr.txt");
     78
     79        /* Flush the output in case anything is queued */
     80        fclose(stdout);
     81        fclose(stderr);
     82
     83        /* Redirect standard input and standard output */
     84        FILE *newfp = freopen(STDOUT_FILE, "w", stdout);
     85        if (newfp == NULL) {    /* This happens on NT */
     86#if !defined(stdout)
     87                stdout = fopen(STDOUT_FILE, "w");
     88#else
     89                newfp = fopen(STDOUT_FILE, "w");
     90                if (newfp) {
     91                        *stdout = *newfp;
     92                }
     93#endif
     94        }
     95        newfp = freopen(STDERR_FILE, "w", stderr);
     96        if (newfp == NULL) {    /* This happens on NT */
     97#if !defined(stderr)
     98                stderr = fopen(STDERR_FILE, "w");
     99#else
     100                newfp = fopen(STDERR_FILE, "w");
     101                if (newfp) {
     102                        *stderr = *newfp;
     103                }
     104#endif
     105        }
     106        setbuf(stderr, NULL);                   /* No buffering */
     107
     108#endif // defined(__SYMBIAN32__)
     109
     110        // Create our OSystem instance
     111#if defined(__SYMBIAN32__)
     112        g_system = new OSystem_Common_Symbian();
     113#else
     114        g_system = new OSystem_Common();
     115#endif
     116        assert(g_system);
     117
     118#ifdef DYNAMIC_MODULES
     119        PluginManager::instance().addPluginProvider(new SDLPluginProvider());
     120#endif
     121
     122        // Invoke the actual ScummVM main entry point:
     123        int res = scummvm_main(argc, argv);
     124        g_system->quit();       // TODO: Consider removing / replacing this!
     125        return res;
     126}
     127#endif  // defined(_WIN32_WCE)
     128#endif  // defined(__MAEMO__)
     129
     130void OSystem_Common::initBackend() {
     131        assert(!_inited);
     132
     133        int joystick_num = ConfMan.getInt("joystick_num");
     134        uint32 sdlFlags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
     135
     136        if (ConfMan.hasKey("disable_sdl_parachute"))
     137                sdlFlags |= SDL_INIT_NOPARACHUTE;
     138
     139#ifdef _WIN32_WCE
     140        if (ConfMan.hasKey("use_GDI") && ConfMan.getBool("use_GDI")) {
     141                SDL_VideoInit("windib", 0);
     142                sdlFlags ^= SDL_INIT_VIDEO;
     143        }
     144#endif
     145
     146        if (joystick_num > -1)
     147                sdlFlags |= SDL_INIT_JOYSTICK;
     148
     149        if (SDL_Init(sdlFlags) == -1) {
     150                error("Could not initialize SDL: %s", SDL_GetError());
     151        }
     152
     153        _graphicsMutex = createMutex();
     154
     155        SDL_ShowCursor(SDL_DISABLE);
     156
     157        // Enable unicode support if possible
     158        SDL_EnableUNICODE(1);
     159
     160        _cksumValid = false;
     161#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) && !defined(DISABLE_SCALERS)
     162        _mode = GFX_DOUBLESIZE;
     163        _scaleFactor = 2;
     164        _scalerProc = Normal2x;
     165        _fullscreen = ConfMan.getBool("fullscreen");
     166        _adjustAspectRatio = ConfMan.getBool("aspect_ratio");
     167#else // for small screen platforms
     168        _mode = GFX_NORMAL;
     169        _scaleFactor = 1;
     170        _scalerProc = Normal1x;
     171
     172#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
     173        _fullscreen = ConfMan.getBool("fullscreen");
     174#else
     175        _fullscreen = true;
     176#endif
     177
     178        _adjustAspectRatio = false;
     179#endif
     180        _scalerType = 0;
     181        _modeFlags = 0;
     182
     183#if !defined(MACOSX) && !defined(__SYMBIAN32__)         // Don't set icon on OS X, as we use a nicer external icon there
     184        setupIcon();                                                                    // Don't for Symbian: it uses the EScummVM.aif file for the icon
     185#endif
     186
     187        // enable joystick
     188        if (joystick_num > -1 && SDL_NumJoysticks() > 0) {
     189                printf("Using joystick: %s\n", SDL_JoystickName(0));
     190                _joystick = SDL_JoystickOpen(joystick_num);
     191        }
     192       
     193
     194        // Create the savefile manager, if none exists yet (we check for this to
     195        // allow subclasses to provide their own).
     196        if (_savefile == 0) {
     197                _savefile = new DefaultSaveFileManager();
     198        }
     199
     200        // Create and hook up the mixer, if none exists yet (we check for this to
     201        // allow subclasses to provide their own).
     202        if (_mixer == 0) {
     203                _mixer = new Audio::Mixer();
     204                bool result = setSoundCallback(Audio::Mixer::mixCallback, _mixer);
     205                _mixer->setReady(result);
     206        }
     207
     208        // Create and hook up the timer manager, if none exists yet (we check for
     209        // this to allow subclasses to provide their own).
     210        if (_timer == 0) {
     211                // TODO: We could implement a custom SDLTimerManager by using
     212                // SDL_AddTimer. That might yield better timer resolution, but it would
     213                // also change the semantics of a timer: Right now, ScummVM timers
     214                // *never* run in parallel, due to the way they are implemented. If we
     215                // switched to SDL_AddTimer, each timer might run in a separate thread.
     216                // Unfortunately, not all our code is prepared for that, so we can't just
     217                // switch. But it's a long term goal to do just that!
     218                _timer = new DefaultTimerManager();
     219                _timerID = SDL_AddTimer(10, &timer_handler, _timer);
     220        }
     221       
     222        OSystem::initBackend();
     223
     224        _inited = true;
     225}
     226
     227OSystem_Common::OSystem_Common()
     228        :
     229#ifdef USE_OSD
     230        _osdSurface(0), _osdAlpha(SDL_ALPHA_TRANSPARENT), _osdFadeStartTime(0),
     231#endif
     232        _hwscreen(0), _screen(0), _screenWidth(0), _screenHeight(0),
     233        _tmpscreen(0), _overlayWidth(0), _overlayHeight(0),
     234        _overlayVisible(false),
     235        _overlayscreen(0), _tmpscreen2(0),
     236        _samplesPerSec(0),
     237        _cdrom(0), _scalerProc(0), _modeChanged(false), _screenChangeCount(0), _dirtyChecksums(0),
     238        _mouseVisible(false), _mouseDrawn(false), _mouseData(0), _mouseSurface(0),
     239        _mouseOrigSurface(0), _cursorTargetScale(1), _cursorPaletteDisabled(true),
     240        _joystick(0),
     241        _currentShakePos(0), _newShakePos(0),
     242        _paletteDirtyStart(0), _paletteDirtyEnd(0),
     243        _savefile(0),
     244        _mixer(0),
     245        _timer(0),
     246        _screenIsLocked(false),
     247        _graphicsMutex(0), _transactionMode(kTransactionNone) {
     248
     249        // allocate palette storage
     250        _currentPalette = (SDL_Color *)calloc(sizeof(SDL_Color), 256);
     251        _cursorPalette = (SDL_Color *)calloc(sizeof(SDL_Color), 256);
     252
     253        _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0;
     254
     255        // reset mouse state
     256        memset(&_km, 0, sizeof(_km));
     257        memset(&_mouseCurState, 0, sizeof(_mouseCurState));
     258
     259        _inited = false;
     260}
     261
     262OSystem_Common::~OSystem_Common() {
     263        SDL_RemoveTimer(_timerID);
     264        SDL_CloseAudio();
     265
     266        free(_dirtyChecksums);
     267        free(_currentPalette);
     268        free(_cursorPalette);
     269        free(_mouseData);
     270
     271        delete _savefile;
     272        delete _mixer;
     273        delete _timer;
     274}
     275
     276uint32 OSystem_Common::getMillis() {
     277        return SDL_GetTicks();
     278}
     279
     280void OSystem_Common::delayMillis(uint msecs) {
     281        SDL_Delay(msecs);
     282}
     283
     284Common::TimerManager *OSystem_Common::getTimerManager() {
     285        assert(_timer);
     286        return _timer;
     287}
     288
     289Common::SaveFileManager *OSystem_Common::getSavefileManager() {
     290        assert(_savefile);
     291        return _savefile;
     292}
     293
     294void OSystem_Common::setWindowCaption(const char *caption) {
     295        SDL_WM_SetCaption(caption, caption);
     296}
     297
     298bool OSystem_Common::hasFeature(Feature f) {
     299        return
     300                (f == kFeatureFullscreenMode) ||
     301                (f == kFeatureAspectRatioCorrection) ||
     302                (f == kFeatureAutoComputeDirtyRects) ||
     303                (f == kFeatureCursorHasPalette) ||
     304                (f == kFeatureIconifyWindow);
     305}
     306
     307void OSystem_Common::setFeatureState(Feature f, bool enable) {
     308        switch (f) {
     309        case kFeatureFullscreenMode:
     310                setFullscreenMode(enable);
     311                break;
     312        case kFeatureAspectRatioCorrection:
     313                setAspectRatioCorrection(enable);
     314                break;
     315        case kFeatureAutoComputeDirtyRects:
     316                if (enable)
     317                        _modeFlags |= DF_WANT_RECT_OPTIM;
     318                else
     319                        _modeFlags &= ~DF_WANT_RECT_OPTIM;
     320                break;
     321        case kFeatureIconifyWindow:
     322                if (enable)
     323                        SDL_WM_IconifyWindow();
     324                break;
     325        default:
     326                break;
     327        }
     328}
     329
     330bool OSystem_Common::getFeatureState(Feature f) {
     331        assert (_transactionMode == kTransactionNone);
     332
     333        switch (f) {
     334        case kFeatureFullscreenMode:
     335                return _fullscreen;
     336        case kFeatureAspectRatioCorrection:
     337                return _adjustAspectRatio;
     338        case kFeatureAutoComputeDirtyRects:
     339                return _modeFlags & DF_WANT_RECT_OPTIM;
     340        default:
     341                return false;
     342        }
     343}
     344
     345void OSystem_Common::quit() {
     346        if (_cdrom) {
     347                SDL_CDStop(_cdrom);
     348                SDL_CDClose(_cdrom);
     349        }
     350        unloadGFXMode();
     351        deleteMutex(_graphicsMutex);
     352
     353        if (_joystick)
     354                SDL_JoystickClose(_joystick);
     355        SDL_ShowCursor(SDL_ENABLE);
     356        SDL_Quit();
     357
     358        exit(0);
     359}
     360
     361void OSystem_Common::setupIcon() {
     362        int w, h, ncols, nbytes, i;
     363        unsigned int rgba[256], icon[32 * 32];
     364        unsigned char mask[32][4];
     365
     366        sscanf(scummvm_icon[0], "%d %d %d %d", &w, &h, &ncols, &nbytes);
     367        if ((w != 32) || (h != 32) || (ncols > 255) || (nbytes > 1)) {
     368                warning("Could not load the icon (%d %d %d %d)", w, h, ncols, nbytes);
     369                return;
     370        }
     371        for (i = 0; i < ncols; i++) {
     372                unsigned char code;
     373                char color[32];
     374                unsigned int col;
     375                sscanf(scummvm_icon[1 + i], "%c c %s", &code, color);
     376                if (!strcmp(color, "None"))
     377                        col = 0x00000000;
     378                else if (!strcmp(color, "black"))
     379                        col = 0xFF000000;
     380                else if (color[0] == '#') {
     381                        sscanf(color + 1, "%06x", &col);
     382                        col |= 0xFF000000;
     383                } else {
     384                        warning("Could not load the icon (%d %s - %s) ", code, color, scummvm_icon[1 + i]);
     385                        return;
     386                }
     387
     388                rgba[code] = col;
     389        }
     390        memset(mask, 0, sizeof(mask));
     391        for (h = 0; h < 32; h++) {
     392                const char *line = scummvm_icon[1 + ncols + h];
     393                for (w = 0; w < 32; w++) {
     394                        icon[w + 32 * h] = rgba[(int)line[w]];
     395                        if (rgba[(int)line[w]] & 0xFF000000) {
     396                                mask[h][w >> 3] |= 1 << (7 - (w & 0x07));
     397                        }
     398                }
     399        }
     400
     401        SDL_Surface *sdl_surf = SDL_CreateRGBSurfaceFrom(icon, 32, 32, 32, 32 * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000);
     402        SDL_WM_SetIcon(sdl_surf, (unsigned char *) mask);
     403        SDL_FreeSurface(sdl_surf);
     404}
     405
     406OSystem::MutexRef OSystem_Common::createMutex(void) {
     407        return (MutexRef) SDL_CreateMutex();
     408}
     409
     410void OSystem_Common::lockMutex(MutexRef mutex) {
     411        SDL_mutexP((SDL_mutex *) mutex);
     412}
     413
     414void OSystem_Common::unlockMutex(MutexRef mutex) {
     415        SDL_mutexV((SDL_mutex *) mutex);
     416}
     417
     418void OSystem_Common::deleteMutex(MutexRef mutex) {
     419        SDL_DestroyMutex((SDL_mutex *) mutex);
     420}
     421
     422#pragma mark -
     423#pragma mark --- Audio ---
     424#pragma mark -
     425
     426bool OSystem_Common::setSoundCallback(SoundProc proc, void *param) {
     427        SDL_AudioSpec desired;
     428        SDL_AudioSpec obtained;
     429
     430        memset(&desired, 0, sizeof(desired));
     431
     432        _samplesPerSec = 0;
     433
     434        if (ConfMan.hasKey("output_rate"))
     435                _samplesPerSec = ConfMan.getInt("output_rate");
     436
     437        if (_samplesPerSec <= 0)
     438                _samplesPerSec = SAMPLES_PER_SEC;
     439
     440        // Originally, we always used 2048 samples. This loop will produce the
     441        // same result at 22050 Hz, and should hopefully produce something
     442        // sensible for other frequencies. Note that it must be a power of two.
     443
     444        uint32 samples = 0x8000;
     445
     446        for (;;) {
     447                if ((1000 * samples) / _samplesPerSec < 100)
     448                        break;
     449                samples >>= 1;
     450        }
     451
     452        desired.freq = _samplesPerSec;
     453        desired.format = AUDIO_S16SYS;
     454        desired.channels = 2;
     455        desired.samples = (uint16)samples;
     456        desired.callback = proc;
     457        desired.userdata = param;
     458        if (SDL_OpenAudio(&desired, &obtained) != 0) {
     459                warning("Could not open audio device: %s", SDL_GetError());
     460                return false;
     461        }
     462        // Note: This should be the obtained output rate, but it seems that at
     463        // least on some platforms SDL will lie and claim it did get the rate
     464        // even if it didn't. Probably only happens for "weird" rates, though.
     465        _samplesPerSec = obtained.freq;
     466        debug(1, "Output sample rate: %d Hz", _samplesPerSec);
     467        SDL_PauseAudio(0);
     468        return true;
     469}
     470
     471int OSystem_Common::getOutputSampleRate() const {
     472        return _samplesPerSec;
     473}
     474
     475Audio::Mixer *OSystem_Common::getMixer() {
     476        assert(_mixer);
     477        return _mixer;
     478}
     479
     480#pragma mark -
     481#pragma mark --- CD Audio ---
     482#pragma mark -
     483
     484bool OSystem_Common::openCD(int drive) {
     485        if (SDL_InitSubSystem(SDL_INIT_CDROM) == -1)
     486                _cdrom = NULL;
     487        else {
     488                _cdrom = SDL_CDOpen(drive);
     489                // Did it open? Check if _cdrom is NULL
     490                if (!_cdrom) {
     491                        warning("Couldn't open drive: %s", SDL_GetError());
     492                } else {
     493                        _cdNumLoops = 0;
     494                        _cdStopTime = 0;
     495                        _cdEndTime = 0;
     496                }
     497        }
     498
     499        return (_cdrom != NULL);
     500}
     501
     502void OSystem_Common::stopCD() { /* Stop CD Audio in 1/10th of a second */
     503        _cdStopTime = SDL_GetTicks() + 100;
     504        _cdNumLoops = 0;
     505}
     506
     507void OSystem_Common::playCD(int track, int num_loops, int start_frame, int duration) {
     508        if (!num_loops && !start_frame)
     509                return;
     510
     511        if (!_cdrom)
     512                return;
     513
     514        if (duration > 0)
     515                duration += 5;
     516
     517        _cdTrack = track;
     518        _cdNumLoops = num_loops;
     519        _cdStartFrame = start_frame;
     520
     521        SDL_CDStatus(_cdrom);
     522        if (start_frame == 0 && duration == 0)
     523                SDL_CDPlayTracks(_cdrom, track, 0, 1, 0);
     524        else
     525                SDL_CDPlayTracks(_cdrom, track, start_frame, 0, duration);
     526        _cdDuration = duration;
     527        _cdStopTime = 0;
     528        _cdEndTime = SDL_GetTicks() + _cdrom->track[track].length * 1000 / CD_FPS;
     529}
     530
     531bool OSystem_Common::pollCD() {
     532        if (!_cdrom)
     533                return false;
     534
     535        return (_cdNumLoops != 0 && (SDL_GetTicks() < _cdEndTime || SDL_CDStatus(_cdrom) != CD_STOPPED));
     536}
     537
     538void OSystem_Common::updateCD() {
     539        if (!_cdrom)
     540                return;
     541
     542        if (_cdStopTime != 0 && SDL_GetTicks() >= _cdStopTime) {
     543                SDL_CDStop(_cdrom);
     544                _cdNumLoops = 0;
     545                _cdStopTime = 0;
     546                return;
     547        }
     548
     549        if (_cdNumLoops == 0 || SDL_GetTicks() < _cdEndTime)
     550                return;
     551
     552        if (_cdNumLoops != 1 && SDL_CDStatus(_cdrom) != CD_STOPPED) {
     553                // Wait another second for it to be done
     554                _cdEndTime += 1000;
     555                return;
     556        }
     557
     558        if (_cdNumLoops > 0)
     559                _cdNumLoops--;
     560
     561        if (_cdNumLoops != 0) {
     562                if (_cdStartFrame == 0 && _cdDuration == 0)
     563                        SDL_CDPlayTracks(_cdrom, _cdTrack, 0, 1, 0);
     564                else
     565                        SDL_CDPlayTracks(_cdrom, _cdTrack, _cdStartFrame, 0, _cdDuration);
     566                _cdEndTime = SDL_GetTicks() + _cdrom->track[_cdTrack].length * 1000 / CD_FPS;
     567        }
     568}