From aa452d3aeb3e2506c7386554d5dfbe852b8ae475 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 8 Mar 2011 12:53:31 +0100 Subject: WINCE: Make scummvm compile and run again for WinCE platform (patch #3202337) --- backends/graphics/sdl/sdl-graphics.cpp | 7 - backends/graphics/wincesdl/wincesdl-graphics.cpp | 1638 ++++++++++++++++++++++ backends/graphics/wincesdl/wincesdl-graphics.h | 206 +++ 3 files changed, 1844 insertions(+), 7 deletions(-) create mode 100644 backends/graphics/wincesdl/wincesdl-graphics.cpp create mode 100644 backends/graphics/wincesdl/wincesdl-graphics.h (limited to 'backends/graphics') diff --git a/backends/graphics/sdl/sdl-graphics.cpp b/backends/graphics/sdl/sdl-graphics.cpp index d8b686e61f..7d36786b7d 100644 --- a/backends/graphics/sdl/sdl-graphics.cpp +++ b/backends/graphics/sdl/sdl-graphics.cpp @@ -161,13 +161,6 @@ SdlGraphicsManager::SdlGraphicsManager(SdlEventSource *sdlEventSource) _graphicsMutex = g_system->createMutex(); -#ifdef _WIN32_WCE - if (ConfMan.hasKey("use_GDI") && ConfMan.getBool("use_GDI")) { - SDL_VideoInit("windib", 0); - sdlFlags ^= SDL_INIT_VIDEO; - } -#endif - SDL_ShowCursor(SDL_DISABLE); memset(&_oldVideoMode, 0, sizeof(_oldVideoMode)); diff --git a/backends/graphics/wincesdl/wincesdl-graphics.cpp b/backends/graphics/wincesdl/wincesdl-graphics.cpp new file mode 100644 index 0000000000..ad1a8e7a1a --- /dev/null +++ b/backends/graphics/wincesdl/wincesdl-graphics.cpp @@ -0,0 +1,1638 @@ +/* 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/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), + _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), _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 +//__XXX__ panel->add(NAME_ITEM_SOUND, new CEGUI::ItemSwitch(ITEM_SOUND_OFF, ITEM_SOUND_ON, &_soundMaster)); + 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"); +} + +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(); +} + +// 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); +} + +WINCESdlGraphicsManager::zoneDesc WINCESdlGraphicsManager::_zones[TOTAL_ZONES] = { + { 0, 0, 320, 145 }, + { 0, 145, 150, 55 }, + { 150, 145, 170, 55 } +}; + +#endif /* _WIN32_WCE */ + diff --git a/backends/graphics/wincesdl/wincesdl-graphics.h b/backends/graphics/wincesdl/wincesdl-graphics.h new file mode 100644 index 0000000000..76b623d5d3 --- /dev/null +++ b/backends/graphics/wincesdl/wincesdl-graphics.h @@ -0,0 +1,206 @@ +/* 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$ + * + */ + +#ifndef BACKENDS_GRAPHICS_WINCE_SDL_H +#define BACKENDS_GRAPHICS_WINCE_SDL_H + +#include "backends/graphics/sdl/sdl-graphics.h" +#include "backends/platform/wince/CEgui/CEGUI.h" + +// Internal GUI names +#define NAME_MAIN_PANEL "MainPanel" +#define NAME_PANEL_KEYBOARD "Keyboard" +#define NAME_ITEM_OPTIONS "Options" +#define NAME_ITEM_SKIP "Skip" +#define NAME_ITEM_SOUND "Sound" +#define NAME_ITEM_ORIENTATION "Orientation" +#define NAME_ITEM_BINDKEYS "Bindkeys" + +#define TOTAL_ZONES 3 + +extern bool _hasSmartphoneResolution; + +class WINCESdlGraphicsManager : public SdlGraphicsManager { +public: + WINCESdlGraphicsManager(SdlEventSource *sdlEventSource); + + const OSystem::GraphicsMode *getSupportedGraphicsModes() const; + void initSize(uint w, uint h, const Graphics::PixelFormat *format = NULL); + + bool hasFeature(OSystem::Feature f); + void setFeatureState(OSystem::Feature f, bool enable); + bool getFeatureState(OSystem::Feature f); + + int getDefaultGraphicsMode() const; + bool setGraphicsMode(int mode); + bool loadGFXMode(); + void unloadGFXMode(); + bool hotswapGFXMode(); + + // Overloaded from SDL backend (toolbar handling) + void drawMouse(); + // Overloaded from SDL backend (new scaler handling) + void addDirtyRect(int x, int y, int w, int h, bool mouseRect = false); + // Overloaded from SDL backend (new scaler handling) + void warpMouse(int x, int y); + + // Update the dirty areas of the screen + void internUpdateScreen(); + bool saveScreenshot(const char *filename); + + // Overloaded from SDL_Common (FIXME) + void internDrawMouse(); + void undrawMouse(); + bool showMouse(bool visible); + void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format); // overloaded by CE backend + void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h); + void copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h); // overloaded by CE backend (FIXME) + Graphics::Surface *lockScreen(); + void unlockScreen(); + void blitCursor(); + void showOverlay(); + void hideOverlay(); + void setMousePos(int x, int y); + + // GUI and action stuff + void swap_panel_visibility(); + void swap_panel(); + void swap_smartphone_keyboard(); + void swap_zoom_up(); + void swap_zoom_down(); + void swap_mouse_visibility(); + + +//#ifdef WIN32_PLATFORM_WFSP + void move_cursor_up(); + void move_cursor_down(); + void move_cursor_left(); + void move_cursor_right(); + + void retrieve_mouse_location(int &x, int &y); + void switch_zone(); + + void add_right_click(bool pushed); + void add_left_click(bool pushed); + + void initZones(); + void smartphone_rotate_display(); +//#endif + + bool _panelInitialized; // only initialize the toolbar once + bool _noDoubleTapRMB; // disable double tap -> rmb click + + CEGUI::ToolbarHandler _toolbarHandler; + + bool _toolbarHighDrawn; // cache toolbar 640x80 + int _newOrientation; // new orientation + int _orientationLandscape; // current orientation + + int _scaleFactorXm; // scaler X * + int _scaleFactorXd; // scaler X / + int _scaleFactorYm; // scaler Y * + int _scaleFactorYd; // scaler Y / + + bool _hasfocus; // scummvm has the top window + + bool hasPocketPCResolution(); + bool hasDesktopResolution(); + bool hasSquareQVGAResolution(); + bool hasWideResolution() const; + + MousePos _mouseCurState; + + bool _zoomUp; // zooming up mode + bool _zoomDown; // zooming down mode + + bool _usesEmulatedMouse; // emulated mousemove ever been used in this session + + int _mouseXZone[TOTAL_ZONES]; + int _mouseYZone[TOTAL_ZONES]; + int _currentZone; + + // Smartphone specific variables + int _lastKeyPressed; // last key pressed + int _keyRepeat; // number of time the last key was repeated + int _keyRepeatTime; // elapsed time since the key was pressed + int _keyRepeatTrigger; // minimum time to consider the key was repeated + + struct zoneDesc { + int x; + int y; + int width; + int height; + }; + + static zoneDesc _zones[TOTAL_ZONES]; + +protected: + virtual void adjustMouseEvent(const Common::Event &event); + +private: + bool update_scalers(); + void update_game_settings(); + void drawToolbarMouse(SDL_Surface *surf, bool draw); + + void create_toolbar(); + bool _panelVisible; // panel visibility + bool _panelStateForced; // panel visibility forced by external call + String _saveActiveToolbar; // save active toolbar when forced + + bool _canBeAspectScaled; // game screen size allows for aspect scaling + + SDL_Rect _dirtyRectOut[NUM_DIRTY_RECT]; + bool _scalersChanged; + + bool isOzone(); + + bool _saveToolbarState; // save visibility when forced + bool _saveToolbarZoom; // save visibility when zooming + + SDL_Surface *_toolbarLow; // toolbar 320x40 + SDL_Surface *_toolbarHigh; // toolbar 640x80 + + // Mouse + int _mouseHotspotX, _mouseHotspotY; + byte *_mouseBackupOld; + uint16 *_mouseBackupToolbar; + uint16 _mouseBackupDim; + + bool _forceHideMouse; // force invisible mouse cursor + + // Smartphone specific variables + void loadDeviceConfigurationElement(Common::String element, int &value, int defaultValue); + int _repeatX; // repeat trigger for left and right cursor moves + int _repeatY; // repeat trigger for up and down cursor moves + int _stepX1; // offset for left and right cursor moves (slowest) + int _stepX2; // offset for left and right cursor moves (faster) + int _stepX3; // offset for left and right cursor moves (fastest) + int _stepY1; // offset for up and down cursor moves (slowest) + int _stepY2; // offset for up and down cursor moves (faster) + int _stepY3; // offset for up and down cursor moves (fastest) +}; + +#endif /* BACKENDS_GRAPHICS_WINCE_SDL_H */ + -- cgit v1.2.3