Logo Search packages:      
Sourcecode: scummvm version File versions

wincesdl-graphics.cpp

/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * $URL$
 * $Id$
 *
 */

#include "common/scummsys.h"

#ifdef _WIN32_WCE

#include "common/system.h"
#include "common/textconsole.h"
#include "common/translation.h"
#include "common/mutex.h"

#include "graphics/scaler/downscaler.h"
#include "graphics/scaler/aspect.h"
#include "backends/graphics/wincesdl/wincesdl-graphics.h"
#include "backends/events/wincesdl/wincesdl-events.h"
#include "backends/platform/wince/wince-sdl.h"

#include "backends/platform/wince/resource.h"
#include "backends/platform/wince/CEActionsPocket.h"
#include "backends/platform/wince/CEActionsSmartphone.h"
#include "backends/platform/wince/CEDevice.h"
#include "backends/platform/wince/CEScaler.h"
#include "backends/platform/wince/CEgui/ItemAction.h"

WINCESdlGraphicsManager::WINCESdlGraphicsManager(SdlEventSource *sdlEventSource)
      : SdlGraphicsManager(sdlEventSource),
        _panelInitialized(false), _noDoubleTapRMB(false), _noDoubleTapPT(false),
        _toolbarHighDrawn(false), _newOrientation(0), _orientationLandscape(0),
        _panelVisible(true), _saveActiveToolbar(NAME_MAIN_PANEL), _panelStateForced(false),
        _canBeAspectScaled(false), _scalersChanged(false), _saveToolbarState(false),
        _mouseBackupOld(NULL), _mouseBackupDim(0), _mouseBackupToolbar(NULL),
        _usesEmulatedMouse(false), _forceHideMouse(false), _freeLook(false),
        _hasfocus(true), _zoomUp(false), _zoomDown(false) {
      memset(&_mouseCurState, 0, sizeof(_mouseCurState));
      if (_isSmartphone) {
            _mouseCurState.x = 20;
            _mouseCurState.y = 20;
      }

      loadDeviceConfigurationElement("repeatTrigger", _keyRepeatTrigger, 200);
      loadDeviceConfigurationElement("repeatX", _repeatX, 4);
      loadDeviceConfigurationElement("repeatY", _repeatY, 4);
      loadDeviceConfigurationElement("stepX1", _stepX1, 2);
      loadDeviceConfigurationElement("stepX2", _stepX2, 10);
      loadDeviceConfigurationElement("stepX3", _stepX3, 40);
      loadDeviceConfigurationElement("stepY1", _stepY1, 2);
      loadDeviceConfigurationElement("stepY2", _stepY2, 10);
      loadDeviceConfigurationElement("stepY3", _stepY3, 20);
      ConfMan.flushToDisk();

      _isSmartphone = CEDevice::isSmartphone();

      // Query SDL for screen size and init screen dependent stuff
      OSystem_WINCE3::initScreenInfos();
      create_toolbar();
      _hasSmartphoneResolution = CEDevice::hasSmartphoneResolution() || CEDevice::isSmartphone();
      if (_hasSmartphoneResolution)
            _panelVisible = false;  // init correctly in smartphones

      _screen = NULL;
}

// Graphics mode consts

// Low end devices 240x320

static const OSystem::GraphicsMode s_supportedGraphicsModesLow[] = {
      {"1x", _s("Normal (no scaling)"), GFX_NORMAL},
      {0, 0, 0}
};

// High end device 480x640

static const OSystem::GraphicsMode s_supportedGraphicsModesHigh[] = {
      {"1x", _s("Normal (no scaling)"), GFX_NORMAL},
      {"2x", "2x", GFX_DOUBLESIZE},
#ifndef _MSC_VER // EVC breaks template functions, and I'm tired of fixing them :)
      {"2xsai", "2xSAI", GFX_2XSAI},
      {"super2xsai", "Super2xSAI", GFX_SUPER2XSAI},
      {"supereagle", "SuperEagle", GFX_SUPEREAGLE},
#endif
      {"advmame2x", "AdvMAME2x", GFX_ADVMAME2X},
#ifndef _MSC_VER
      {"hq2x", "HQ2x", GFX_HQ2X},
      {"tv2x", "TV2x", GFX_TV2X},
#endif
      {"dotmatrix", "DotMatrix", GFX_DOTMATRIX},
      {0, 0, 0}
};

const OSystem::GraphicsMode *WINCESdlGraphicsManager::getSupportedGraphicsModes() const {
      if (CEDevice::hasWideResolution())
            return s_supportedGraphicsModesHigh;
      else
            return s_supportedGraphicsModesLow;
}

bool WINCESdlGraphicsManager::hasFeature(OSystem::Feature f) {
      return (f == OSystem::kFeatureVirtualKeyboard);
}

void WINCESdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
      switch (f) {
      case OSystem::kFeatureFullscreenMode:
            return;

      case OSystem::kFeatureVirtualKeyboard:
            if (_hasSmartphoneResolution)
                  return;
            _toolbarHighDrawn = false;
            if (enable) {
                  _panelStateForced = true;
                  if (!_toolbarHandler.visible()) swap_panel_visibility();
                  //_saveToolbarState = _toolbarHandler.visible();
                  _saveActiveToolbar = _toolbarHandler.activeName();
                  _toolbarHandler.setActive(NAME_PANEL_KEYBOARD);
                  _toolbarHandler.setVisible(true);
            } else if (_panelStateForced) {
                  _panelStateForced = false;
                  _toolbarHandler.setActive(_saveActiveToolbar);
                  //_toolbarHandler.setVisible(_saveToolbarState);
            }
            return;

      case OSystem::kFeatureDisableKeyFiltering:
            if (_hasSmartphoneResolution) {
                  GUI::Actions::Instance()->beginMapping(enable);
            }
            return;

      default:
            SdlGraphicsManager::setFeatureState(f, enable);
      }
}

bool WINCESdlGraphicsManager::getFeatureState(OSystem::Feature f) {
      switch (f) {
      case OSystem::kFeatureFullscreenMode:
            return false;
      case OSystem::kFeatureVirtualKeyboard:
            return (_panelStateForced);
      default:
            return SdlGraphicsManager::getFeatureState(f);
      }
}

int WINCESdlGraphicsManager::getDefaultGraphicsMode() const {
      return GFX_NORMAL;
}

void WINCESdlGraphicsManager::initSize(uint w, uint h, const Graphics::PixelFormat *format) {
      if (_hasSmartphoneResolution && h == 240)
            h = 200;  // mainly for the launcher

      if (_isSmartphone && !ConfMan.hasKey("landscape")) {
            ConfMan.setInt("landscape", 1);
            ConfMan.flushToDisk();
      }

      _canBeAspectScaled = false;
      if (w == 320 && h == 200 && !_hasSmartphoneResolution) {
            _canBeAspectScaled = true;
            h = 240; // use the extra 40 pixels height for the toolbar
      }

      if (h == 400)   // touche engine fixup
            h += 80;

      if (!_hasSmartphoneResolution) {
            if (h == 240)
                  _toolbarHandler.setOffset(200);
            else
                  _toolbarHandler.setOffset(400);
      } else {
            if (h == 240)
                  _toolbarHandler.setOffset(200);
            else    // 176x220
                  _toolbarHandler.setOffset(0);
      }

      if (w != (uint) _videoMode.screenWidth || h != (uint) _videoMode.screenHeight)
            _scalersChanged = false;

      _videoMode.overlayWidth = w;
      _videoMode.overlayHeight = h;

      SdlGraphicsManager::initSize(w, h, format);

      if (_scalersChanged) {
            unloadGFXMode();
            loadGFXMode();
            _scalersChanged = false;
      }

      update_game_settings();
}

void WINCESdlGraphicsManager::loadDeviceConfigurationElement(Common::String element, int &value, int defaultValue) {
      value = ConfMan.getInt(element, ConfMan.kApplicationDomain);
      if (!value) {
            value = defaultValue;
            ConfMan.setInt(element, value, ConfMan.kApplicationDomain);
      }
}

void WINCESdlGraphicsManager::move_cursor_up() {
      int x, y;
      _usesEmulatedMouse = true;
      retrieve_mouse_location(x, y);
      if (_keyRepeat > _repeatY)
            y -= _stepY3;
      else if (_keyRepeat)
            y -= _stepY2;
      else
            y -= _stepY1;

      if (y < 0)
            y = 0;

      EventsBuffer::simulateMouseMove(x, y);
}

void WINCESdlGraphicsManager::move_cursor_down() {
      int x, y;
      _usesEmulatedMouse = true;
      retrieve_mouse_location(x, y);
      if (_keyRepeat > _repeatY)
            y += _stepY3;
      else if (_keyRepeat)
            y += _stepY2;
      else
            y += _stepY1;

      if (y > _videoMode.screenHeight * _scaleFactorYm / _scaleFactorYd)
            y = _videoMode.screenHeight * _scaleFactorYm / _scaleFactorYd;

      EventsBuffer::simulateMouseMove(x, y);
}

void WINCESdlGraphicsManager::move_cursor_left() {
      int x, y;
      _usesEmulatedMouse = true;
      retrieve_mouse_location(x, y);
      if (_keyRepeat > _repeatX)
            x -= _stepX3;
      else if (_keyRepeat)
            x -= _stepX2;
      else
            x -= _stepX1;

      if (x < 0)
            x = 0;

      EventsBuffer::simulateMouseMove(x, y);
}

void WINCESdlGraphicsManager::move_cursor_right() {
      int x, y;
      _usesEmulatedMouse = true;
      retrieve_mouse_location(x, y);
      if (_keyRepeat > _repeatX)
            x += _stepX3;
      else if (_keyRepeat)
            x += _stepX2;
      else
            x += _stepX1;

      if (x > _videoMode.screenWidth * _scaleFactorXm / _scaleFactorXd)
            x = _videoMode.screenWidth * _scaleFactorXm / _scaleFactorXd;

      EventsBuffer::simulateMouseMove(x, y);
}

void WINCESdlGraphicsManager::retrieve_mouse_location(int &x, int &y) {
      x = _mouseCurState.x;
      y = _mouseCurState.y;

      x = x * _scaleFactorXm / _scaleFactorXd;
      y = y * _scaleFactorYm / _scaleFactorYd;

      if (_zoomDown)
            y -= 240;
}

void WINCESdlGraphicsManager::switch_zone() {
      int x, y;
      int i;
      retrieve_mouse_location(x, y);

      for (i = 0; i < TOTAL_ZONES; i++)
            if (x >= _zones[i].x && y >= _zones[i].y &&
                    x <= _zones[i].x + _zones[i].width && y <= _zones[i].y + _zones[i].height) {
                  _mouseXZone[i] = x;
                  _mouseYZone[i] = y;
                  break;
            }
      _currentZone = i + 1;
      if (_currentZone >= TOTAL_ZONES)
            _currentZone = 0;

      EventsBuffer::simulateMouseMove(_mouseXZone[_currentZone], _mouseYZone[_currentZone]);
}

void WINCESdlGraphicsManager::add_right_click(bool pushed) {
      int x, y;
      retrieve_mouse_location(x, y);
      EventsBuffer::simulateMouseRightClick(x, y, pushed);
}

void WINCESdlGraphicsManager::add_left_click(bool pushed) {
      int x, y;
      retrieve_mouse_location(x, y);
      EventsBuffer::simulateMouseLeftClick(x, y, pushed);
}

bool WINCESdlGraphicsManager::update_scalers() {
      _videoMode.aspectRatioCorrection = false;

      if (CEDevice::hasPocketPCResolution()) {
            if (_videoMode.mode != GFX_NORMAL)
                  return false;

            if ((!_orientationLandscape && (_videoMode.screenWidth == 320 || !_videoMode.screenWidth))
                    || CEDevice::hasSquareQVGAResolution()) {
                  if (OSystem_WINCE3::getScreenWidth() != 320) {
                        _scaleFactorXm = 3;
                        _scaleFactorXd = 4;
                        _scaleFactorYm = 1;
                        _scaleFactorYd = 1;
                        _scalerProc = DownscaleHorizByThreeQuarters;
                  } else {
                        _scaleFactorXm = 1;
                        _scaleFactorXd = 1;
                        _scaleFactorYm = 1;
                        _scaleFactorYd = 1;
                        _scalerProc = Normal1x;
                  }
            } else if (_orientationLandscape && (_videoMode.screenWidth == 320 || !_videoMode.screenWidth)) {
                  if (!_panelVisible && !_hasSmartphoneResolution  && !_overlayVisible && _canBeAspectScaled) {
                        _scaleFactorXm = 1;
                        _scaleFactorXd = 1;
                        _scaleFactorYm = 6;
                        _scaleFactorYd = 5;
                        _scalerProc = Normal1xAspect;
                        _videoMode.aspectRatioCorrection = true;
                  } else {
                        _scaleFactorXm = 1;
                        _scaleFactorXd = 1;
                        _scaleFactorYm = 1;
                        _scaleFactorYd = 1;
                        _scalerProc = Normal1x;
                  }
            } else if (_videoMode.screenWidth == 640 && !(OSystem_WINCE3::isOzone() && (OSystem_WINCE3::getScreenWidth() >= 640 || OSystem_WINCE3::getScreenHeight() >= 640))) {
                  _scaleFactorXm = 1;
                  _scaleFactorXd = 2;
                  _scaleFactorYm = 1;
                  _scaleFactorYd = 2;
                  _scalerProc = DownscaleAllByHalf;
            } else if (_videoMode.screenWidth == 640 && (OSystem_WINCE3::isOzone() && (OSystem_WINCE3::getScreenWidth() >= 640 || OSystem_WINCE3::getScreenHeight() >= 640))) {
                  _scaleFactorXm = 1;
                  _scaleFactorXd = 1;
                  _scaleFactorYm = 1;
                  _scaleFactorYd = 1;
                  _scalerProc = Normal1x;
            }

            return true;
      } else if (CEDevice::hasWideResolution()) {
#ifdef USE_ARM_SCALER_ASM
            if (_videoMode.mode == GFX_DOUBLESIZE && (_videoMode.screenWidth == 320 || !_videoMode.screenWidth)) {
                  if (!_panelVisible && !_overlayVisible && _canBeAspectScaled) {
                        _scaleFactorXm = 2;
                        _scaleFactorXd = 1;
                        _scaleFactorYm = 12;
                        _scaleFactorYd = 5;
                        _scalerProc = Normal2xAspect;
                        _videoMode.aspectRatioCorrection = true;
                  } else if ((_panelVisible || _overlayVisible) && _canBeAspectScaled) {
                        _scaleFactorXm = 2;
                        _scaleFactorXd = 1;
                        _scaleFactorYm = 2;
                        _scaleFactorYd = 1;
                        _scalerProc = Normal2x;
                  }
                  return true;
            }
#endif
      } else if (CEDevice::hasSmartphoneResolution()) {
            if (_videoMode.mode != GFX_NORMAL)
                  return false;

            if (_videoMode.screenWidth > 320)
                  error("Game resolution not supported on Smartphone");
#ifdef ARM
            _scaleFactorXm = 11;
            _scaleFactorXd = 16;
#else
            _scaleFactorXm = 2;
            _scaleFactorXd = 3;
#endif
            _scaleFactorYm = 7;
            _scaleFactorYd = 8;
            _scalerProc = SmartphoneLandscape;
            initZones();
            return true;
      }

      return false;
}

void WINCESdlGraphicsManager::update_game_settings() {
      Common::String gameid(ConfMan.get("gameid"));

      // Finish panel initialization
      if (!_panelInitialized && !gameid.empty()) {
            CEGUI::Panel *panel;
            _panelInitialized = true;
            // Add the main panel
            panel = new CEGUI::Panel(0, 32);
            panel->setBackground(IMAGE_PANEL);

            // Save
            panel->add(NAME_ITEM_OPTIONS, new CEGUI::ItemAction(ITEM_OPTIONS, POCKET_ACTION_SAVE));
            // Skip
            panel->add(NAME_ITEM_SKIP, new CEGUI::ItemAction(ITEM_SKIP, POCKET_ACTION_SKIP));
            // sound
            panel->add(NAME_ITEM_SOUND, new CEGUI::ItemSwitch(ITEM_SOUND_OFF, ITEM_SOUND_ON, &OSystem_WINCE3::_soundMaster));

            // bind keys
            panel->add(NAME_ITEM_BINDKEYS, new CEGUI::ItemAction(ITEM_BINDKEYS, POCKET_ACTION_BINDKEYS));
            // portrait/landscape - screen dependent
            // FIXME : will still display the portrait/landscape icon when using a scaler (but will be disabled)
            if (ConfMan.hasKey("landscape")) {
                  if (ConfMan.get("landscape")[0] > 57) {
                        _newOrientation = _orientationLandscape = ConfMan.getBool("landscape");
                        //ConfMan.removeKey("landscape", "");
                        ConfMan.setInt("landscape", _orientationLandscape);
                  } else
                        _newOrientation = _orientationLandscape = ConfMan.getInt("landscape");
            } else {
                  _newOrientation = _orientationLandscape = 0;
            }
            panel->add(NAME_ITEM_ORIENTATION, new CEGUI::ItemSwitch(ITEM_VIEW_LANDSCAPE, ITEM_VIEW_PORTRAIT, &_newOrientation, 2));
            _toolbarHandler.add(NAME_MAIN_PANEL, *panel);
            _toolbarHandler.setActive(NAME_MAIN_PANEL);
            _toolbarHandler.setVisible(true);

            if (_videoMode.mode == GFX_NORMAL && ConfMan.hasKey("landscape") && ConfMan.getInt("landscape")) {
                  setGraphicsMode(GFX_NORMAL);
                  hotswapGFXMode();
            }

            if (_hasSmartphoneResolution)
                  panel->setVisible(false);

            _saveToolbarState = true;
      }

      if (ConfMan.hasKey("no_doubletap_rightclick"))
            _noDoubleTapRMB = ConfMan.getBool("no_doubletap_rightclick");

      if (ConfMan.hasKey("no_doubletap_paneltoggle"))
            _noDoubleTapPT = ConfMan.getBool("no_doubletap_paneltoggle");
}

void WINCESdlGraphicsManager::internUpdateScreen() {
      SDL_Surface *srcSurf, *origSurf;
      static bool old_overlayVisible = false;
      int numRectsOut = 0;
      int16 routx, routy, routw, routh, stretch, shakestretch;

      assert(_hwscreen != NULL);

      // bail if the application is minimized, be nice to OS
      if (!_hasfocus) {
            Sleep(20);
            return;
      }

      // If the shake position changed, fill the dirty area with blackness
      if (_currentShakePos != _newShakePos) {
            SDL_Rect blackrect = {0, 0, _videoMode.screenWidth *_scaleFactorXm / _scaleFactorXd, _newShakePos *_scaleFactorYm / _scaleFactorYd};
            if (_videoMode.aspectRatioCorrection)
                  blackrect.h = real2Aspect(blackrect.h - 1) + 1;
            SDL_FillRect(_hwscreen, &blackrect, 0);
            _currentShakePos = _newShakePos;
            _forceFull = true;
      }

      // Make sure the mouse is drawn, if it should be drawn.
      drawMouse();

      // Check whether the palette was changed in the meantime and update the
      // screen surface accordingly.
      if (_paletteDirtyEnd != 0) {
            SDL_SetColors(_screen, _currentPalette + _paletteDirtyStart, _paletteDirtyStart, _paletteDirtyEnd - _paletteDirtyStart);
            _paletteDirtyEnd = 0;
            _forceFull = true;
      }

      if (!_overlayVisible) {
            origSurf = _screen;
            srcSurf = _tmpscreen;
      } else {
            origSurf = _overlayscreen;
            srcSurf = _tmpscreen2;
      }

      if (old_overlayVisible != _overlayVisible) {
            old_overlayVisible = _overlayVisible;
            update_scalers();
      }

      // Force a full redraw if requested
      if (_forceFull) {
            _numDirtyRects = 1;

            _dirtyRectList[0].x = 0;
            if (!_zoomDown)
                  _dirtyRectList[0].y = 0;
            else
                  _dirtyRectList[0].y = _videoMode.screenHeight / 2;
            _dirtyRectList[0].w = _videoMode.screenWidth;
            if (!_zoomUp && !_zoomDown)
                  _dirtyRectList[0].h = _videoMode.screenHeight;
            else
                  _dirtyRectList[0].h = _videoMode.screenHeight / 2;

            _toolbarHandler.forceRedraw();
      }

      // Only draw anything if necessary
      if (_numDirtyRects > 0) {

            SDL_Rect *r, *rout;
            SDL_Rect dst;
            uint32 srcPitch, dstPitch;
            SDL_Rect *last_rect = _dirtyRectList + _numDirtyRects;
            bool toolbarVisible = _toolbarHandler.visible();
            int toolbarOffset = _toolbarHandler.getOffset();

            for (r = _dirtyRectList; r != last_rect; ++r) {
                  dst = *r;
                  dst.x++;    // Shift rect by one since 2xSai needs to access the data around
                  dst.y++;    // any pixel to scale it, and we want to avoid mem access crashes.
                  // NOTE: This is also known as BLACK MAGIC, copied from the sdl backend
                  if (SDL_BlitSurface(origSurf, r, srcSurf, &dst) != 0)
                        error("SDL_BlitSurface failed: %s", SDL_GetError());
            }

            SDL_LockSurface(srcSurf);
            SDL_LockSurface(_hwscreen);

            srcPitch = srcSurf->pitch;
            dstPitch = _hwscreen->pitch;

            for (r = _dirtyRectList, rout = _dirtyRectOut; r != last_rect; ++r) {

                  // always clamp to enclosing, downsampled-grid-aligned rect in the downscaled image
                  if (_scaleFactorXd != 1) {
                        stretch = r->x % _scaleFactorXd;
                        r->x -= stretch;
                        r->w += stretch;
                        r->w = (r->x + r->w + _scaleFactorXd - 1) / _scaleFactorXd * _scaleFactorXd - r->x;
                  }
                  if (_scaleFactorYd != 1) {
                        stretch = r->y % _scaleFactorYd;
                        r->y -= stretch;
                        r->h += stretch;
                        r->h = (r->y + r->h + _scaleFactorYd - 1) / _scaleFactorYd * _scaleFactorYd - r->y;
                  }

                  // transform
                  shakestretch = _currentShakePos * _scaleFactorYm / _scaleFactorYd;
                  routx = r->x * _scaleFactorXm / _scaleFactorXd;                 // locate position in scaled screen
                  routy = r->y * _scaleFactorYm / _scaleFactorYd + shakestretch;  // adjust for shake offset
                  routw = r->w * _scaleFactorXm / _scaleFactorXd;
                  routh = r->h * _scaleFactorYm / _scaleFactorYd - shakestretch;

                  // clipping destination rectangle inside device screen (more strict, also more tricky but more stable)
                  // note that all current scalers do not make dst rect exceed left/right, unless chosen badly (FIXME)
                  if (_zoomDown)  routy -= 240;           // adjust for zoom position
                  if (routy + routh < 0)  continue;
                  if (routy < 0) {
                        routh += routy;
                        r->y -= routy * _scaleFactorYd / _scaleFactorYm;
                        routy = 0;
                        r->h = routh * _scaleFactorYd / _scaleFactorYm;
                  }
                  if (_orientationLandscape) {
                        if (routy > OSystem_WINCE3::getScreenWidth())   continue;
                        if (routy + routh > OSystem_WINCE3::getScreenWidth()) {
                              routh = OSystem_WINCE3::getScreenWidth() - routy;
                              r->h = routh * _scaleFactorYd / _scaleFactorYm;
                        }
                  } else {
                        if (routy > OSystem_WINCE3::getScreenHeight())  continue;
                        if (routy + routh > OSystem_WINCE3::getScreenHeight()) {
                              routh = OSystem_WINCE3::getScreenHeight() - routy;
                              r->h = routh * _scaleFactorYd / _scaleFactorYm;
                        }
                  }

                  // check if the toolbar is overwritten
                  if (toolbarVisible && r->y + r->h >= toolbarOffset)
                        _toolbarHandler.forceRedraw();

                  // blit it (with added voodoo from the sdl backend, shifting the source rect again)
                  _scalerProc((byte *)srcSurf->pixels + (r->x * 2 + 2) + (r->y + 1) * srcPitch, srcPitch,
                              (byte *)_hwscreen->pixels + routx * 2 + routy * dstPitch, dstPitch,
                              r->w, r->h - _currentShakePos);

                  // add this rect to output
                  rout->x = routx;
                  rout->y = routy - shakestretch;
                  rout->w = routw;
                  rout->h = routh + shakestretch;
                  numRectsOut++;
                  rout++;

            }
            SDL_UnlockSurface(srcSurf);
            SDL_UnlockSurface(_hwscreen);
      }
      // Add the toolbar if needed
      SDL_Rect toolbar_rect[1];
      if (_panelVisible && _toolbarHandler.draw(_toolbarLow, &toolbar_rect[0])) {
            // It can be drawn, scale it
            uint32 srcPitch, dstPitch;
            SDL_Surface *toolbarSurface;
            ScalerProc *toolbarScaler;

            if (_videoMode.screenHeight > 240) {
                  if (!_toolbarHighDrawn) {
                        // Resize the toolbar
                        SDL_LockSurface(_toolbarLow);
                        SDL_LockSurface(_toolbarHigh);
                        Normal2x((byte *)_toolbarLow->pixels, _toolbarLow->pitch, (byte *)_toolbarHigh->pixels, _toolbarHigh->pitch, toolbar_rect[0].w, toolbar_rect[0].h);
                        SDL_UnlockSurface(_toolbarHigh);
                        SDL_UnlockSurface(_toolbarLow);
                        _toolbarHighDrawn = true;
                  }
                  toolbar_rect[0].w *= 2;
                  toolbar_rect[0].h *= 2;
                  toolbarSurface = _toolbarHigh;
            } else
                  toolbarSurface = _toolbarLow;

            drawToolbarMouse(toolbarSurface, true);     // draw toolbar mouse if applicable

            // Apply the appropriate scaler
            SDL_LockSurface(toolbarSurface);
            SDL_LockSurface(_hwscreen);
            srcPitch = toolbarSurface->pitch;
            dstPitch = _hwscreen->pitch;

            toolbarScaler = _scalerProc;
            if (_videoMode.scaleFactor == 2)
                  toolbarScaler = Normal2x;
            else if (_videoMode.scaleFactor == 3)
                  toolbarScaler = Normal3x;
            toolbarScaler((byte *)toolbarSurface->pixels, srcPitch,
                          (byte *)_hwscreen->pixels + (_toolbarHandler.getOffset() * _scaleFactorYm / _scaleFactorYd * dstPitch),
                          dstPitch, toolbar_rect[0].w, toolbar_rect[0].h);
            SDL_UnlockSurface(toolbarSurface);
            SDL_UnlockSurface(_hwscreen);

            // And blit it
            toolbar_rect[0].y = _toolbarHandler.getOffset();
            toolbar_rect[0].x = toolbar_rect[0].x * _scaleFactorXm / _scaleFactorXd;
            toolbar_rect[0].y = toolbar_rect[0].y * _scaleFactorYm / _scaleFactorYd;
            toolbar_rect[0].w = toolbar_rect[0].w * _scaleFactorXm / _scaleFactorXd;
            toolbar_rect[0].h = toolbar_rect[0].h * _scaleFactorYm / _scaleFactorYd;

            SDL_UpdateRects(_hwscreen, 1, toolbar_rect);

            drawToolbarMouse(toolbarSurface, false);    // undraw toolbar mouse
      }

      // Finally, blit all our changes to the screen
      if (numRectsOut > 0)
            SDL_UpdateRects(_hwscreen, numRectsOut, _dirtyRectOut);

      _numDirtyRects = 0;
      _forceFull = false;
}

bool WINCESdlGraphicsManager::setGraphicsMode(int mode) {

      Common::StackLock lock(_graphicsMutex);
      int oldScaleFactorXm = _scaleFactorXm;
      int oldScaleFactorXd = _scaleFactorXd;
      int oldScaleFactorYm = _scaleFactorYm;
      int oldScaleFactorYd = _scaleFactorYd;

      _scaleFactorXm = -1;
      _scaleFactorXd = -1;
      _scaleFactorYm = -1;
      _scaleFactorYd = -1;

      if (ConfMan.hasKey("landscape"))
            if (ConfMan.get("landscape")[0] > 57) {
                  _newOrientation = _orientationLandscape = ConfMan.getBool("landscape");
                  ConfMan.setInt("landscape", _orientationLandscape);
            } else
                  _newOrientation = _orientationLandscape = ConfMan.getInt("landscape");
      else
            _newOrientation = _orientationLandscape = 0;

      if (OSystem_WINCE3::isOzone() && (OSystem_WINCE3::getScreenWidth() >= 640 || OSystem_WINCE3::getScreenHeight() >= 640) && mode)
            _scaleFactorXm = -1;

      if (CEDevice::hasPocketPCResolution() && !CEDevice::hasWideResolution() && _orientationLandscape)
            _videoMode.mode = GFX_NORMAL;
      else
            _videoMode.mode = mode;

      if (_scaleFactorXm < 0) {
            /* Standard scalers, from the SDL backend */
            switch (_videoMode.mode) {
            case GFX_NORMAL:
                  _videoMode.scaleFactor = 1;
                  _scalerProc = Normal1x;
                  break;
            case GFX_DOUBLESIZE:
                  _videoMode.scaleFactor = 2;
                  _scalerProc = Normal2x;
                  break;
            case GFX_TRIPLESIZE:
                  _videoMode.scaleFactor = 3;
                  _scalerProc = Normal3x;
                  break;
            case GFX_2XSAI:
                  _videoMode.scaleFactor = 2;
                  _scalerProc = _2xSaI;
                  break;
            case GFX_SUPER2XSAI:
                  _videoMode.scaleFactor = 2;
                  _scalerProc = Super2xSaI;
                  break;
            case GFX_SUPEREAGLE:
                  _videoMode.scaleFactor = 2;
                  _scalerProc = SuperEagle;
                  break;
            case GFX_ADVMAME2X:
                  _videoMode.scaleFactor = 2;
                  _scalerProc = AdvMame2x;
                  break;
            case GFX_ADVMAME3X:
                  _videoMode.scaleFactor = 3;
                  _scalerProc = AdvMame3x;
                  break;
#ifdef USE_HQ_SCALERS
            case GFX_HQ2X:
                  _videoMode.scaleFactor = 2;
                  _scalerProc = HQ2x;
                  break;
            case GFX_HQ3X:
                  _videoMode.scaleFactor = 3;
                  _scalerProc = HQ3x;
                  break;
#endif
            case GFX_TV2X:
                  _videoMode.scaleFactor = 2;
                  _scalerProc = TV2x;
                  break;
            case GFX_DOTMATRIX:
                  _videoMode.scaleFactor = 2;
                  _scalerProc = DotMatrix;
                  break;

            default:
                  error("unknown gfx mode %d", mode);
            }
      }

      // Check if the scaler can be accepted, if not get back to normal scaler
      if (_videoMode.scaleFactor && ((_videoMode.scaleFactor * _videoMode.screenWidth > OSystem_WINCE3::getScreenWidth() && _videoMode.scaleFactor * _videoMode.screenWidth > OSystem_WINCE3::getScreenHeight())
                                     || (_videoMode.scaleFactor * _videoMode.screenHeight > OSystem_WINCE3::getScreenWidth() && _videoMode.scaleFactor * _videoMode.screenHeight > OSystem_WINCE3::getScreenHeight()))) {
            _videoMode.scaleFactor = 1;
            _scalerProc = Normal1x;
      }

      // Common scaler system was used
      if (_scaleFactorXm < 0) {
            _scaleFactorXm = _videoMode.scaleFactor;
            _scaleFactorXd = 1;
            _scaleFactorYm = _videoMode.scaleFactor;
            _scaleFactorYd = 1;
      }

      _forceFull = true;

      if (oldScaleFactorXm != _scaleFactorXm ||
              oldScaleFactorXd != _scaleFactorXd ||
              oldScaleFactorYm != _scaleFactorYm ||
              oldScaleFactorYd != _scaleFactorYd) {
            _scalersChanged = true;
      } else
            _scalersChanged = false;


      return true;

}

bool WINCESdlGraphicsManager::loadGFXMode() {
      int displayWidth;
      int displayHeight;
      unsigned int flags = SDL_FULLSCREEN | SDL_SWSURFACE;

      _videoMode.fullscreen = true; // forced
      _forceFull = true;

      _tmpscreen = NULL;

      // Recompute scalers if necessary
      update_scalers();

      // Create the surface that contains the 8 bit game data
      _screen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth, _videoMode.screenHeight, 8, 0, 0, 0, 0);
      if (_screen == NULL)
            error("_screen failed (%s)", SDL_GetError());

      // Create the surface that contains the scaled graphics in 16 bit mode
      // Always use full screen mode to have a "clean screen"
      if (!_videoMode.aspectRatioCorrection) {
            displayWidth = _videoMode.screenWidth * _scaleFactorXm / _scaleFactorXd;
            displayHeight = _videoMode.screenHeight * _scaleFactorYm / _scaleFactorYd;
      } else {
            displayWidth = _videoMode.screenWidth * _videoMode.scaleFactor;
            displayHeight = _videoMode.screenHeight * _videoMode.scaleFactor;
      }

      switch (_orientationLandscape) {
      case 1:
            flags |= SDL_LANDSCVIDEO;
            break;
      case 2:
            flags |= SDL_INVLNDVIDEO;
            break;
      default:
            flags |= SDL_PORTRTVIDEO;
      }
      _hwscreen = SDL_SetVideoMode(displayWidth, displayHeight, 16, flags);

      if (_hwscreen == NULL) {
            warning("SDL_SetVideoMode says we can't switch to that mode (%s)", SDL_GetError());
            g_system->quit();
      }

      // see what orientation sdl finally accepted
      if (_hwscreen->flags & SDL_PORTRTVIDEO)
            _orientationLandscape = _newOrientation = 0;
      else if (_hwscreen->flags & SDL_LANDSCVIDEO)
            _orientationLandscape = _newOrientation = 1;
      else
            _orientationLandscape = _newOrientation = 2;

      // Create the surface used for the graphics in 16 bit before scaling, and also the overlay
      // Distinguish 555 and 565 mode
      if (_hwscreen->format->Rmask == 0x7C00)
            InitScalers(555);
      else
            InitScalers(565);
      _overlayFormat.bytesPerPixel = _hwscreen->format->BytesPerPixel;
      _overlayFormat.rLoss = _hwscreen->format->Rloss;
      _overlayFormat.gLoss = _hwscreen->format->Gloss;
      _overlayFormat.bLoss = _hwscreen->format->Bloss;
      _overlayFormat.aLoss = _hwscreen->format->Aloss;
      _overlayFormat.rShift = _hwscreen->format->Rshift;
      _overlayFormat.gShift = _hwscreen->format->Gshift;
      _overlayFormat.bShift = _hwscreen->format->Bshift;
      _overlayFormat.aShift = _hwscreen->format->Ashift;

      // Need some extra bytes around when using 2xSaI
      _tmpscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth + 3, _videoMode.screenHeight + 3, 16, _hwscreen->format->Rmask, _hwscreen->format->Gmask, _hwscreen->format->Bmask, _hwscreen->format->Amask);

      if (_tmpscreen == NULL)
            error("_tmpscreen creation failed (%s)", SDL_GetError());

      // Overlay
      if (CEDevice::hasDesktopResolution()) {
            _overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth * _scaleFactorXm / _scaleFactorXd, _videoMode.overlayHeight * _scaleFactorYm / _scaleFactorYd, 16, 0, 0, 0, 0);
            if (_overlayscreen == NULL)
                  error("_overlayscreen failed (%s)", SDL_GetError());
            _tmpscreen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth * _scaleFactorXm / _scaleFactorXd + 3, _videoMode.overlayHeight * _scaleFactorYm / _scaleFactorYd + 3, 16, 0, 0, 0, 0);
            if (_tmpscreen2 == NULL)
                  error("_tmpscreen2 failed (%s)", SDL_GetError());
      } else {
            _overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth, _videoMode.overlayHeight, 16, 0, 0, 0, 0);
            if (_overlayscreen == NULL)
                  error("_overlayscreen failed (%s)", SDL_GetError());
            _tmpscreen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth + 3, _videoMode.overlayHeight + 3, 16, 0, 0, 0, 0);
            if (_tmpscreen2 == NULL)
                  error("_tmpscreen2 failed (%s)", SDL_GetError());
      }

      // Toolbar
      _toolbarHighDrawn = false;
      uint16 *toolbar_screen = (uint16 *)calloc(320 * 40, sizeof(uint16));    // *not* leaking memory here
      _toolbarLow = SDL_CreateRGBSurfaceFrom(toolbar_screen, 320, 40, 16, 320 * 2, _hwscreen->format->Rmask, _hwscreen->format->Gmask, _hwscreen->format->Bmask, _hwscreen->format->Amask);

      if (_toolbarLow == NULL)
            error("_toolbarLow failed (%s)", SDL_GetError());

      if (_videoMode.screenHeight > 240) {
            uint16 *toolbar_screen_high = (uint16 *)calloc(640 * 80, sizeof(uint16));
            _toolbarHigh = SDL_CreateRGBSurfaceFrom(toolbar_screen_high, 640, 80, 16, 640 * 2, _hwscreen->format->Rmask, _hwscreen->format->Gmask, _hwscreen->format->Bmask, _hwscreen->format->Amask);

            if (_toolbarHigh == NULL)
                  error("_toolbarHigh failed (%s)", SDL_GetError());
      } else
            _toolbarHigh = NULL;

      // keyboard cursor control, some other better place for it?
      _sdlEventSource->resetKeyboadEmulation(_videoMode.screenWidth * _scaleFactorXm / _scaleFactorXd - 1, _videoMode.screenHeight * _scaleFactorXm / _scaleFactorXd - 1);

      return true;
}

void WINCESdlGraphicsManager::unloadGFXMode() {
      if (_screen) {
            SDL_FreeSurface(_screen);
            _screen = NULL;
      }

      if (_hwscreen) {
            SDL_FreeSurface(_hwscreen);
            _hwscreen = NULL;
      }

      if (_tmpscreen) {
            SDL_FreeSurface(_tmpscreen);
            _tmpscreen = NULL;
      }
}

bool WINCESdlGraphicsManager::hotswapGFXMode() {
      if (!_screen)
            return false;

      // Keep around the old _screen & _tmpscreen so we can restore the screen data
      // after the mode switch. (also for the overlay)
      SDL_Surface *old_screen = _screen;
      SDL_Surface *old_tmpscreen = _tmpscreen;
      SDL_Surface *old_overlayscreen = _overlayscreen;
      SDL_Surface *old_tmpscreen2 = _tmpscreen2;

      // Release the HW screen surface
      SDL_FreeSurface(_hwscreen);

      // Release toolbars
      free(_toolbarLow->pixels);
      SDL_FreeSurface(_toolbarLow);
      if (_toolbarHigh) {
            free(_toolbarHigh->pixels);
            SDL_FreeSurface(_toolbarHigh);
      }

      // Setup the new GFX mode
      if (!loadGFXMode()) {
            unloadGFXMode();

            _screen = old_screen;
            _overlayscreen = old_overlayscreen;

            return false;
      }

      // reset palette
      SDL_SetColors(_screen, _currentPalette, 0, 256);

      // Restore old screen content
      SDL_BlitSurface(old_screen, NULL, _screen, NULL);
      SDL_BlitSurface(old_tmpscreen, NULL, _tmpscreen, NULL);
      if (_overlayVisible) {
            SDL_BlitSurface(old_overlayscreen, NULL, _overlayscreen, NULL);
            SDL_BlitSurface(old_tmpscreen2, NULL, _tmpscreen2, NULL);
      }

      // Free the old surfaces
      SDL_FreeSurface(old_screen);
      SDL_FreeSurface(old_tmpscreen);
      SDL_FreeSurface(old_overlayscreen);
      SDL_FreeSurface(old_tmpscreen2);

      // Blit everything back to the screen
      _toolbarHighDrawn = false;
      internUpdateScreen();

      // Make sure that a Common::EVENT_SCREEN_CHANGED gets sent later -> FIXME this crashes when no game has been loaded.
//    _modeChanged = true;

      return true;
}

bool WINCESdlGraphicsManager::saveScreenshot(const char *filename) {
      assert(_hwscreen != NULL);

      Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
      SDL_SaveBMP(_hwscreen, filename);
      return true;
}

void WINCESdlGraphicsManager::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) {
      assert(_transactionMode == kTransactionNone);

      if (_overlayscreen == NULL)
            return;

      // Clip the coordinates
      if (x < 0) {
            w += x;
            buf -= x;
            x = 0;
      }

      if (y < 0) {
            h += y;
            buf -= y * pitch;
            y = 0;
      }

      if (w > _videoMode.overlayWidth - x) {
            w = _videoMode.overlayWidth - x;
      }

      if (h > _videoMode.overlayHeight - y) {
            h = _videoMode.overlayHeight - y;
      }

      if (w <= 0 || h <= 0)
            return;

      // Mark the modified region as dirty
      addDirtyRect(x, y, w, h);

      undrawMouse();

      if (SDL_LockSurface(_overlayscreen) == -1)
            error("SDL_LockSurface failed: %s", SDL_GetError());

      byte *dst = (byte *)_overlayscreen->pixels + y * _overlayscreen->pitch + x * 2;
      do {
            memcpy(dst, buf, w * 2);
            dst += _overlayscreen->pitch;
            buf += pitch;
      } while (--h);

      SDL_UnlockSurface(_overlayscreen);
}

void WINCESdlGraphicsManager::copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h) {
      assert(_transactionMode == kTransactionNone);
      assert(src);

      if (_screen == NULL)
            return;

      Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends

      /* Clip the coordinates */
      if (x < 0) {
            w += x;
            src -= x;
            x = 0;
      }

      if (y < 0) {
            h += y;
            src -= y * pitch;
            y = 0;
      }

      if (w > _videoMode.screenWidth - x) {
            w = _videoMode.screenWidth - x;
      }

      if (h > _videoMode.screenHeight - y) {
            h = _videoMode.screenHeight - y;
      }

      if (w <= 0 || h <= 0)
            return;

      addDirtyRect(x, y, w, h);

      undrawMouse();

      // Try to lock the screen surface
      if (SDL_LockSurface(_screen) == -1)
            error("SDL_LockSurface failed: %s", SDL_GetError());

      byte *dst = (byte *)_screen->pixels + y * _videoMode.screenWidth + x;

      if (_videoMode.screenWidth == pitch && pitch == w) {
            memcpy(dst, src, h * w);
      } else {
            do {
                  memcpy(dst, src, w);
                  src += pitch;
                  dst += _videoMode.screenWidth;
            } while (--h);
      }

      // Unlock the screen surface
      SDL_UnlockSurface(_screen);
}

void WINCESdlGraphicsManager::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) {

      undrawMouse();
      if (w == 0 || h == 0)
            return;

      _mouseCurState.w = w;
      _mouseCurState.h = h;

      _mouseHotspotX = hotspot_x;
      _mouseHotspotY = hotspot_y;

      _mouseKeyColor = keycolor;

      free(_mouseData);

      _mouseData = (byte *) malloc(w * h);
      memcpy(_mouseData, buf, w * h);

      if (w > _mouseBackupDim || h > _mouseBackupDim) {
            // mouse has been undrawn, adjust sprite backup area
            free(_mouseBackupOld);
            free(_mouseBackupToolbar);
            uint16 tmp = (w > h) ? w : h;
            _mouseBackupOld = (byte *) malloc(tmp * tmp * 2);   // can hold 8bpp (playfield) or 16bpp (overlay) data
            _mouseBackupToolbar = (uint16 *) malloc(tmp * tmp * 2); // 16 bpp
            _mouseBackupDim = tmp;
      }
}

void WINCESdlGraphicsManager::adjustMouseEvent(const Common::Event &event) {
      if (!event.synthetic) {
            Common::Event newEvent(event);
            newEvent.synthetic = true;
            /*
            if (!_overlayVisible) {
                  newEvent.mouse.x = newEvent.mouse.x * _scaleFactorXd / _scaleFactorXm;
                  newEvent.mouse.y = newEvent.mouse.y * _scaleFactorYd / _scaleFactorYm;
                  newEvent.mouse.x /= _videoMode.scaleFactor;
                  newEvent.mouse.y /= _videoMode.scaleFactor;
                  if (_videoMode.aspectRatioCorrection)
                        newEvent.mouse.y = aspect2Real(newEvent.mouse.y);
            }
            */
            g_system->getEventManager()->pushEvent(newEvent);
      }
}

void WINCESdlGraphicsManager::setMousePos(int x, int y) {
      if (x != _mouseCurState.x || y != _mouseCurState.y) {
            undrawMouse();
            _mouseCurState.x = x;
            _mouseCurState.y = y;
            updateScreen();
      }
}

Graphics::Surface *WINCESdlGraphicsManager::lockScreen() {
      // Make sure mouse pointer is not painted over the playfield at the time of locking
      undrawMouse();
      return SdlGraphicsManager::lockScreen();
}

void WINCESdlGraphicsManager::showOverlay() {
      assert(_transactionMode == kTransactionNone);

      if (_overlayVisible)
            return;

      undrawMouse();
      _overlayVisible = true;
      update_scalers();
      clearOverlay();
}

void WINCESdlGraphicsManager::hideOverlay() {
      assert(_transactionMode == kTransactionNone);

      if (!_overlayVisible)
            return;

      undrawMouse();
      _overlayVisible = false;
      clearOverlay();
      _forceFull = true;
}

void WINCESdlGraphicsManager::blitCursor() {
}

void WINCESdlGraphicsManager::drawToolbarMouse(SDL_Surface *surf, bool draw) {

      if (!_mouseData || !_usesEmulatedMouse)
            return;

      int x = _mouseCurState.x - _mouseHotspotX;
      int y = _mouseCurState.y - _mouseHotspotY - _toolbarHandler.getOffset();
      int w = _mouseCurState.w;
      int h = _mouseCurState.h;
      byte color;
      const byte *src = _mouseData;
      int width;

      // clip
      if (x < 0) {
            w += x;
            src -= x;
            x = 0;
      }
      if (y < 0) {
            h += y;
            src -= y * _mouseCurState.w;
            y = 0;
      }
      if (w > surf->w - x)
            w = surf->w - x;
      if (h > surf->h - y)
            h = surf->h - y;
      if (w <= 0 || h <= 0)
            return;

      if (SDL_LockSurface(surf) == -1)
            error("SDL_LockSurface failed at internDrawToolbarMouse: %s", SDL_GetError());

      uint16 *bak = _mouseBackupToolbar;  // toolbar surfaces are 16bpp
      uint16 *dst;
      dst = (uint16 *)surf->pixels + y * surf->w + x;

      if (draw) {     // blit it
            while (h > 0) {
                  width = w;
                  while (width > 0) {
                        *bak++ = *dst;
                        color = *src++;
                        if (color != _mouseKeyColor)    // transparent color
                              *dst = 0xFFFF;
                        dst++;
                        width--;
                  }
                  src += _mouseCurState.w - w;
                  bak += _mouseBackupDim - w;
                  dst += surf->w - w;
                  h--;
            }
      } else {        // restore bg
            for (y = 0; y < h; ++y, bak += _mouseBackupDim, dst += surf->w)
                  memcpy(dst, bak, w << 1);
      }

      SDL_UnlockSurface(surf);
}

void WINCESdlGraphicsManager::warpMouse(int x, int y) {
      if (_mouseCurState.x != x || _mouseCurState.y != y) {
            SDL_WarpMouse(x * _scaleFactorXm / _scaleFactorXd, y * _scaleFactorYm / _scaleFactorYd);

            // SDL_WarpMouse() generates a mouse movement event, so
            // set_mouse_pos() would be called eventually. However, the
            // cannon script in CoMI calls this function twice each time
            // the cannon is reloaded. Unless we update the mouse position
            // immediately the second call is ignored, causing the cannon
            // to change its aim.

            setMousePos(x, y);
      }
}

void WINCESdlGraphicsManager::unlockScreen() {
      SdlGraphicsManager::unlockScreen();
}

void WINCESdlGraphicsManager::internDrawMouse() {
      if (!_mouseNeedsRedraw || !_mouseVisible || !_mouseData)
            return;

      int x = _mouseCurState.x - _mouseHotspotX;
      int y = _mouseCurState.y - _mouseHotspotY;
      int w = _mouseCurState.w;
      int h = _mouseCurState.h;
      byte color;
      const byte *src = _mouseData;       // Image representing the mouse
      int width;

      // clip the mouse rect, and adjust the src pointer accordingly
      if (x < 0) {
            w += x;
            src -= x;
            x = 0;
      }
      if (y < 0) {
            h += y;
            src -= y * _mouseCurState.w;
            y = 0;
      }

      if (w > _videoMode.screenWidth - x)
            w = _videoMode.screenWidth - x;
      if (h > _videoMode.screenHeight - y)
            h = _videoMode.screenHeight - y;

      // Quick check to see if anything has to be drawn at all
      if (w <= 0 || h <= 0)
            return;

      // Draw the mouse cursor; backup the covered area in "bak"
      if (SDL_LockSurface(_overlayVisible ? _overlayscreen : _screen) == -1)
            error("SDL_LockSurface failed: %s", SDL_GetError());

      // Mark as dirty
      addDirtyRect(x, y, w, h);

      if (!_overlayVisible) {
            byte *bak = _mouseBackupOld;        // Surface used to backup the area obscured by the mouse
            byte *dst;                  // Surface we are drawing into

            dst = (byte *)_screen->pixels + y * _videoMode.screenWidth + x;
            while (h > 0) {
                  width = w;
                  while (width > 0) {
                        *bak++ = *dst;
                        color = *src++;
                        if (color != _mouseKeyColor)    // transparent, don't draw
                              *dst = color;
                        dst++;
                        width--;
                  }
                  src += _mouseCurState.w - w;
                  bak += _mouseBackupDim - w;
                  dst += _videoMode.screenWidth - w;
                  h--;
            }

      } else {
            uint16 *bak = (uint16 *)_mouseBackupOld;    // Surface used to backup the area obscured by the mouse
            byte *dst;                  // Surface we are drawing into

            dst = (byte *)_overlayscreen->pixels + (y + 1) * _overlayscreen->pitch + (x + 1) * 2;
            while (h > 0) {
                  width = w;
                  while (width > 0) {
                        *bak++ = *(uint16 *)dst;
                        color = *src++;
                        if (color != 0xFF)  // 0xFF = transparent, don't draw
                              *(uint16 *)dst = SDL_MapRGB(_overlayscreen->format, _currentPalette[color].r, _currentPalette[color].g, _currentPalette[color].b);
                        dst += 2;
                        width--;
                  }
                  src += _mouseCurState.w - w;
                  bak += _mouseBackupDim - w;
                  dst += _overlayscreen->pitch - w * 2;
                  h--;
            }
      }

      SDL_UnlockSurface(_overlayVisible ? _overlayscreen : _screen);

      // Finally, set the flag to indicate the mouse has been drawn
      _mouseNeedsRedraw = false;
}

void WINCESdlGraphicsManager::undrawMouse() {
      assert(_transactionMode == kTransactionNone);

      if (_mouseNeedsRedraw)
            return;

      int old_mouse_x = _mouseCurState.x - _mouseHotspotX;
      int old_mouse_y = _mouseCurState.y - _mouseHotspotY;
      int old_mouse_w = _mouseCurState.w;
      int old_mouse_h = _mouseCurState.h;

      // clip the mouse rect, and adjust the src pointer accordingly
      if (old_mouse_x < 0) {
            old_mouse_w += old_mouse_x;
            old_mouse_x = 0;
      }
      if (old_mouse_y < 0) {
            old_mouse_h += old_mouse_y;
            old_mouse_y = 0;
      }

      if (old_mouse_w > _videoMode.screenWidth - old_mouse_x)
            old_mouse_w = _videoMode.screenWidth - old_mouse_x;
      if (old_mouse_h > _videoMode.screenHeight - old_mouse_y)
            old_mouse_h = _videoMode.screenHeight - old_mouse_y;

      // Quick check to see if anything has to be drawn at all
      if (old_mouse_w <= 0 || old_mouse_h <= 0)
            return;


      if (SDL_LockSurface(_overlayVisible ? _overlayscreen : _screen) == -1)
            error("SDL_LockSurface failed: %s", SDL_GetError());

      int y;
      if (!_overlayVisible) {
            byte *dst, *bak = _mouseBackupOld;

            // No need to do clipping here, since drawMouse() did that already
            dst = (byte *)_screen->pixels + old_mouse_y * _videoMode.screenWidth + old_mouse_x;
            for (y = 0; y < old_mouse_h; ++y, bak += _mouseBackupDim, dst += _videoMode.screenWidth)
                  memcpy(dst, bak, old_mouse_w);
      } else {
            byte *dst;
            uint16 *bak = (uint16 *)_mouseBackupOld;

            // No need to do clipping here, since drawMouse() did that already
            dst = (byte *)_overlayscreen->pixels + (old_mouse_y + 1) * _overlayscreen->pitch + (old_mouse_x + 1) * 2;
            for (y = 0; y < old_mouse_h; ++y, bak += _mouseBackupDim, dst += _overlayscreen->pitch)
                  memcpy(dst, bak, old_mouse_w << 1);
      }

      addDirtyRect(old_mouse_x, old_mouse_y, old_mouse_w, old_mouse_h);

      SDL_UnlockSurface(_overlayVisible ? _overlayscreen : _screen);

      _mouseNeedsRedraw = true;
}

void WINCESdlGraphicsManager::drawMouse() {
      if (!(_toolbarHandler.visible() && _mouseCurState.y >= _toolbarHandler.getOffset() && !_usesEmulatedMouse) && !_forceHideMouse)
            internDrawMouse();
}

bool WINCESdlGraphicsManager::showMouse(bool visible) {
      if (_mouseVisible == visible)
            return visible;

      if (visible == false)
            undrawMouse();

      bool last = _mouseVisible;
      _mouseVisible = visible;
      _mouseNeedsRedraw = true;

      return last;
}

void WINCESdlGraphicsManager::addDirtyRect(int x, int y, int w, int h, bool mouseRect) {

      if (_forceFull || _paletteDirtyEnd)
            return;

      SdlGraphicsManager::addDirtyRect(x, y, w, h, false);
}

void WINCESdlGraphicsManager::swap_panel_visibility() {
      //if (!_forcePanelInvisible && !_panelStateForced) {
      if (_zoomDown || _zoomUp)
            return;

      if (_panelVisible) {
            if (_toolbarHandler.activeName() == NAME_PANEL_KEYBOARD)
                  _panelVisible = !_panelVisible;
            else
                  _toolbarHandler.setActive(NAME_PANEL_KEYBOARD);
      } else {
            _toolbarHandler.setActive(NAME_MAIN_PANEL);
            _panelVisible = !_panelVisible;
      }
      _toolbarHandler.setVisible(_panelVisible);
      _toolbarHighDrawn = false;

      if (_videoMode.screenHeight > 240)
            addDirtyRect(0, 400, 640, 80);
      else
            addDirtyRect(0, 200, 320, 40);

      if (_toolbarHandler.activeName() == NAME_PANEL_KEYBOARD && _panelVisible)
            internUpdateScreen();
      else {
            update_scalers();
            hotswapGFXMode();
      }
      //}
}

void WINCESdlGraphicsManager::swap_panel() {
      _toolbarHighDrawn = false;
      //if (!_panelStateForced) {
      if (_toolbarHandler.activeName() == NAME_PANEL_KEYBOARD && _panelVisible)
            _toolbarHandler.setActive(NAME_MAIN_PANEL);
      else
            _toolbarHandler.setActive(NAME_PANEL_KEYBOARD);

      if (_videoMode.screenHeight > 240)
            addDirtyRect(0, 400, 640, 80);
      else
            addDirtyRect(0, 200, 320, 40);

      _toolbarHandler.setVisible(true);
      if (!_panelVisible) {
            _panelVisible = true;
            update_scalers();
            hotswapGFXMode();
      }
      //}
}

void WINCESdlGraphicsManager::swap_smartphone_keyboard() {
      _toolbarHandler.setActive(NAME_PANEL_KEYBOARD);
      _panelVisible = !_panelVisible;
      _toolbarHandler.setVisible(_panelVisible);
      if (_videoMode.screenHeight > 240)
            addDirtyRect(0, 0, 640, 80);
      else
            addDirtyRect(0, 0, 320, 40);
      internUpdateScreen();
}

void WINCESdlGraphicsManager::swap_zoom_up() {
      if (_zoomUp) {
            // restore visibility
            _toolbarHandler.setVisible(_saveToolbarZoom);
            // restore scaler
            _scaleFactorYd = 2;
            _scalerProc = DownscaleAllByHalf;
            _zoomUp = false;
            _zoomDown = false;
      } else {
            // only active if running on a PocketPC
            if (_scalerProc != DownscaleAllByHalf && _scalerProc != DownscaleHorizByHalf)
                  return;
            if (_scalerProc == DownscaleAllByHalf) {
                  _saveToolbarZoom = _toolbarHandler.visible();
                  _toolbarHandler.setVisible(false);
                  // set zoom scaler
                  _scaleFactorYd = 1;
                  _scalerProc = DownscaleHorizByHalf;
            }

            _zoomDown = false;
            _zoomUp = true;
      }
      // redraw whole screen
      addDirtyRect(0, 0, 640, 480);
      internUpdateScreen();
}

void WINCESdlGraphicsManager::swap_zoom_down() {
      if (_zoomDown) {
            // restore visibility
            _toolbarHandler.setVisible(_saveToolbarZoom);
            // restore scaler
            _scaleFactorYd = 2;
            _scalerProc = DownscaleAllByHalf;
            _zoomDown = false;
            _zoomUp = false;
      } else {
            // only active if running on a PocketPC
            if (_scalerProc != DownscaleAllByHalf && _scalerProc != DownscaleHorizByHalf)
                  return;
            if (_scalerProc == DownscaleAllByHalf) {
                  _saveToolbarZoom = _toolbarHandler.visible();
                  _toolbarHandler.setVisible(false);
                  // set zoom scaler
                  _scaleFactorYd = 1;
                  _scalerProc = DownscaleHorizByHalf;
            }

            _zoomUp = false;
            _zoomDown = true;
      }
      // redraw whole screen
      addDirtyRect(0, 0, 640, 480);
      internUpdateScreen();
}

void WINCESdlGraphicsManager::swap_mouse_visibility() {
      _forceHideMouse = !_forceHideMouse;
      if (_forceHideMouse)
            undrawMouse();
}

void WINCESdlGraphicsManager::init_panel() {
      _panelVisible = true;
      if (_panelInitialized) {
            _toolbarHandler.setVisible(true);
            _toolbarHandler.setActive(NAME_MAIN_PANEL);
      }
}

void WINCESdlGraphicsManager::reset_panel() {
      _panelVisible = false;
      _toolbarHandler.setVisible(false);
}

// Smartphone actions
void WINCESdlGraphicsManager::initZones() {
      int i;

      _currentZone = 0;
      for (i = 0; i < TOTAL_ZONES; i++) {
            _mouseXZone[i] = (_zones[i].x + (_zones[i].width / 2)) * _scaleFactorXm / _scaleFactorXd;
            _mouseYZone[i] = (_zones[i].y + (_zones[i].height / 2)) * _scaleFactorYm / _scaleFactorYd;
      }
}

void WINCESdlGraphicsManager::smartphone_rotate_display() {
      _orientationLandscape = _newOrientation = _orientationLandscape == 1 ? 2 : 1;
      ConfMan.setInt("landscape", _orientationLandscape);
      ConfMan.flushToDisk();
      hotswapGFXMode();
}

void WINCESdlGraphicsManager::create_toolbar() {
      CEGUI::PanelKeyboard *keyboard;

      // Add the keyboard
      keyboard = new CEGUI::PanelKeyboard(PANEL_KEYBOARD);
      _toolbarHandler.add(NAME_PANEL_KEYBOARD, *keyboard);
      _toolbarHandler.setVisible(false);
}

void WINCESdlGraphicsManager::swap_freeLook() {
      _freeLook = !_freeLook;
}

bool WINCESdlGraphicsManager::getFreeLookState() {
      return _freeLook;
}

WINCESdlGraphicsManager::zoneDesc WINCESdlGraphicsManager::_zones[TOTAL_ZONES] = {
      { 0, 0, 320, 145 },
      { 0, 145, 150, 55 },
      { 150, 145, 170, 55 }
};

#endif /* _WIN32_WCE */


Generated by  Doxygen 1.6.0   Back to index