diff options
Diffstat (limited to 'backends')
93 files changed, 7354 insertions, 5444 deletions
diff --git a/backends/base-backend.cpp b/backends/base-backend.cpp index 42ab7b887a..f349cc8005 100644 --- a/backends/base-backend.cpp +++ b/backends/base-backend.cpp @@ -101,7 +101,4 @@ AudioCDManager *BaseBackend::getAudioCDManager() { } void BaseBackend::resetGraphicsScale() { - // As a hack, we use 0 here. Backends should override this method - // and provide their own. - setGraphicsMode(0); } diff --git a/backends/events/wincesdl/wincesdl-events.cpp b/backends/events/wincesdl/wincesdl-events.cpp new file mode 100644 index 0000000000..2505b0fb31 --- /dev/null +++ b/backends/events/wincesdl/wincesdl-events.cpp @@ -0,0 +1,332 @@ +/* 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/config-manager.h" + +#include "backends/events/wincesdl/wincesdl-events.h" +#include "backends/platform/wince/CEActionsPocket.h" +#include "backends/platform/wince/CEActionsSmartphone.h" +#include "backends/platform/wince/CEDevice.h" + +#include "backends/platform/sdl/sdl.h" + +WINCESdlEventSource::WINCESdlEventSource() + : _tapTime(0), _closeClick(false), _rbutton(false), + _freeLook(false), _graphicsMan(0) { +} + +void WINCESdlEventSource::init(WINCESdlGraphicsManager *graphicsMan) { + assert(graphicsMan); + _graphicsMan = graphicsMan; +} + +void WINCESdlEventSource::fillMouseEvent(Common::Event &event, int x, int y) { + event.mouse.x = x; + event.mouse.y = y; + + // Update the "keyboard mouse" coords + _km.x = event.mouse.x; + _km.y = event.mouse.y; + + // Adjust for the screen scaling + if (_graphicsMan->_zoomDown) + event.mouse.y += 240; + + event.mouse.x = event.mouse.x * _graphicsMan->_scaleFactorXd / _graphicsMan->_scaleFactorXm; + event.mouse.y = event.mouse.y * _graphicsMan->_scaleFactorYd / _graphicsMan->_scaleFactorYm; +} + +bool WINCESdlEventSource::pollEvent(Common::Event &event) { + SDL_Event ev; + ev.type = SDL_NOEVENT; + DWORD currentTime; + bool keyEvent = false; + int deltaX, deltaY; + + memset(&event, 0, sizeof(Common::Event)); + + handleKbdMouse(); + + // If the screen changed, send an Common::EVENT_SCREEN_CHANGED + int screenID = _graphicsMan->getScreenChangeID(); + if (screenID != _lastScreenID) { + _lastScreenID = screenID; + event.type = Common::EVENT_SCREEN_CHANGED; + return true; + } + + CEDevice::wakeUp(); + + currentTime = GetTickCount(); + + while (SDL_PollEvent(&ev)) { + switch (ev.type) { + case SDL_KEYDOWN: + debug(1, "Key down %X %s", ev.key.keysym.sym, SDL_GetKeyName((SDLKey)ev.key.keysym.sym)); + // KMOD_RESERVED is used if the key has been injected by an external buffer + if (ev.key.keysym.mod != KMOD_RESERVED && !GUI::Actions::Instance()->mappingActive()) { + keyEvent = true; + _graphicsMan->_lastKeyPressed = ev.key.keysym.sym; + _graphicsMan->_keyRepeatTime = currentTime; + _graphicsMan->_keyRepeat = 0; + + if (!GUI_Actions::Instance()->mappingActive() && GUI_Actions::Instance()->performMapped(ev.key.keysym.sym, true)) + return true; + } + + if (GUI_Actions::Instance()->mappingActive()) + event.kbd.flags = 0xFF; + else if (ev.key.keysym.sym == SDLK_PAUSE) { + _graphicsMan->_lastKeyPressed = 0; + event.type = Common::EVENT_PREDICTIVE_DIALOG; + return true; + } + event.type = Common::EVENT_KEYDOWN; + if (!GUI::Actions::Instance()->mappingActive()) + event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym; + else + event.kbd.keycode = (Common::KeyCode)mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, GUI::Actions::Instance()->mappingActive()); + event.kbd.ascii = mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, GUI::Actions::Instance()->mappingActive()); + + if (ev.key.keysym.mod == KMOD_RESERVED && ev.key.keysym.unicode == KMOD_SHIFT) { + event.kbd.ascii ^= 0x20; + event.kbd.flags = Common::KBD_SHIFT; + } + + return true; + + case SDL_KEYUP: + debug(1, "Key up %X %s", ev.key.keysym.sym, SDL_GetKeyName((SDLKey)ev.key.keysym.sym)); + // KMOD_RESERVED is used if the key has been injected by an external buffer + if (ev.key.keysym.mod != KMOD_RESERVED && !GUI::Actions::Instance()->mappingActive()) { + keyEvent = true; + _graphicsMan->_lastKeyPressed = 0; + + if (!GUI_Actions::Instance()->mappingActive() && GUI_Actions::Instance()->performMapped(ev.key.keysym.sym, false)) + return true; + } + + if (GUI_Actions::Instance()->mappingActive()) + event.kbd.flags = 0xFF; + else if (ev.key.keysym.sym == SDLK_PAUSE) { + _graphicsMan->_lastKeyPressed = 0; + return false; // chew up the show agi dialog key up event + } + + event.type = Common::EVENT_KEYUP; + if (!GUI::Actions::Instance()->mappingActive()) + event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym; + else + event.kbd.keycode = (Common::KeyCode)mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, GUI::Actions::Instance()->mappingActive()); + event.kbd.ascii = mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, GUI::Actions::Instance()->mappingActive()); + + if (ev.key.keysym.mod == KMOD_RESERVED && ev.key.keysym.unicode == KMOD_SHIFT) { + event.kbd.ascii ^= 0x20; + event.kbd.flags = Common::KBD_SHIFT; + } + + return true; + + case SDL_MOUSEMOTION: + event.type = Common::EVENT_MOUSEMOVE; + fillMouseEvent(event, ev.motion.x, ev.motion.y); + _graphicsMan->setMousePos(event.mouse.x, event.mouse.y); + + return true; + + case SDL_MOUSEBUTTONDOWN: + if (ev.button.button == SDL_BUTTON_LEFT) + event.type = Common::EVENT_LBUTTONDOWN; + else if (ev.button.button == SDL_BUTTON_RIGHT) + event.type = Common::EVENT_RBUTTONDOWN; + else + break; + fillMouseEvent(event, ev.button.x, ev.button.y); + + + if (event.mouse.x > _tapX) + deltaX = event.mouse.x - _tapX; + else + deltaX = _tapX - event.mouse.x; + if (event.mouse.y > _tapY) + deltaY = event.mouse.y - _tapY; + else + deltaY = _tapY - event.mouse.y; + _closeClick = (deltaX <= 5 && deltaY <= 5); + + if (!_isSmartphone) { + // handle double-taps + if (_tapTime) { // second tap + if (_closeClick && (GetTickCount() - _tapTime < 1000)) { + if (event.mouse.y <= 20 && + _graphicsMan->_panelInitialized) { + // top of screen (show panel) + _graphicsMan->swap_panel_visibility(); + } else if (!_graphicsMan->_noDoubleTapRMB) { + // right click + event.type = Common::EVENT_RBUTTONDOWN; + _rbutton = true; + } + } + _tapTime = 0; + } else { + _tapTime = GetTickCount(); + _tapX = event.mouse.x; + _tapY = event.mouse.y; + } + } + + if (_freeLook && !_closeClick) { + _rbutton = false; + _tapTime = 0; + _tapX = event.mouse.x; + _tapY = event.mouse.y; + event.type = Common::EVENT_MOUSEMOVE; + _graphicsMan->setMousePos(event.mouse.x, event.mouse.y); + } + + + if (_graphicsMan->_toolbarHandler.action(event.mouse.x, event.mouse.y, true)) { + if (!_graphicsMan->_toolbarHandler.drawn()) { + _graphicsMan->_toolbarHighDrawn = false; + _graphicsMan->internUpdateScreen(); + } + if (_graphicsMan->_newOrientation != _graphicsMan->_orientationLandscape) { + _graphicsMan->_orientationLandscape = _graphicsMan->_newOrientation; + _graphicsMan->_toolbarHighDrawn = false; + ConfMan.setInt("landscape", _graphicsMan->_orientationLandscape); + ConfMan.flushToDisk(); + _graphicsMan->hotswapGFXMode(); + } + return false; + } + + return true; + + case SDL_MOUSEBUTTONUP: + if (ev.button.button == SDL_BUTTON_LEFT) + event.type = Common::EVENT_LBUTTONUP; + else if (ev.button.button == SDL_BUTTON_RIGHT) + event.type = Common::EVENT_RBUTTONUP; + else + break; + + if (_rbutton) { + event.type = Common::EVENT_RBUTTONUP; + _rbutton = false; + } + + fillMouseEvent(event, ev.button.x, ev.button.y); + + if (_freeLook && !_closeClick) { + _tapX = event.mouse.x; + _tapY = event.mouse.y; + event.type = Common::EVENT_MOUSEMOVE; + _graphicsMan->setMousePos(event.mouse.x, event.mouse.y); + } + + if (_graphicsMan->_toolbarHandler.action(event.mouse.x, event.mouse.y, false)) { + if (!_graphicsMan->_toolbarHandler.drawn()) { + _graphicsMan->_toolbarHighDrawn = false; + _graphicsMan->internUpdateScreen(); + } + return false; + + } + return true; + + case SDL_VIDEOEXPOSE: + // HACK: Send a fake event, handled by SdlGraphicsManager + event.type = (Common::EventType)OSystem_SDL::kSdlEventExpose; + break; + + case SDL_QUIT: + event.type = Common::EVENT_QUIT; + return true; + + case SDL_ACTIVEEVENT: + if (ev.active.state & SDL_APPMOUSEFOCUS) + debug(2, "%s mouse focus.", ev.active.gain ? "Got" : "Lost"); + if (ev.active.state & SDL_APPINPUTFOCUS) + debug(2, "%s input focus.", ev.active.gain ? "Got" : "Lost"); + if (ev.active.state & SDL_APPACTIVE) + debug(2, "%s total focus.", ev.active.gain ? "Got" : "Lost"); + if (ev.active.state & SDL_APPINPUTFOCUS) { + _graphicsMan->_hasfocus = ev.active.gain; + SDL_PauseAudio(!_graphicsMan->_hasfocus); + if (_graphicsMan->_hasfocus) { + event.type = (Common::EventType)OSystem_SDL::kSdlEventExpose; + } + } + break; + } + } + + // Simulate repeated key for backend + if (!keyEvent && _graphicsMan->_lastKeyPressed && (int)currentTime > _graphicsMan->_keyRepeatTime + _graphicsMan->_keyRepeatTrigger) { + _graphicsMan->_keyRepeatTime = currentTime; + _graphicsMan->_keyRepeat++; + GUI_Actions::Instance()->performMapped(_graphicsMan->_lastKeyPressed, true); + } + + return false; +} + +int WINCESdlEventSource::mapKeyCE(SDLKey key, SDLMod mod, Uint16 unicode, bool unfilter) { + if (GUI::Actions::Instance()->mappingActive()) + return key; + + if (unfilter) { + switch (key) { + case SDLK_ESCAPE: + return SDLK_BACKSPACE; + case SDLK_F8: + return SDLK_ASTERISK; + case SDLK_F9: + return SDLK_HASH; + default: + return key; + } + } + + if (key >= SDLK_KP0 && key <= SDLK_KP9) { + return key - SDLK_KP0 + '0'; + } else if (key >= SDLK_UP && key <= SDLK_PAGEDOWN) { + return key; + } else if (key >= SDLK_NUMLOCK && key <= SDLK_EURO) { + return 0; + } + return key; +} + +void WINCESdlEventSource::swap_freeLook() { + _freeLook = !_freeLook; +} + +#endif /* _WIN32_WCE */ diff --git a/backends/events/wincesdl/wincesdl-events.h b/backends/events/wincesdl/wincesdl-events.h new file mode 100644 index 0000000000..f5b1026c46 --- /dev/null +++ b/backends/events/wincesdl/wincesdl-events.h @@ -0,0 +1,73 @@ +/* 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_EVENTS_SDL_WINCE_H +#define BACKENDS_EVENTS_SDL_WINCE_H + +#include "common/scummsys.h" + +#ifdef _WIN32_WCE + +#include "backends/events/sdl/sdl-events.h" +#include "backends/graphics/wincesdl/wincesdl-graphics.h" + +extern bool _isSmartphone; + +class WINCESdlEventSource : public SdlEventSource { +public: + WINCESdlEventSource(); + + void init(WINCESdlGraphicsManager *graphicsMan); + + void loadDeviceConfiguration(); + + // Overloaded from SDL backend (toolbar handling) + bool pollEvent(Common::Event &event); + // Overloaded from SDL backend (mouse and new scaler handling) + void fillMouseEvent(Common::Event &event, int x, int y); + + void swap_freeLook(); + +protected: + +private: + int mapKeyCE(SDLKey key, SDLMod mod, Uint16 unicode, bool unfilter); + + WINCESdlGraphicsManager *_graphicsMan; + + // Keyboard tap + int _tapX; + int _tapY; + long _tapTime; + + bool _closeClick; // flag when taps are spatially close together + bool _rbutton; // double tap -> right button simulation + bool _freeLook; // freeLook mode (do not send mouse button events) + +}; + +#endif + +#endif /* BACKENDS_EVENTS_SDL_WINCE_H */ diff --git a/backends/graphics/opengl/gltexture.cpp b/backends/graphics/opengl/gltexture.cpp index cd9e23cb71..7b7d40f174 100644 --- a/backends/graphics/opengl/gltexture.cpp +++ b/backends/graphics/opengl/gltexture.cpp @@ -149,7 +149,7 @@ void GLTexture::updateBuffer(const void *buf, int pitch, GLuint x, GLuint y, GLu glBindTexture(GL_TEXTURE_2D, _textureName); CHECK_GL_ERROR(); // Check if the buffer has its data contiguously - if (static_cast<int>(w) * _bytesPerPixel == pitch && w == _textureWidth) { + if (static_cast<int>(w) * _bytesPerPixel == pitch) { glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, _glFormat, _glType, buf); CHECK_GL_ERROR(); } else { diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp index beac2f6d3e..9a2efe3eec 100644 --- a/backends/graphics/opengl/opengl-graphics.cpp +++ b/backends/graphics/opengl/opengl-graphics.cpp @@ -136,6 +136,8 @@ int OpenGLGraphicsManager::getDefaultGraphicsMode() const { bool OpenGLGraphicsManager::setGraphicsMode(int mode) { assert(_transactionMode == kTransactionActive); + setScale(2); + if (_oldVideoMode.setup && _oldVideoMode.mode == mode) return true; @@ -166,11 +168,9 @@ void OpenGLGraphicsManager::resetGraphicsScale() { } #ifdef USE_RGB_COLOR - Graphics::PixelFormat OpenGLGraphicsManager::getScreenFormat() const { return _screenFormat; } - #endif void OpenGLGraphicsManager::initSize(uint width, uint height, const Graphics::PixelFormat *format) { @@ -308,7 +308,7 @@ int16 OpenGLGraphicsManager::getWidth() { void OpenGLGraphicsManager::setPalette(const byte *colors, uint start, uint num) { assert(colors); - + #ifdef USE_RGB_COLOR assert(_screenFormat.bytesPerPixel == 1); #endif @@ -324,7 +324,7 @@ void OpenGLGraphicsManager::setPalette(const byte *colors, uint start, uint num) void OpenGLGraphicsManager::grabPalette(byte *colors, uint start, uint num) { assert(colors); - + #ifdef USE_RGB_COLOR assert(_screenFormat.bytesPerPixel == 1); #endif @@ -341,9 +341,9 @@ void OpenGLGraphicsManager::copyRectToScreen(const byte *buf, int pitch, int x, // Copy buffer data to game screen internal buffer const byte *src = buf; - byte *dst = (byte *)_screenData.pixels + y * _screenData.pitch; + byte *dst = (byte *)_screenData.pixels + y * _screenData.pitch + x * _screenData.bytesPerPixel; for (int i = 0; i < h; i++) { - memcpy(dst + x * _screenData.bytesPerPixel, src, w * _screenData.bytesPerPixel); + memcpy(dst, src, w * _screenData.bytesPerPixel); src += pitch; dst += _screenData.pitch; } @@ -367,6 +367,7 @@ void OpenGLGraphicsManager::fillScreen(uint32 col) { if (_gameTexture == NULL) return; +#ifdef USE_RGB_COLOR if (_screenFormat.bytesPerPixel == 1) { memset(_screenData.pixels, col, _screenData.h * _screenData.pitch); } else if (_screenFormat.bytesPerPixel == 2) { @@ -392,7 +393,9 @@ void OpenGLGraphicsManager::fillScreen(uint32 col) { pixels[i] = col; } } - +#else + memset(_screenData.pixels, col, _screenData.h * _screenData.pitch); +#endif _screenNeedsRedraw = true; } @@ -558,7 +561,8 @@ void OpenGLGraphicsManager::setMouseCursor(const byte *buf, uint w, uint h, int #endif // Allocate space for cursor data - if (_cursorData.w != w || _cursorData.h != h) + if (_cursorData.w != w || _cursorData.h != h || + _cursorData.bytesPerPixel != _cursorFormat.bytesPerPixel) _cursorData.create(w, h, _cursorFormat.bytesPerPixel); // Save cursor data @@ -754,11 +758,17 @@ void OpenGLGraphicsManager::refreshOverlay() { void OpenGLGraphicsManager::refreshCursor() { _cursorNeedsRedraw = false; - if (_cursorFormat.bytesPerPixel == 1) { - // Create a temporary RGBA8888 surface - byte *surface = new byte[_cursorState.w * _cursorState.h * 4]; - memset(surface, 0, _cursorState.w * _cursorState.h * 4); + // Allocate a texture big enough for cursor + _cursorTexture->allocBuffer(_cursorState.w, _cursorState.h); + // Create a temporary RGBA8888 surface + byte *surface = new byte[_cursorState.w * _cursorState.h * 4]; + memset(surface, 0, _cursorState.w * _cursorState.h * 4); + + byte *dst = surface; + + // Convert the paletted cursor to RGBA8888 + if (_cursorFormat.bytesPerPixel == 1) { // Select palette byte *palette; if (_cursorPaletteDisabled) @@ -768,7 +778,6 @@ void OpenGLGraphicsManager::refreshCursor() { // Convert the paletted cursor to RGBA8888 const byte *src = (byte *)_cursorData.pixels; - byte *dst = surface; for (int i = 0; i < _cursorState.w * _cursorState.h; i++) { // Check for keycolor if (src[i] != _cursorKeyColor) { @@ -779,16 +788,42 @@ void OpenGLGraphicsManager::refreshCursor() { } dst += 4; } + } else { + const bool gotNoAlpha = (_cursorFormat.aLoss == 8); + + // Convert the RGB cursor to RGBA8888 + if (_cursorFormat.bytesPerPixel == 2) { + const uint16 *src = (uint16 *)_cursorData.pixels; + for (int i = 0; i < _cursorState.w * _cursorState.h; i++) { + // Check for keycolor + if (src[i] != _cursorKeyColor) { + _cursorFormat.colorToARGB(src[i], dst[3], dst[0], dst[1], dst[2]); + + if (gotNoAlpha) + dst[3] = 255; + } + dst += 4; + } + } else if (_cursorFormat.bytesPerPixel == 4) { + const uint32 *src = (uint32 *)_cursorData.pixels; + for (int i = 0; i < _cursorState.w * _cursorState.h; i++) { + // Check for keycolor + if (src[i] != _cursorKeyColor) { + _cursorFormat.colorToARGB(src[i], dst[3], dst[0], dst[1], dst[2]); + + if (gotNoAlpha) + dst[3] = 255; + } + dst += 4; + } + } + } - // Allocate a texture big enough for cursor - _cursorTexture->allocBuffer(_cursorState.w, _cursorState.h); - - // Update the texture with new cursor - _cursorTexture->updateBuffer(surface, _cursorState.w * 4, 0, 0, _cursorState.w, _cursorState.h); + // Update the texture with new cursor + _cursorTexture->updateBuffer(surface, _cursorState.w * 4, 0, 0, _cursorState.w, _cursorState.h); - // Free the temp surface - delete[] surface; - } + // Free the temp surface + delete[] surface; } void OpenGLGraphicsManager::refreshCursorScale() { @@ -811,7 +846,8 @@ void OpenGLGraphicsManager::refreshCursorScale() { } else { // Otherwise, scale the cursor for the overlay int targetScaleFactor = MIN(_cursorTargetScale, _videoMode.scaleFactor); - int actualFactor = screenScaleFactor - (targetScaleFactor - 1) * 10000; + // We limit the maximum scale to 3 here to avoid too big cursors, for large overlay resolutions + int actualFactor = MIN<uint>(3, screenScaleFactor - (targetScaleFactor - 1)) * 10000; _cursorState.rW = (int16)(_cursorState.w * actualFactor / 10000); _cursorState.rH = (int16)(_cursorState.h * actualFactor / 10000); _cursorState.rHotX = (int16)(_cursorState.hotX * actualFactor / 10000); @@ -873,6 +909,11 @@ void OpenGLGraphicsManager::getGLPixelFormat(Graphics::PixelFormat pixelFormat, intFormat = GL_RGBA; glFormat = GL_RGBA; gltype = GL_UNSIGNED_SHORT_5_5_5_1; + } else if (pixelFormat == Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)) { // RGB555 + bpp = 2; + intFormat = GL_RGB; + glFormat = GL_BGRA; + gltype = GL_UNSIGNED_SHORT_1_5_5_5_REV; } else if (pixelFormat == Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0)) { // RGBA4444 bpp = 2; intFormat = GL_RGBA; @@ -963,7 +1004,7 @@ void OpenGLGraphicsManager::internUpdateScreen() { refreshOverlay(); // Draw the overlay - _overlayTexture->drawTexture(_displayX, _displayY, _displayWidth, _displayHeight); + _overlayTexture->drawTexture(0, 0, _videoMode.overlayWidth, _videoMode.overlayHeight); } if (_cursorVisible) { @@ -1059,10 +1100,14 @@ void OpenGLGraphicsManager::initGL() { void OpenGLGraphicsManager::loadTextures() { #ifdef USE_RGB_COLOR - if (_transactionDetails.formatChanged && _gameTexture) + if (_transactionDetails.formatChanged && _gameTexture) { delete _gameTexture; + _gameTexture = 0; + } #endif + uint gameScreenBPP = 0; + if (!_gameTexture) { byte bpp; GLenum intformat; @@ -1073,6 +1118,7 @@ void OpenGLGraphicsManager::loadTextures() { #else getGLPixelFormat(Graphics::PixelFormat::createFormatCLUT8(), bpp, intformat, format, type); #endif + gameScreenBPP = bpp; _gameTexture = new GLTexture(bpp, intformat, format, type); } else _gameTexture->refresh(); @@ -1093,7 +1139,7 @@ void OpenGLGraphicsManager::loadTextures() { _cursorTexture = new GLTexture(4, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE); else _cursorTexture->refresh(); - + GLint filter = _videoMode.antialiasing ? GL_LINEAR : GL_NEAREST; _gameTexture->setFilter(filter); _overlayTexture->setFilter(filter); @@ -1104,21 +1150,38 @@ void OpenGLGraphicsManager::loadTextures() { _overlayTexture->allocBuffer(_videoMode.overlayWidth, _videoMode.overlayHeight); _cursorTexture->allocBuffer(_cursorState.w, _cursorState.h); - if (_transactionDetails.formatChanged || + if ( +#ifdef USE_RGB_COLOR + _transactionDetails.formatChanged || +#endif _oldVideoMode.screenWidth != _videoMode.screenWidth || _oldVideoMode.screenHeight != _videoMode.screenHeight) _screenData.create(_videoMode.screenWidth, _videoMode.screenHeight, - _screenFormat.bytesPerPixel); +#ifdef USE_RGB_COLOR + _screenFormat.bytesPerPixel +#else + 1 +#endif + ); + if (_oldVideoMode.overlayWidth != _videoMode.overlayWidth || _oldVideoMode.overlayHeight != _videoMode.overlayHeight) _overlayData.create(_videoMode.overlayWidth, _videoMode.overlayHeight, _overlayFormat.bytesPerPixel); - + _screenNeedsRedraw = true; _overlayNeedsRedraw = true; _cursorNeedsRedraw = true; + // We need to setup a proper unpack alignment value here, else we will + // get problems with the texture updates, in case the surface data is + // not properly aligned. + // For now we use the gcd of the game screen format and 2, since 2 is + // the BPP value for the overlay and the OSD. + if (gameScreenBPP) + glPixelStorei(GL_UNPACK_ALIGNMENT, Common::gcd<uint>(gameScreenBPP, 2)); + #ifdef USE_OSD if (!_osdTexture) _osdTexture = new GLTexture(2, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1); @@ -1166,32 +1229,20 @@ uint OpenGLGraphicsManager::getAspectRatio() { } void OpenGLGraphicsManager::adjustMousePosition(int16 &x, int16 &y) { - if (_videoMode.mode == OpenGL::GFX_NORMAL) { - if (_videoMode.hardwareWidth != _videoMode.overlayWidth) - x = x * _videoMode.overlayWidth / _videoMode.hardwareWidth; - if (_videoMode.hardwareHeight != _videoMode.overlayHeight) - y = y * _videoMode.overlayHeight / _videoMode.hardwareHeight; - - if (!_overlayVisible) { - x /= _videoMode.scaleFactor; - y /= _videoMode.scaleFactor; - } + if (_overlayVisible) + return; - } else { + if (_videoMode.mode == OpenGL::GFX_NORMAL) { + x /= _videoMode.scaleFactor; + y /= _videoMode.scaleFactor; + } else if (!_overlayVisible) { x -= _displayX; y -= _displayY; - if (_overlayVisible) { - if (_displayWidth != _videoMode.overlayWidth) - x = x * _videoMode.overlayWidth / _displayWidth; - if (_displayHeight != _videoMode.overlayHeight) - y = y * _videoMode.overlayHeight / _displayHeight; - } else { - if (_displayWidth != _videoMode.screenWidth) - x = x * _videoMode.screenWidth / _displayWidth; - if (_displayHeight != _videoMode.screenHeight) - y = y * _videoMode.screenHeight / _displayHeight; - } + if (_displayWidth != _videoMode.screenWidth) + x = x * _videoMode.screenWidth / _displayWidth; + if (_displayHeight != _videoMode.screenHeight) + y = y * _videoMode.screenHeight / _displayHeight; } } diff --git a/backends/graphics/openglsdl/openglsdl-graphics.cpp b/backends/graphics/openglsdl/openglsdl-graphics.cpp index c7ce0aa7de..cbc152a4a3 100644 --- a/backends/graphics/openglsdl/openglsdl-graphics.cpp +++ b/backends/graphics/openglsdl/openglsdl-graphics.cpp @@ -121,6 +121,7 @@ void OpenGLSdlGraphicsManager::detectSupportedFormats() { #endif Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), // RGB565 Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0), // RGB5551 + Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0), // RGB555 Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0), // RGBA4444 #ifndef USE_GLES Graphics::PixelFormat(2, 4, 4, 4, 4, 8, 4, 0, 12) // ARGB4444 @@ -344,13 +345,10 @@ bool OpenGLSdlGraphicsManager::loadGFXMode() { if (_aspectRatioCorrection) _videoMode.mode = OpenGL::GFX_4_3; - _videoMode.overlayWidth = _videoMode.screenWidth * _videoMode.scaleFactor; - _videoMode.overlayHeight = _videoMode.screenHeight * _videoMode.scaleFactor; - // If the screen was resized, do not change its size if (!_screenResized) { - _videoMode.hardwareWidth = _videoMode.overlayWidth; - _videoMode.hardwareHeight = _videoMode.overlayHeight; + _videoMode.overlayWidth = _videoMode.hardwareWidth = _videoMode.screenWidth * _videoMode.scaleFactor; + _videoMode.overlayHeight = _videoMode.hardwareHeight = _videoMode.screenHeight * _videoMode.scaleFactor; int screenAspectRatio = _videoMode.screenWidth * 10000 / _videoMode.screenHeight; int desiredAspectRatio = getAspectRatio(); @@ -365,6 +363,9 @@ bool OpenGLSdlGraphicsManager::loadGFXMode() { // the width is modified it can break the overlay. if (_videoMode.hardwareHeight > _videoMode.overlayHeight) _videoMode.overlayHeight = _videoMode.hardwareHeight; + } else { + _videoMode.overlayWidth = _videoMode.hardwareWidth; + _videoMode.overlayHeight = _videoMode.hardwareHeight; } _screenResized = false; @@ -376,11 +377,15 @@ bool OpenGLSdlGraphicsManager::loadGFXMode() { SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - if (_videoMode.fullscreen) + if (_videoMode.fullscreen) { if (!setupFullscreenMode()) // Failed setuping a fullscreen mode return false; + _videoMode.overlayWidth = _videoMode.hardwareWidth; + _videoMode.overlayHeight = _videoMode.hardwareHeight; + } + uint32 flags = SDL_OPENGL; if (_videoMode.fullscreen) diff --git a/backends/graphics/sdl/sdl-graphics.cpp b/backends/graphics/sdl/sdl-graphics.cpp index 09c4f39636..c0d93b3bf2 100644 --- a/backends/graphics/sdl/sdl-graphics.cpp +++ b/backends/graphics/sdl/sdl-graphics.cpp @@ -165,13 +165,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 - #ifdef USE_SDL_DEBUG_FOCUSRECT if (ConfMan.hasKey("use_sdl_debug_focusrect")) _enableFocusRectDebugCode = ConfMan.getBool("use_sdl_debug_focusrect"); @@ -1248,25 +1241,25 @@ void SdlGraphicsManager::copyRectToScreen(const byte *src, int pitch, int x, int error("SDL_LockSurface failed: %s", SDL_GetError()); #ifdef USE_RGB_COLOR - byte *dst = (byte *)_screen->pixels + y * _videoMode.screenWidth * _screenFormat.bytesPerPixel + x * _screenFormat.bytesPerPixel; - if (_videoMode.screenWidth == w && pitch == w * _screenFormat.bytesPerPixel) { - memcpy(dst, src, h*w*_screenFormat.bytesPerPixel); + byte *dst = (byte *)_screen->pixels + y * _screen->pitch + x * _screenFormat.bytesPerPixel; + if (_videoMode.screenWidth == w && pitch == _screen->pitch) { + memcpy(dst, src, h*pitch); } else { do { memcpy(dst, src, w * _screenFormat.bytesPerPixel); src += pitch; - dst += _videoMode.screenWidth * _screenFormat.bytesPerPixel; + dst += _screen->pitch; } while (--h); } #else - byte *dst = (byte *)_screen->pixels + y * _videoMode.screenWidth + x; - if (_videoMode.screenWidth == pitch && pitch == w) { + byte *dst = (byte *)_screen->pixels + y * _screen->pitch + x; + if (_screen->pitch == pitch && pitch == w) { memcpy(dst, src, h*w); } else { do { memcpy(dst, src, w); src += pitch; - dst += _videoMode.screenWidth; + dst += _screen->pitch; } while (--h); } #endif diff --git a/backends/graphics/wincesdl/wincesdl-graphics.cpp b/backends/graphics/wincesdl/wincesdl-graphics.cpp new file mode 100644 index 0000000000..37c6624560 --- /dev/null +++ b/backends/graphics/wincesdl/wincesdl-graphics.cpp @@ -0,0 +1,1639 @@ +/* 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..c8d683b158 --- /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 */ + diff --git a/backends/midi/alsa.cpp b/backends/midi/alsa.cpp index 953b088958..feed60eaef 100644 --- a/backends/midi/alsa.cpp +++ b/backends/midi/alsa.cpp @@ -44,7 +44,7 @@ #if SND_LIB_MAJOR >= 1 || SND_LIB_MINOR >= 6 #define snd_seq_flush_output(x) snd_seq_drain_output(x) -#define snd_seq_set_client_group(x,name) /*nop */ +#define snd_seq_set_client_group(x,name) /*nop */ #define my_snd_seq_open(seqp) snd_seq_open(seqp, "hw", SND_SEQ_OPEN_DUPLEX, 0) #else /* SND_SEQ_OPEN_OUT causes oops on early version of ALSA */ @@ -53,9 +53,8 @@ #define perm_ok(pinfo,bits) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits)) -static int check_permission(snd_seq_port_info_t *pinfo) -{ - if (perm_ok(pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE)) { +static int check_permission(snd_seq_port_info_t *pinfo) { + if (perm_ok(pinfo, SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE)) { if (!(snd_seq_port_info_get_capability(pinfo) & SND_SEQ_PORT_CAP_NO_EXPORT)) return 1; } @@ -68,7 +67,7 @@ static int check_permission(snd_seq_port_info_t *pinfo) #define ADDR_DELIM ".:" -class MidiDriver_ALSA:public MidiDriver_MPU401 { +class MidiDriver_ALSA : public MidiDriver_MPU401 { public: MidiDriver_ALSA(int client, int port); int open(); @@ -83,11 +82,12 @@ private: snd_seq_t *seq_handle; int seq_client, seq_port; int my_client, my_port; + // The volume controller value of the first MIDI channel + int8 _channel0Volume; }; MidiDriver_ALSA::MidiDriver_ALSA(int client, int port) - : _isOpen(false), seq_handle(0), seq_client(client), seq_port(port), my_client(0), my_port(0) -{ + : _isOpen(false), seq_handle(0), seq_client(client), seq_port(port), my_client(0), my_port(0), _channel0Volume(127) { memset(&ev, 0, sizeof(ev)); } @@ -114,7 +114,7 @@ int MidiDriver_ALSA::open() { // with those capabilities. my_port = snd_seq_create_simple_port(seq_handle, "SCUMMVM port 0", 0, - SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION); + SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION); if (my_port < 0) { snd_seq_close(seq_handle); @@ -208,24 +208,41 @@ void MidiDriver_ALSA::send(uint32 b) { case 0xB0: /* is it this simple ? Wow... */ snd_seq_ev_set_controller(&ev, chanID, midiCmd[1], midiCmd[2]); + + // We save the volume of the first MIDI channel here to utilize it in + // our workaround for broken USB-MIDI cables. + if (chanID == 0 && midiCmd[1] == 0x07) + _channel0Volume = midiCmd[2]; + send_event(1); break; case 0xC0: snd_seq_ev_set_pgmchange(&ev, chanID, midiCmd[1]); send_event(0); + + // Send a volume change command to work around a firmware bug in common + // USB-MIDI cables. If the first MIDI command in a USB packet is a + // Cx or Dx command, the second command in the packet is dropped + // somewhere. + send(0x07B0 | (_channel0Volume << 16)); break; case 0xD0: snd_seq_ev_set_chanpress(&ev, chanID, midiCmd[1]); send_event(1); + + // Send a volume change command to work around a firmware bug in common + // USB-MIDI cables. If the first MIDI command in a USB packet is a + // Cx or Dx command, the second command in the packet is dropped + // somewhere. + send(0x07B0 | (_channel0Volume << 16)); break; - case 0xE0:{ - // long theBend = ((((long)midiCmd[1] + (long)(midiCmd[2] << 7))) - 0x2000) / 4; - // snd_seq_ev_set_pitchbend(&ev, chanID, theBend); - long theBend = ((long)midiCmd[1] + (long)(midiCmd[2] << 7)) - 0x2000; - snd_seq_ev_set_pitchbend(&ev, chanID, theBend); - send_event(1); - } - break; + case 0xE0: { + // long theBend = ((((long)midiCmd[1] + (long)(midiCmd[2] << 7))) - 0x2000) / 4; + // snd_seq_ev_set_pitchbend(&ev, chanID, theBend); + long theBend = ((long)midiCmd[1] + (long)(midiCmd[2] << 7)) - 0x2000; + snd_seq_ev_set_pitchbend(&ev, chanID, theBend); + send_event(1); + } break; default: warning("Unknown MIDI Command: %08x", (int)b); @@ -280,6 +297,9 @@ typedef Common::List<AlsaDevice> AlsaDevices; AlsaDevice::AlsaDevice(Common::String name, MusicType mt, int client) : _name(name), _type(mt), _client(client) { + // Make sure we do not get any trailing spaces to avoid problems when + // storing the name in the configuration file. + _name.trim(); } Common::String AlsaDevice::getName() { diff --git a/backends/mixer/wincesdl/wincesdl-mixer.cpp b/backends/mixer/wincesdl/wincesdl-mixer.cpp new file mode 100644 index 0000000000..fb8a7d10c7 --- /dev/null +++ b/backends/mixer/wincesdl/wincesdl-mixer.cpp @@ -0,0 +1,183 @@ +/* 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$ + * + */ + +#ifdef _WIN32_WCE + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "common/config-manager.h" +#include "backends/platform/wince/wince-sdl.h" +#include "backends/mixer/wincesdl/wincesdl-mixer.h" +#include "common/system.h" + +#ifdef USE_VORBIS +#ifndef USE_TREMOR +#include <vorbis/vorbisfile.h> +#else +#include <tremor/ivorbisfile.h> +#endif +#endif + +#define SAMPLES_PER_SEC_OLD 11025 +#define SAMPLES_PER_SEC_NEW 22050 + +WINCESdlMixerManager::WINCESdlMixerManager() { + +} + +WINCESdlMixerManager::~WINCESdlMixerManager() { + +} + +void WINCESdlMixerManager::init() { + SDL_AudioSpec desired; + int thread_priority; + + uint32 sampleRate = compute_sample_rate(); + if (sampleRate == 0) + warning("OSystem_WINCE3::setupMixer called with sample rate 0 - audio will not work"); + else if (_mixer && _mixer->getOutputRate() == sampleRate) { + debug(1, "Skipping sound mixer re-init: samplerate is good"); + return; + } + + memset(&desired, 0, sizeof(desired)); + desired.freq = sampleRate; + desired.format = AUDIO_S16SYS; + desired.channels = 2; + desired.samples = 128; + desired.callback = private_sound_proc; + desired.userdata = this; + + // Create the mixer instance + if (_mixer == 0) + _mixer = new Audio::MixerImpl(g_system, sampleRate); + + // Add sound thread priority + if (!ConfMan.hasKey("sound_thread_priority")) + thread_priority = THREAD_PRIORITY_NORMAL; + else + thread_priority = ConfMan.getInt("sound_thread_priority"); + + desired.thread_priority = thread_priority; + + SDL_CloseAudio(); + if (SDL_OpenAudio(&desired, NULL) != 0) { + warning("Could not open audio device: %s", SDL_GetError()); + _mixer->setReady(false); + + } else { + debug(1, "Sound opened OK, mixing at %d Hz", sampleRate); + + // Re-create mixer to match the output rate + int vol1 = _mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType); + int vol2 = _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType); + int vol3 = _mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType); + int vol4 = _mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType); + delete _mixer; + _mixer = new Audio::MixerImpl(g_system, sampleRate); + _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, vol1); + _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, vol2); + _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, vol3); + _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, vol4); + _mixer->setReady(true); + SDL_PauseAudio(0); + } +} + +void WINCESdlMixerManager::private_sound_proc(void *param, byte *buf, int len) { + WINCESdlMixerManager *this_ = (WINCESdlMixerManager *)param; + assert(this_); + + if (this_->_mixer) + this_->_mixer->mixCallback(buf, len); + if (!OSystem_WINCE3::_soundMaster) + memset(buf, 0, len); +} + +uint32 WINCESdlMixerManager::compute_sample_rate() { + uint32 sampleRate; + + // Force at least medium quality FM synthesis for FOTAQ + Common::String gameid(ConfMan.get("gameid")); + if (gameid == "queen") { + if (!((ConfMan.hasKey("FM_high_quality") && ConfMan.getBool("FM_high_quality")) || + (ConfMan.hasKey("FM_medium_quality") && ConfMan.getBool("FM_medium_quality")))) { + ConfMan.setBool("FM_medium_quality", true); + ConfMan.flushToDisk(); + } + } + // See if the output frequency is forced by the game + if (gameid == "ft" || gameid == "dig" || gameid == "comi" || gameid == "queen" || gameid == "sword" || gameid == "agi") + sampleRate = SAMPLES_PER_SEC_NEW; + else { + if (ConfMan.hasKey("high_sample_rate") && ConfMan.getBool("high_sample_rate")) + sampleRate = SAMPLES_PER_SEC_NEW; + else + sampleRate = SAMPLES_PER_SEC_OLD; + } + +#ifdef USE_VORBIS + // Modify the sample rate on the fly if OGG is involved + if (sampleRate == SAMPLES_PER_SEC_OLD) + if (checkOggHighSampleRate()) + sampleRate = SAMPLES_PER_SEC_NEW; +#endif + + return sampleRate; +} + +#ifdef USE_VORBIS +bool WINCESdlMixerManager::checkOggHighSampleRate() { + char trackFile[255]; + FILE *testFile; + OggVorbis_File *test_ov_file = new OggVorbis_File; + + // FIXME: The following sprintf assumes that "path" is always + // terminated by a path separator. This is *not* true in general. + // This code really should check for the path separator, or even + // better, use the FSNode API. + sprintf(trackFile, "%sTrack1.ogg", ConfMan.get("path").c_str()); + // Check if we have an OGG audio track + testFile = fopen(trackFile, "rb"); + if (testFile) { + if (!ov_open(testFile, test_ov_file, NULL, 0)) { + bool highSampleRate = (ov_info(test_ov_file, -1)->rate == 22050); + ov_clear(test_ov_file); + delete test_ov_file; + return highSampleRate; + } + } + + // Do not test for OGG samples - too big and too slow anyway :) + + delete test_ov_file; + return false; +} +#endif + +#endif + diff --git a/backends/mixer/wincesdl/wincesdl-mixer.h b/backends/mixer/wincesdl/wincesdl-mixer.h new file mode 100644 index 0000000000..6c2f1efeee --- /dev/null +++ b/backends/mixer/wincesdl/wincesdl-mixer.h @@ -0,0 +1,53 @@ +/* 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_MIXER_WINCE_SDL_H +#define BACKENDS_MIXER_WINCE_SDL_H + +#include "backends/mixer/sdl/sdl-mixer.h" + +/** + * SDL mixer manager for WinCE + */ +class WINCESdlMixerManager : public SdlMixerManager { +public: + WINCESdlMixerManager(); + virtual ~WINCESdlMixerManager(); + + virtual void init(); + +private: + +#ifdef USE_VORBIS + bool checkOggHighSampleRate(); +#endif + + static void private_sound_proc(void *param, byte *buf, int len); + uint32 compute_sample_rate(); + +}; + +#endif + diff --git a/backends/module.mk b/backends/module.mk index 5a8a63c2a2..484f804ee0 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -12,6 +12,7 @@ MODULE_OBJS := \ events/samsungtvsdl/samsungtvsdl-events.o \ events/sdl/sdl-events.o \ events/symbiansdl/symbiansdl-events.o \ + events/wincesdl/wincesdl-events.o \ fs/abstract-fs.o \ fs/stdiostream.o \ fs/amigaos4/amigaos4-fs-factory.o \ @@ -27,6 +28,7 @@ MODULE_OBJS := \ graphics/openglsdl/openglsdl-graphics.o \ graphics/sdl/sdl-graphics.o \ graphics/symbiansdl/symbiansdl-graphics.o \ + graphics/wincesdl/wincesdl-graphics.o \ keymapper/action.o \ keymapper/keymap.o \ keymapper/keymapper.o \ @@ -44,6 +46,7 @@ MODULE_OBJS := \ mixer/doublebuffersdl/doublebuffersdl-mixer.o \ mixer/sdl/sdl-mixer.o \ mixer/symbiansdl/symbiansdl-mixer.o \ + mixer/wincesdl/wincesdl-mixer.o \ mutex/sdl/sdl-mutex.o \ plugins/elf/elf-loader.o \ plugins/elf/mips-loader.o \ diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index c49745f8bd..4e1373a1b1 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -25,22 +25,11 @@ #if defined(__ANDROID__) -#include "backends/base-backend.h" -#include "base/main.h" -#include "graphics/surface.h" - -#include "backends/platform/android/android.h" -#include "backends/platform/android/video.h" - -#include <jni.h> - -#include <string.h> -#include <unistd.h> -#include <pthread.h> #include <sys/time.h> +#include <sys/resource.h> #include <time.h> +#include <unistd.h> -#include "common/archive.h" #include "common/util.h" #include "common/rect.h" #include "common/queue.h" @@ -48,14 +37,12 @@ #include "common/events.h" #include "common/config-manager.h" -#include "backends/fs/posix/posix-fs-factory.h" #include "backends/keymapper/keymapper.h" #include "backends/saves/default/default-saves.h" #include "backends/timer/default/default-timer.h" -#include "backends/plugins/posix/posix-provider.h" -#include "audio/mixer_intern.h" -#include "backends/platform/android/asset-archive.h" +#include "backends/platform/android/jni.h" +#include "backends/platform/android/android.h" const char *android_log_tag = "ScummVM"; @@ -68,7 +55,8 @@ extern "C" { expr, file, line); } - void __assert2(const char *file, int line, const char *func, const char *expr) { + void __assert2(const char *file, int line, const char *func, + const char *expr) { __android_log_assert(expr, android_log_tag, "Assertion failure: '%s' in %s:%d (%s)", expr, file, line, func); @@ -106,235 +94,24 @@ void checkGlError(const char *expr, const char *file, int line) { } #endif -static JavaVM *cached_jvm; -static jfieldID FID_Event_type; -static jfieldID FID_Event_synthetic; -static jfieldID FID_Event_kbd_keycode; -static jfieldID FID_Event_kbd_ascii; -static jfieldID FID_Event_kbd_flags; -static jfieldID FID_Event_mouse_x; -static jfieldID FID_Event_mouse_y; -static jfieldID FID_Event_mouse_relative; -static jfieldID FID_ScummVM_nativeScummVM; -static jmethodID MID_Object_wait; - -JNIEnv *JNU_GetEnv() { - JNIEnv *env = 0; - - jint res = cached_jvm->GetEnv((void **)&env, JNI_VERSION_1_2); - - if (res != JNI_OK) { - LOGE("GetEnv() failed: %d", res); - abort(); - } - - return env; -} - -static void JNU_ThrowByName(JNIEnv *env, const char *name, const char *msg) { - jclass cls = env->FindClass(name); - - // if cls is 0, an exception has already been thrown - if (cls != 0) - env->ThrowNew(cls, msg); - - env->DeleteLocalRef(cls); -} - -// floating point. use sparingly -template <class T> -static inline T scalef(T in, float numerator, float denominator) { - return static_cast<float>(in) * numerator / denominator; -} - -static inline GLfixed xdiv(int numerator, int denominator) { - assert(numerator < (1 << 16)); - return (numerator << 16) / denominator; -} - -#ifdef DYNAMIC_MODULES -class AndroidPluginProvider : public POSIXPluginProvider { -protected: - virtual void addCustomDirectories(Common::FSList &dirs) const; -}; -#endif - -class OSystem_Android : public BaseBackend, public PaletteManager { -private: - // back pointer to (java) peer instance - jobject _back_ptr; - - jmethodID MID_displayMessageOnOSD; - jmethodID MID_setWindowCaption; - jmethodID MID_initBackend; - jmethodID MID_audioSampleRate; - jmethodID MID_showVirtualKeyboard; - jmethodID MID_getSysArchives; - jmethodID MID_getPluginDirectories; - jmethodID MID_setupScummVMSurface; - jmethodID MID_destroyScummVMSurface; - jmethodID MID_swapBuffers; - - int _screen_changeid; - int _egl_surface_width; - int _egl_surface_height; - - bool _force_redraw; - - // Game layer - GLESPaletteTexture *_game_texture; - int _shake_offset; - Common::Rect _focus_rect; - - // Overlay layer - GLES4444Texture *_overlay_texture; - bool _show_overlay; - - // Mouse layer - GLESPaletteATexture *_mouse_texture; - Common::Point _mouse_hotspot; - int _mouse_targetscale; - bool _show_mouse; - bool _use_mouse_palette; - - Common::Queue<Common::Event> _event_queue; - MutexRef _event_queue_lock; - - bool _timer_thread_exit; - pthread_t _timer_thread; - static void *timerThreadFunc(void *arg); - - bool _enable_zoning; - bool _virtkeybd_on; - - Common::SaveFileManager *_savefile; - Audio::MixerImpl *_mixer; - Common::TimerManager *_timer; - FilesystemFactory *_fsFactory; - Common::Archive *_asset_archive; - timeval _startTime; - - void setupScummVMSurface(); - void destroyScummVMSurface(); - void setupKeymapper(); - void _setCursorPalette(const byte *colors, uint start, uint num); - -public: - OSystem_Android(jobject am); - virtual ~OSystem_Android(); - bool initJavaHooks(JNIEnv *env, jobject self); - - static OSystem_Android *fromJavaObject(JNIEnv *env, jobject obj); - virtual void initBackend(); - void addPluginDirectories(Common::FSList &dirs) const; - void enableZoning(bool enable) { _enable_zoning = enable; } - void setSurfaceSize(int width, int height) { - _egl_surface_width = width; - _egl_surface_height = height; - } - - virtual bool hasFeature(Feature f); - virtual void setFeatureState(Feature f, bool enable); - virtual bool getFeatureState(Feature f); - virtual const GraphicsMode *getSupportedGraphicsModes() const; - virtual int getDefaultGraphicsMode() const; - bool setGraphicsMode(const char *name); - virtual bool setGraphicsMode(int mode); - virtual int getGraphicsMode() const; - virtual void initSize(uint width, uint height, - const Graphics::PixelFormat *format); - - virtual int getScreenChangeID() const { - return _screen_changeid; - } - - virtual int16 getHeight(); - virtual int16 getWidth(); - - virtual PaletteManager *getPaletteManager() { - return this; - } - -protected: - // PaletteManager API - virtual void setPalette(const byte *colors, uint start, uint num); - virtual void grabPalette(byte *colors, uint start, uint num); - -public: - virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h); - virtual void updateScreen(); - virtual Graphics::Surface *lockScreen(); - virtual void unlockScreen(); - virtual void setShakePos(int shakeOffset); - virtual void fillScreen(uint32 col); - virtual void setFocusRectangle(const Common::Rect& rect); - virtual void clearFocusRectangle(); - - virtual void showOverlay(); - virtual void hideOverlay(); - virtual void clearOverlay(); - virtual void grabOverlay(OverlayColor *buf, int pitch); - virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h); - virtual int16 getOverlayHeight(); - virtual int16 getOverlayWidth(); - - // RGBA 4444 - virtual Graphics::PixelFormat getOverlayFormat() const { - Graphics::PixelFormat format; - - format.bytesPerPixel = 2; - format.rLoss = 8 - 4; - format.gLoss = 8 - 4; - format.bLoss = 8 - 4; - format.aLoss = 8 - 4; - format.rShift = 3 * 4; - format.gShift = 2 * 4; - format.bShift = 1 * 4; - format.aShift = 0 * 4; - - return format; - } - - virtual bool showMouse(bool visible); - - virtual void warpMouse(int x, int y); - virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format); - virtual void setCursorPalette(const byte *colors, uint start, uint num); - virtual void disableCursorPalette(bool disable); - - virtual bool pollEvent(Common::Event &event); - void pushEvent(const Common::Event& event); - virtual uint32 getMillis(); - virtual void delayMillis(uint msecs); - - virtual MutexRef createMutex(void); - virtual void lockMutex(MutexRef mutex); - virtual void unlockMutex(MutexRef mutex); - virtual void deleteMutex(MutexRef mutex); - - virtual void quit(); - - virtual void setWindowCaption(const char *caption); - virtual void displayMessageOnOSD(const char *msg); - virtual void showVirtualKeyboard(bool enable); - - virtual Common::SaveFileManager *getSavefileManager(); - virtual Audio::Mixer *getMixer(); - virtual void getTimeAndDate(TimeDate &t) const; - virtual Common::TimerManager *getTimerManager(); - virtual FilesystemFactory *getFilesystemFactory(); - virtual void logMessage(LogMessageType::Type type, const char *message); - virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0); -}; - -OSystem_Android::OSystem_Android(jobject am) : - _back_ptr(0), +OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : + _audio_sample_rate(audio_sample_rate), + _audio_buffer_size(audio_buffer_size), _screen_changeid(0), + _egl_surface_width(0), + _egl_surface_height(0), _force_redraw(false), _game_texture(0), _overlay_texture(0), _mouse_texture(0), + _mouse_texture_palette(0), + _mouse_texture_rgb(0), + _mouse_hotspot(), + _mouse_keycolor(0), _use_mouse_palette(false), + _fullscreen(false), + _graphicsMode(0), + _ar_correction(false), _show_mouse(false), _show_overlay(false), _enable_zoning(false), @@ -342,876 +119,288 @@ OSystem_Android::OSystem_Android(jobject am) : _mixer(0), _timer(0), _fsFactory(new POSIXFilesystemFactory()), - _asset_archive(new AndroidAssetArchive(am)), _shake_offset(0), - _event_queue_lock(createMutex()) { + _event_queue_lock(createMutex()), + _touch_pt_down(), + _touch_pt_dt(), + _eventScaleX(100), + _eventScaleY(100), + // TODO put these values in some option dlg? + _touchpad_mode(true), + _touchpad_scale(50), + _dpad_scale(4), + _trackball_scale(2) { } OSystem_Android::~OSystem_Android() { ENTER(); - delete _game_texture; - delete _overlay_texture; - delete _mouse_texture; - - destroyScummVMSurface(); - - JNIEnv *env = JNU_GetEnv(); - //env->DeleteWeakGlobalRef(_back_ptr); - env->DeleteGlobalRef(_back_ptr); - delete _savefile; - delete _mixer; delete _timer; + delete _mixer; delete _fsFactory; - delete _asset_archive; deleteMutex(_event_queue_lock); } -OSystem_Android *OSystem_Android::fromJavaObject(JNIEnv *env, jobject obj) { - jlong peer = env->GetLongField(obj, FID_ScummVM_nativeScummVM); - return (OSystem_Android *)peer; -} - -bool OSystem_Android::initJavaHooks(JNIEnv *env, jobject self) { - // weak global ref to allow class to be unloaded - // ... except dalvik doesn't implement NewWeakGlobalRef (yet) - //_back_ptr = env->NewWeakGlobalRef(self); - _back_ptr = env->NewGlobalRef(self); - - jclass cls = env->GetObjectClass(_back_ptr); - -#define FIND_METHOD(name, signature) do { \ - MID_ ## name = env->GetMethodID(cls, #name, signature); \ - if (MID_ ## name == 0) \ - return false; \ - } while (0) - - FIND_METHOD(setWindowCaption, "(Ljava/lang/String;)V"); - FIND_METHOD(displayMessageOnOSD, "(Ljava/lang/String;)V"); - FIND_METHOD(initBackend, "()V"); - FIND_METHOD(audioSampleRate, "()I"); - FIND_METHOD(showVirtualKeyboard, "(Z)V"); - FIND_METHOD(getSysArchives, "()[Ljava/lang/String;"); - FIND_METHOD(getPluginDirectories, "()[Ljava/lang/String;"); - FIND_METHOD(setupScummVMSurface, "()V"); - FIND_METHOD(destroyScummVMSurface, "()V"); - FIND_METHOD(swapBuffers, "()Z"); - -#undef FIND_METHOD - - return true; -} - -static void ScummVM_create(JNIEnv *env, jobject self, jobject am) { - OSystem_Android *cpp_obj = new OSystem_Android(am); - - // Exception already thrown by initJavaHooks? - if (!cpp_obj->initJavaHooks(env, self)) - return; - - env->SetLongField(self, FID_ScummVM_nativeScummVM, (jlong)cpp_obj); - -#ifdef DYNAMIC_MODULES - PluginManager::instance().addPluginProvider(new AndroidPluginProvider()); -#endif -} - -static void ScummVM_nativeDestroy(JNIEnv *env, jobject self) { - OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self); - delete cpp_obj; -} - -static void ScummVM_audioMixCallback(JNIEnv *env, jobject self, - jbyteArray jbuf) { - OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self); - jsize len = env->GetArrayLength(jbuf); - jbyte *buf = env->GetByteArrayElements(jbuf, 0); - - if (buf == 0) { - warning("Unable to get Java audio byte array. Skipping"); - return; - } - - Audio::MixerImpl *mixer = - static_cast<Audio::MixerImpl *>(cpp_obj->getMixer()); - assert(mixer); - mixer->mixCallback(reinterpret_cast<byte *>(buf), len); - - env->ReleaseByteArrayElements(jbuf, buf, 0); -} - -static void ScummVM_setConfManInt(JNIEnv *env, jclass cls, - jstring key_obj, jint value) { - ENTER("%p, %d", key_obj, (int)value); - - const char *key = env->GetStringUTFChars(key_obj, 0); - - if (key == 0) - return; - - ConfMan.setInt(key, value); - - env->ReleaseStringUTFChars(key_obj, key); -} - -static void ScummVM_setConfManString(JNIEnv *env, jclass cls, jstring key_obj, - jstring value_obj) { - ENTER("%p, %p", key_obj, value_obj); - - const char *key = env->GetStringUTFChars(key_obj, 0); - - if (key == 0) - return; - - const char *value = env->GetStringUTFChars(value_obj, 0); - - if (value == 0) { - env->ReleaseStringUTFChars(key_obj, key); - return; - } - - ConfMan.set(key, value); - - env->ReleaseStringUTFChars(value_obj, value); - env->ReleaseStringUTFChars(key_obj, key); -} - void *OSystem_Android::timerThreadFunc(void *arg) { OSystem_Android *system = (OSystem_Android *)arg; DefaultTimerManager *timer = (DefaultTimerManager *)(system->_timer); - JNIEnv *env = 0; - jint res = cached_jvm->AttachCurrentThread(&env, 0); + // renice this thread to boost the audio thread + if (setpriority(PRIO_PROCESS, 0, 19) < 0) + LOGW("couldn't renice the timer thread"); - if (res != JNI_OK) { - LOGE("AttachCurrentThread() failed: %d", res); - abort(); - } + JNI::attachThread(); struct timespec tv; tv.tv_sec = 0; tv.tv_nsec = 100 * 1000 * 1000; // 100ms while (!system->_timer_thread_exit) { + if (JNI::pause) { + LOGD("timer thread going to sleep"); + sem_wait(&JNI::pause_sem); + LOGD("timer thread woke up"); + } + timer->handler(); nanosleep(&tv, 0); } - res = cached_jvm->DetachCurrentThread(); - - if (res != JNI_OK) { - LOGE("DetachCurrentThread() failed: %d", res); - abort(); - } + JNI::detachThread(); return 0; } -void OSystem_Android::initBackend() { - ENTER(); - - JNIEnv *env = JNU_GetEnv(); - - ConfMan.setInt("autosave_period", 0); - ConfMan.setInt("FM_medium_quality", true); - - // must happen before creating TimerManager to avoid race in - // creating EventManager - setupKeymapper(); - - // BUG: "transient" ConfMan settings get nuked by the options - // screen. Passing the savepath in this way makes it stick - // (via ConfMan.registerDefault) - _savefile = new DefaultSaveFileManager(ConfMan.get("savepath")); - _timer = new DefaultTimerManager(); - - gettimeofday(&_startTime, 0); - - jint sample_rate = env->CallIntMethod(_back_ptr, MID_audioSampleRate); - if (env->ExceptionCheck()) { - warning("Error finding audio sample rate - assuming 11025HZ"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - - sample_rate = 11025; - } - - _mixer = new Audio::MixerImpl(this, sample_rate); - _mixer->setReady(true); - - env->CallVoidMethod(_back_ptr, MID_initBackend); +void *OSystem_Android::audioThreadFunc(void *arg) { + JNI::attachThread(); - if (env->ExceptionCheck()) { - error("Error in Java initBackend"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } - - _timer_thread_exit = false; - pthread_create(&_timer_thread, 0, timerThreadFunc, this); + OSystem_Android *system = (OSystem_Android *)arg; + Audio::MixerImpl *mixer = system->_mixer; - OSystem::initBackend(); + uint buf_size = system->_audio_buffer_size; - setupScummVMSurface(); -} + JNIEnv *env = JNI::getEnv(); -void OSystem_Android::addPluginDirectories(Common::FSList &dirs) const { - ENTER(); + jbyteArray bufa = env->NewByteArray(buf_size); - JNIEnv *env = JNU_GetEnv(); + bool paused = true; - jobjectArray array = - (jobjectArray)env->CallObjectMethod(_back_ptr, MID_getPluginDirectories); - if (env->ExceptionCheck()) { - warning("Error finding plugin directories"); + byte *buf; + int offset, left, written; + int samples, i; - env->ExceptionDescribe(); - env->ExceptionClear(); + struct timespec tv_delay; + tv_delay.tv_sec = 0; + tv_delay.tv_nsec = 20 * 1000 * 1000; - return; - } + uint msecs_full = buf_size * 1000 / (mixer->getOutputRate() * 2 * 2); - jsize size = env->GetArrayLength(array); - for (jsize i = 0; i < size; ++i) { - jstring path_obj = (jstring)env->GetObjectArrayElement(array, i); + struct timespec tv_full; + tv_full.tv_sec = 0; + tv_full.tv_nsec = msecs_full * 1000 * 1000; - if (path_obj == 0) - continue; + bool silence; + uint silence_count = 33; - const char *path = env->GetStringUTFChars(path_obj, 0); - if (path == 0) { - warning("Error getting string characters from plugin directory"); + while (!system->_audio_thread_exit) { + if (JNI::pause) { + JNI::setAudioStop(); - env->ExceptionClear(); - env->DeleteLocalRef(path_obj); + paused = true; + silence_count = 33; - continue; + LOGD("audio thread going to sleep"); + sem_wait(&JNI::pause_sem); + LOGD("audio thread woke up"); } - dirs.push_back(Common::FSNode(path)); - - env->ReleaseStringUTFChars(path_obj, path); - env->DeleteLocalRef(path_obj); - } -} - -bool OSystem_Android::hasFeature(Feature f) { - return (f == kFeatureCursorHasPalette || - f == kFeatureVirtualKeyboard || - f == kFeatureOverlaySupportsAlpha); -} - -void OSystem_Android::setFeatureState(Feature f, bool enable) { - ENTER("%d, %d", f, enable); - - switch (f) { - case kFeatureVirtualKeyboard: - _virtkeybd_on = enable; - showVirtualKeyboard(enable); - break; - default: - break; - } -} - -bool OSystem_Android::getFeatureState(Feature f) { - switch (f) { - case kFeatureVirtualKeyboard: - return _virtkeybd_on; - default: - return false; - } -} - -const OSystem::GraphicsMode *OSystem_Android::getSupportedGraphicsModes() const { - static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { - { "default", "Default", 1 }, - { 0, 0, 0 }, - }; - - return s_supportedGraphicsModes; -} - - -int OSystem_Android::getDefaultGraphicsMode() const { - return 1; -} - -bool OSystem_Android::setGraphicsMode(const char *mode) { - ENTER("%s", mode); - return true; -} - -bool OSystem_Android::setGraphicsMode(int mode) { - ENTER("%d", mode); - return true; -} - -int OSystem_Android::getGraphicsMode() const { - return 1; -} - -void OSystem_Android::setupScummVMSurface() { - ENTER(); - - JNIEnv *env = JNU_GetEnv(); - env->CallVoidMethod(_back_ptr, MID_setupScummVMSurface); - - if (env->ExceptionCheck()) - return; - - // EGL set up with a new surface. Initialise OpenGLES context. - GLESTexture::initGLExtensions(); - - // Turn off anything that looks like 3D ;) - GLCALL(glDisable(GL_CULL_FACE)); - GLCALL(glDisable(GL_DEPTH_TEST)); - GLCALL(glDisable(GL_LIGHTING)); - GLCALL(glDisable(GL_FOG)); - GLCALL(glDisable(GL_DITHER)); - - GLCALL(glShadeModel(GL_FLAT)); - GLCALL(glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST)); - - GLCALL(glEnable(GL_BLEND)); - GLCALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - - GLCALL(glEnableClientState(GL_VERTEX_ARRAY)); - GLCALL(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); - - GLCALL(glEnable(GL_TEXTURE_2D)); - - if (!_game_texture) - _game_texture = new GLESPaletteTexture(); - else - _game_texture->reinitGL(); - - if (!_overlay_texture) - _overlay_texture = new GLES4444Texture(); - else - _overlay_texture->reinitGL(); - - if (!_mouse_texture) - _mouse_texture = new GLESPaletteATexture(); - else - _mouse_texture->reinitGL(); - - GLCALL(glViewport(0, 0, _egl_surface_width, _egl_surface_height)); - - GLCALL(glMatrixMode(GL_PROJECTION)); - GLCALL(glLoadIdentity()); - GLCALL(glOrthof(0, _egl_surface_width, _egl_surface_height, 0, -1, 1)); - GLCALL(glMatrixMode(GL_MODELVIEW)); - GLCALL(glLoadIdentity()); - - clearFocusRectangle(); -} - -void OSystem_Android::destroyScummVMSurface() { - JNIEnv *env = JNU_GetEnv(); - env->CallVoidMethod(_back_ptr, MID_destroyScummVMSurface); - // Can't use OpenGLES functions after this -} - -void OSystem_Android::initSize(uint width, uint height, - const Graphics::PixelFormat *format) { - ENTER("%d, %d, %p", width, height, format); - - _game_texture->allocBuffer(width, height); - - // Cap at 320x200 or the ScummVM themes abort :/ - GLuint overlay_width = MIN(_egl_surface_width, 320); - GLuint overlay_height = MIN(_egl_surface_height, 200); - _overlay_texture->allocBuffer(overlay_width, overlay_height); - - // Don't know mouse size yet - it gets reallocated in - // setMouseCursor. We need the palette allocated before - // setMouseCursor however, so just take a guess at the desired - // size (it's small). - _mouse_texture->allocBuffer(20, 20); -} - -int16 OSystem_Android::getHeight() { - return _game_texture->height(); -} - -int16 OSystem_Android::getWidth() { - return _game_texture->width(); -} - -void OSystem_Android::setPalette(const byte *colors, uint start, uint num) { - ENTER("%p, %u, %u", colors, start, num); + buf = (byte *)env->GetPrimitiveArrayCritical(bufa, 0); + assert(buf); - if (!_use_mouse_palette) - _setCursorPalette(colors, start, num); + samples = mixer->mixCallback(buf, buf_size); - memcpy(_game_texture->palette() + start * 3, colors, num * 3); -} - -void OSystem_Android::grabPalette(byte *colors, uint start, uint num) { - ENTER("%p, %u, %u", colors, start, num); - memcpy(colors, _game_texture->palette_const() + start * 3, num * 3); -} - -void OSystem_Android::copyRectToScreen(const byte *buf, int pitch, - int x, int y, int w, int h) { - ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h); - - _game_texture->updateBuffer(x, y, w, h, buf, pitch); -} - -void OSystem_Android::updateScreen() { - //ENTER(); - - if (!_force_redraw && - !_game_texture->dirty() && - !_overlay_texture->dirty() && - !_mouse_texture->dirty()) - return; - - _force_redraw = false; - - GLCALL(glPushMatrix()); - - if (_shake_offset != 0 || - (!_focus_rect.isEmpty() && - !Common::Rect(_game_texture->width(), - _game_texture->height()).contains(_focus_rect))) { - // These are the only cases where _game_texture doesn't - // cover the entire screen. - GLCALL(glClearColorx(0, 0, 0, 1 << 16)); - GLCALL(glClear(GL_COLOR_BUFFER_BIT)); - - // Move everything up by _shake_offset (game) pixels - GLCALL(glTranslatex(0, -_shake_offset << 16, 0)); - } - - if (_focus_rect.isEmpty()) { - _game_texture->drawTexture(0, 0, - _egl_surface_width, _egl_surface_height); - } else { - GLCALL(glPushMatrix()); - GLCALL(glScalex(xdiv(_egl_surface_width, _focus_rect.width()), - xdiv(_egl_surface_height, _focus_rect.height()), - 1 << 16)); - GLCALL(glTranslatex(-_focus_rect.left << 16, - -_focus_rect.top << 16, 0)); - GLCALL(glScalex(xdiv(_game_texture->width(), _egl_surface_width), - xdiv(_game_texture->height(), _egl_surface_height), - 1 << 16)); - - _game_texture->drawTexture(0, 0, - _egl_surface_width, _egl_surface_height); - GLCALL(glPopMatrix()); - } - - int cs = _mouse_targetscale; - - if (_show_overlay) { - // ugly, but the modern theme sets a wacko factor, only god knows why - cs = 1; - - GLCALL(_overlay_texture->drawTexture(0, 0, - _egl_surface_width, - _egl_surface_height)); - } - - if (_show_mouse) { - GLCALL(glPushMatrix()); + silence = samples < 1; - // Scale up ScummVM -> OpenGL (pixel) coordinates - int texwidth, texheight; + // looks stupid, and it is, but currently there's no way to detect + // silence-only buffers from the mixer + if (!silence) { + silence = true; - if (_show_overlay) { - texwidth = getOverlayWidth(); - texheight = getOverlayHeight(); - } else { - texwidth = getWidth(); - texheight = getHeight(); + for (i = 0; i < samples; i += 2) + // SID streams constant crap + if (READ_UINT16(buf + i) > 32) { + silence = false; + break; + } } - GLCALL(glScalex(xdiv(_egl_surface_width, texwidth), - xdiv(_egl_surface_height, texheight), - 1 << 16)); - - GLCALL(glTranslatex((-_mouse_hotspot.x * cs) << 16, - (-_mouse_hotspot.y * cs) << 16, - 0)); - - // Note the extra half texel to position the mouse in - // the middle of the x,y square: - const Common::Point& mouse = getEventManager()->getMousePos(); - GLCALL(glTranslatex((mouse.x << 16) | 1 << 15, - (mouse.y << 16) | 1 << 15, 0)); - - GLCALL(glScalex(cs << 16, cs << 16, 1 << 16)); - - _mouse_texture->drawTexture(); + env->ReleasePrimitiveArrayCritical(bufa, buf, 0); - GLCALL(glPopMatrix()); - } - - GLCALL(glPopMatrix()); + if (silence) { + if (!paused) + silence_count++; - JNIEnv *env = JNU_GetEnv(); - if (!env->CallBooleanMethod(_back_ptr, MID_swapBuffers)) { - // Context lost -> need to reinit GL - destroyScummVMSurface(); - setupScummVMSurface(); - } -} + // only pause after a while to prevent toggle mania + if (silence_count > 32) { + if (!paused) { + LOGD("AudioTrack pause"); -Graphics::Surface *OSystem_Android::lockScreen() { - ENTER(); + JNI::setAudioPause(); + paused = true; + } - Graphics::Surface *surface = _game_texture->surface(); - assert(surface->pixels); + nanosleep(&tv_full, 0); - return surface; -} + continue; + } + } -void OSystem_Android::unlockScreen() { - ENTER(); + if (paused) { + LOGD("AudioTrack play"); - assert(_game_texture->dirty()); -} + JNI::setAudioPlay(); + paused = false; -void OSystem_Android::setShakePos(int shake_offset) { - ENTER("%d", shake_offset); + silence_count = 0; + } - if (_shake_offset != shake_offset) { - _shake_offset = shake_offset; - _force_redraw = true; - } -} + offset = 0; + left = buf_size; + written = 0; -void OSystem_Android::fillScreen(uint32 col) { - ENTER("%u", col); + while (left > 0) { + written = JNI::writeAudio(env, bufa, offset, left); - assert(col < 256); - _game_texture->fillBuffer(col); -} + if (written < 0) { + LOGE("AudioTrack error: %d", written); + break; + } -void OSystem_Android::setFocusRectangle(const Common::Rect& rect) { - ENTER("%d, %d, %d, %d", rect.left, rect.top, rect.right, rect.bottom); + // buffer full + if (written < left) + nanosleep(&tv_delay, 0); - if (_enable_zoning) { - _focus_rect = rect; - _force_redraw = true; - } -} + offset += written; + left -= written; + } -void OSystem_Android::clearFocusRectangle() { - ENTER(); + if (written < 0) + break; - if (_enable_zoning) { - _focus_rect = Common::Rect(); - _force_redraw = true; + // prepare the next buffer, and run into the blocking AudioTrack.write } -} -void OSystem_Android::showOverlay() { - ENTER(); + JNI::setAudioStop(); - _show_overlay = true; - _force_redraw = true; -} + env->DeleteLocalRef(bufa); -void OSystem_Android::hideOverlay() { - ENTER(); + JNI::detachThread(); - _show_overlay = false; - _force_redraw = true; + return 0; } -void OSystem_Android::clearOverlay() { +void OSystem_Android::initBackend() { ENTER(); - _overlay_texture->fillBuffer(0); - - // Shouldn't need this, but works around a 'blank screen' bug on Nexus1 - updateScreen(); -} - -void OSystem_Android::grabOverlay(OverlayColor *buf, int pitch) { - ENTER("%p, %d", buf, pitch); - - // We support overlay alpha blending, so the pixel data here - // shouldn't actually be used. Let's fill it with zeros, I'm sure - // it will be fine... - const Graphics::Surface *surface = _overlay_texture->surface_const(); - assert(surface->bytesPerPixel == sizeof(buf[0])); - - int h = surface->h; - - do { - memset(buf, 0, surface->w * sizeof(buf[0])); - - // This 'pitch' is pixels not bytes - buf += pitch; - } while (--h); -} - -void OSystem_Android::copyRectToOverlay(const OverlayColor *buf, int pitch, - int x, int y, int w, int h) { - ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h); - - const Graphics::Surface *surface = _overlay_texture->surface_const(); - assert(surface->bytesPerPixel == sizeof(buf[0])); - - // This 'pitch' is pixels not bytes - _overlay_texture->updateBuffer(x, y, w, h, buf, pitch * sizeof(buf[0])); - - // Shouldn't need this, but works around a 'blank screen' bug on Nexus1? - updateScreen(); -} + _main_thread = pthread_self(); -int16 OSystem_Android::getOverlayHeight() { - return _overlay_texture->height(); -} - -int16 OSystem_Android::getOverlayWidth() { - return _overlay_texture->width(); -} - -bool OSystem_Android::showMouse(bool visible) { - ENTER("%d", visible); - - _show_mouse = visible; - - return true; -} - -void OSystem_Android::warpMouse(int x, int y) { - ENTER("%d, %d", x, y); - - // We use only the eventmanager's idea of the current mouse - // position, so there is nothing extra to do here. -} - -void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, - int hotspotX, int hotspotY, - uint32 keycolor, int cursorTargetScale, - const Graphics::PixelFormat *format) { - ENTER("%p, %u, %u, %d, %d, %u, %d, %p", buf, w, h, hotspotX, hotspotY, - keycolor, cursorTargetScale, format); + ConfMan.registerDefault("fullscreen", true); + ConfMan.registerDefault("aspect_ratio", true); - assert(keycolor < 256); + ConfMan.setInt("autosave_period", 0); + ConfMan.setBool("FM_high_quality", false); + ConfMan.setBool("FM_medium_quality", true); - _mouse_texture->allocBuffer(w, h); + // TODO hackity hack + if (ConfMan.hasKey("multi_midi")) + _touchpad_mode = !ConfMan.getBool("multi_midi"); - // Update palette alpha based on keycolor - byte *palette = _mouse_texture->palette(); - int i = 256; + // must happen before creating TimerManager to avoid race in + // creating EventManager + setupKeymapper(); - do { - palette[3] = 0xff; - palette += 4; - } while (--i); + // BUG: "transient" ConfMan settings get nuked by the options + // screen. Passing the savepath in this way makes it stick + // (via ConfMan.registerDefault) + _savefile = new DefaultSaveFileManager(ConfMan.get("savepath")); + _timer = new DefaultTimerManager(); - palette = _mouse_texture->palette(); - palette[keycolor * 4 + 3] = 0x00; + gettimeofday(&_startTime, 0); - _mouse_texture->updateBuffer(0, 0, w, h, buf, w); + _mixer = new Audio::MixerImpl(this, _audio_sample_rate); + _mixer->setReady(true); - _mouse_hotspot = Common::Point(hotspotX, hotspotY); - _mouse_targetscale = cursorTargetScale; -} + _timer_thread_exit = false; + pthread_create(&_timer_thread, 0, timerThreadFunc, this); -void OSystem_Android::_setCursorPalette(const byte *colors, - uint start, uint num) { - byte *palette = _mouse_texture->palette() + start * 4; + _audio_thread_exit = false; + pthread_create(&_audio_thread, 0, audioThreadFunc, this); - do { - for (int i = 0; i < 3; ++i) - palette[i] = colors[i]; + initSurface(); + initViewport(); - // Leave alpha untouched to preserve keycolor + _game_texture = new GLESFakePalette565Texture(); + _overlay_texture = new GLES4444Texture(); + _mouse_texture_palette = new GLESPalette5551Texture(); + _mouse_texture = _mouse_texture_palette; - palette += 4; - colors += 3; - } while (--num); -} + initOverlay(); -void OSystem_Android::setCursorPalette(const byte *colors, - uint start, uint num) { - ENTER("%p, %u, %u", colors, start, num); + // renice this thread to boost the audio thread + if (setpriority(PRIO_PROCESS, 0, 19) < 0) + warning("couldn't renice the main thread"); - _setCursorPalette(colors, start, num); - _use_mouse_palette = true; + JNI::setReadyForEvents(true); } -void OSystem_Android::disableCursorPalette(bool disable) { - ENTER("%d", disable); +void OSystem_Android::addPluginDirectories(Common::FSList &dirs) const { + ENTER(); - _use_mouse_palette = !disable; + JNI::getPluginDirectories(dirs); } -void OSystem_Android::setupKeymapper() { -#ifdef ENABLE_KEYMAPPER - using namespace Common; - - Keymapper *mapper = getEventManager()->getKeymapper(); - - HardwareKeySet *keySet = new HardwareKeySet(); - - keySet->addHardwareKey( - new HardwareKey("n", KeyState(KEYCODE_n), "n (vk)", - kTriggerLeftKeyType, - kVirtualKeyboardActionType)); - - mapper->registerHardwareKeySet(keySet); - - Keymap *globalMap = new Keymap("global"); - Action *act; - - act = new Action(globalMap, "VIRT", "Display keyboard", - kVirtualKeyboardActionType); - act->addKeyEvent(KeyState(KEYCODE_F7, ASCII_F7, 0)); - - mapper->addGlobalKeymap(globalMap); - - mapper->pushKeymap("global"); -#endif +bool OSystem_Android::hasFeature(Feature f) { + return (f == kFeatureFullscreenMode || + f == kFeatureAspectRatioCorrection || + f == kFeatureCursorHasPalette || + f == kFeatureVirtualKeyboard || + f == kFeatureOverlaySupportsAlpha); } -bool OSystem_Android::pollEvent(Common::Event &event) { - //ENTER(); - - lockMutex(_event_queue_lock); - - if (_event_queue.empty()) { - unlockMutex(_event_queue_lock); - return false; - } +void OSystem_Android::setFeatureState(Feature f, bool enable) { + ENTER("%d, %d", f, enable); - event = _event_queue.pop(); - unlockMutex(_event_queue_lock); - - switch (event.type) { - case Common::EVENT_MOUSEMOVE: - // TODO: only dirty/redraw move bounds - _force_redraw = true; - // fallthrough - case Common::EVENT_LBUTTONDOWN: - case Common::EVENT_LBUTTONUP: - case Common::EVENT_RBUTTONDOWN: - case Common::EVENT_RBUTTONUP: - case Common::EVENT_WHEELUP: - case Common::EVENT_WHEELDOWN: - case Common::EVENT_MBUTTONDOWN: - case Common::EVENT_MBUTTONUP: { - // relative mouse hack - if (event.kbd.flags == 1) { - // Relative (trackball) mouse hack. - const Common::Point& mouse_pos = - getEventManager()->getMousePos(); - event.mouse.x += mouse_pos.x; - event.mouse.y += mouse_pos.y; - event.mouse.x = CLIP(event.mouse.x, (int16)0, _show_overlay ? - getOverlayWidth() : getWidth()); - event.mouse.y = CLIP(event.mouse.y, (int16)0, _show_overlay ? - getOverlayHeight() : getHeight()); - } else { - // Touchscreen events need to be converted - // from device to game coords first. - const GLESTexture *tex = _show_overlay - ? static_cast<GLESTexture *>(_overlay_texture) - : static_cast<GLESTexture *>(_game_texture); - event.mouse.x = scalef(event.mouse.x, tex->width(), - _egl_surface_width); - event.mouse.y = scalef(event.mouse.y, tex->height(), - _egl_surface_height); - event.mouse.x -= _shake_offset; - } + switch (f) { + case kFeatureFullscreenMode: + _fullscreen = enable; + updateScreenRect(); break; - } - case Common::EVENT_SCREEN_CHANGED: - debug("EVENT_SCREEN_CHANGED"); - _screen_changeid++; - destroyScummVMSurface(); - setupScummVMSurface(); + case kFeatureAspectRatioCorrection: + _ar_correction = enable; + updateScreenRect(); + break; + case kFeatureVirtualKeyboard: + _virtkeybd_on = enable; + showVirtualKeyboard(enable); break; default: break; } - - return true; -} - -void OSystem_Android::pushEvent(const Common::Event& event) { - lockMutex(_event_queue_lock); - - // Try to combine multiple queued mouse move events - if (event.type == Common::EVENT_MOUSEMOVE && - !_event_queue.empty() && - _event_queue.back().type == Common::EVENT_MOUSEMOVE) { - Common::Event tail = _event_queue.back(); - if (event.kbd.flags) { - // relative movement hack - tail.mouse.x += event.mouse.x; - tail.mouse.y += event.mouse.y; - } else { - // absolute position, clear relative flag - tail.kbd.flags = 0; - tail.mouse.x = event.mouse.x; - tail.mouse.y = event.mouse.y; - } - } else { - _event_queue.push(event); - } - - unlockMutex(_event_queue_lock); } -static void ScummVM_pushEvent(JNIEnv *env, jobject self, jobject java_event) { - OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self); - - Common::Event event; - event.type = (Common::EventType)env->GetIntField(java_event, - FID_Event_type); - - event.synthetic = - env->GetBooleanField(java_event, FID_Event_synthetic); - - switch (event.type) { - case Common::EVENT_KEYDOWN: - case Common::EVENT_KEYUP: - event.kbd.keycode = (Common::KeyCode)env->GetIntField( - java_event, FID_Event_kbd_keycode); - event.kbd.ascii = static_cast<int>(env->GetIntField( - java_event, FID_Event_kbd_ascii)); - event.kbd.flags = static_cast<int>(env->GetIntField( - java_event, FID_Event_kbd_flags)); - break; - case Common::EVENT_MOUSEMOVE: - case Common::EVENT_LBUTTONDOWN: - case Common::EVENT_LBUTTONUP: - case Common::EVENT_RBUTTONDOWN: - case Common::EVENT_RBUTTONUP: - case Common::EVENT_WHEELUP: - case Common::EVENT_WHEELDOWN: - case Common::EVENT_MBUTTONDOWN: - case Common::EVENT_MBUTTONUP: - event.mouse.x = - env->GetIntField(java_event, FID_Event_mouse_x); - event.mouse.y = - env->GetIntField(java_event, FID_Event_mouse_y); - // This is a terrible hack. We stash "relativeness" - // in the kbd.flags field until pollEvent() can work - // it out. - event.kbd.flags = env->GetBooleanField( - java_event, FID_Event_mouse_relative) ? 1 : 0; - break; +bool OSystem_Android::getFeatureState(Feature f) { + switch (f) { + case kFeatureFullscreenMode: + return _fullscreen; + case kFeatureAspectRatioCorrection: + return _ar_correction; + case kFeatureVirtualKeyboard: + return _virtkeybd_on; default: - break; + return false; } - - cpp_obj->pushEvent(event); } uint32 OSystem_Android::getMillis() { @@ -1219,7 +408,7 @@ uint32 OSystem_Android::getMillis() { gettimeofday(&curTime, 0); - return (uint32)(((curTime.tv_sec - _startTime.tv_sec) * 1000) + \ + return (uint32)(((curTime.tv_sec - _startTime.tv_sec) * 1000) + ((curTime.tv_usec - _startTime.tv_usec) / 1000)); } @@ -1229,6 +418,7 @@ void OSystem_Android::delayMillis(uint msecs) { OSystem::MutexRef OSystem_Android::createMutex() { pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); @@ -1267,58 +457,38 @@ void OSystem_Android::deleteMutex(MutexRef mutex) { void OSystem_Android::quit() { ENTER(); + JNI::setReadyForEvents(false); + + _audio_thread_exit = true; + pthread_join(_audio_thread, 0); + _timer_thread_exit = true; pthread_join(_timer_thread, 0); + + delete _game_texture; + delete _overlay_texture; + delete _mouse_texture_palette; + delete _mouse_texture_rgb; + + deinitSurface(); } void OSystem_Android::setWindowCaption(const char *caption) { ENTER("%s", caption); - JNIEnv *env = JNU_GetEnv(); - jstring java_caption = env->NewStringUTF(caption); - env->CallVoidMethod(_back_ptr, MID_setWindowCaption, java_caption); - - if (env->ExceptionCheck()) { - warning("Failed to set window caption"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } - - env->DeleteLocalRef(java_caption); + JNI::setWindowCaption(caption); } void OSystem_Android::displayMessageOnOSD(const char *msg) { ENTER("%s", msg); - JNIEnv *env = JNU_GetEnv(); - jstring java_msg = env->NewStringUTF(msg); - - env->CallVoidMethod(_back_ptr, MID_displayMessageOnOSD, java_msg); - - if (env->ExceptionCheck()) { - warning("Failed to display OSD message"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } - - env->DeleteLocalRef(java_msg); + JNI::displayMessageOnOSD(msg); } void OSystem_Android::showVirtualKeyboard(bool enable) { ENTER("%d", enable); - JNIEnv *env = JNU_GetEnv(); - - env->CallVoidMethod(_back_ptr, MID_showVirtualKeyboard, enable); - - if (env->ExceptionCheck()) { - error("Error trying to show virtual keyboard"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - } + JNI::showVirtualKeyboard(enable); } Common::SaveFileManager *OSystem_Android::getSavefileManager() { @@ -1355,37 +525,13 @@ FilesystemFactory *OSystem_Android::getFilesystemFactory() { void OSystem_Android::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { - s.add("ASSET", _asset_archive, priority, false); - - JNIEnv *env = JNU_GetEnv(); - - jobjectArray array = - (jobjectArray)env->CallObjectMethod(_back_ptr, MID_getSysArchives); - - if (env->ExceptionCheck()) { - warning("Error finding system archive path"); - - env->ExceptionDescribe(); - env->ExceptionClear(); - - return; - } - - jsize size = env->GetArrayLength(array); - for (jsize i = 0; i < size; ++i) { - jstring path_obj = (jstring)env->GetObjectArrayElement(array, i); - const char *path = env->GetStringUTFChars(path_obj, 0); - - if (path != 0) { - s.addDirectory(path, path, priority); - env->ReleaseStringUTFChars(path_obj, path); - } + ENTER(""); - env->DeleteLocalRef(path_obj); - } + JNI::addSysArchivesToSearchSet(s, priority); } -void OSystem_Android::logMessage(LogMessageType::Type type, const char *message) { +void OSystem_Android::logMessage(LogMessageType::Type type, + const char *message) { switch (type) { case LogMessageType::kDebug: __android_log_write(ANDROID_LOG_DEBUG, android_log_tag, message); @@ -1401,177 +547,11 @@ void OSystem_Android::logMessage(LogMessageType::Type type, const char *message) } } -static jint ScummVM_scummVMMain(JNIEnv *env, jobject self, jobjectArray args) { - OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self); - - const int MAX_NARGS = 32; - int res = -1; - - int argc = env->GetArrayLength(args); - if (argc > MAX_NARGS) { - JNU_ThrowByName(env, "java/lang/IllegalArgumentException", - "too many arguments"); - return 0; - } - - char *argv[MAX_NARGS]; - - // note use in cleanup loop below - int nargs; - - for (nargs = 0; nargs < argc; ++nargs) { - jstring arg = (jstring)env->GetObjectArrayElement(args, nargs); - - if (arg == 0) { - argv[nargs] = 0; - } else { - const char *cstr = env->GetStringUTFChars(arg, 0); - - argv[nargs] = const_cast<char *>(cstr); - - // exception already thrown? - if (cstr == 0) - goto cleanup; - } - - env->DeleteLocalRef(arg); - } - - g_system = cpp_obj; - assert(g_system); - - LOGI("Entering scummvm_main with %d args", argc); - - res = scummvm_main(argc, argv); - - LOGI("Exiting scummvm_main"); - - g_system->quit(); - -cleanup: - nargs--; - - for (int i = 0; i < nargs; ++i) { - if (argv[i] == 0) - continue; - - jstring arg = (jstring)env->GetObjectArrayElement(args, nargs); - - // Exception already thrown? - if (arg == 0) - return res; - - env->ReleaseStringUTFChars(arg, argv[i]); - env->DeleteLocalRef(arg); - } - - return res; -} - #ifdef DYNAMIC_MODULES void AndroidPluginProvider::addCustomDirectories(Common::FSList &dirs) const { - OSystem_Android *g_system_android = (OSystem_Android *)g_system; - g_system_android->addPluginDirectories(dirs); + ((OSystem_Android *)g_system)->addPluginDirectories(dirs); } #endif -static void ScummVM_enableZoning(JNIEnv *env, jobject self, jboolean enable) { - OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self); - cpp_obj->enableZoning(enable); -} - -static void ScummVM_setSurfaceSize(JNIEnv *env, jobject self, - jint width, jint height) { - OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self); - cpp_obj->setSurfaceSize(width, height); -} - -const static JNINativeMethod gMethods[] = { - { "create", "(Landroid/content/res/AssetManager;)V", - (void *)ScummVM_create }, - { "nativeDestroy", "()V", - (void *)ScummVM_nativeDestroy }, - { "scummVMMain", "([Ljava/lang/String;)I", - (void *)ScummVM_scummVMMain }, - { "pushEvent", "(Lorg/inodes/gus/scummvm/Event;)V", - (void *)ScummVM_pushEvent }, - { "audioMixCallback", "([B)V", - (void *)ScummVM_audioMixCallback }, - { "setConfMan", "(Ljava/lang/String;I)V", - (void *)ScummVM_setConfManInt }, - { "setConfMan", "(Ljava/lang/String;Ljava/lang/String;)V", - (void *)ScummVM_setConfManString }, - { "enableZoning", "(Z)V", - (void *)ScummVM_enableZoning }, - { "setSurfaceSize", "(II)V", - (void *)ScummVM_setSurfaceSize }, -}; - -JNIEXPORT jint JNICALL -JNI_OnLoad(JavaVM *jvm, void *reserved) { - cached_jvm = jvm; - - JNIEnv *env; - - if (jvm->GetEnv((void **)&env, JNI_VERSION_1_2)) - return JNI_ERR; - - jclass cls = env->FindClass("org/inodes/gus/scummvm/ScummVM"); - if (cls == 0) - return JNI_ERR; - - if (env->RegisterNatives(cls, gMethods, ARRAYSIZE(gMethods)) < 0) - return JNI_ERR; - - FID_ScummVM_nativeScummVM = env->GetFieldID(cls, "nativeScummVM", "J"); - if (FID_ScummVM_nativeScummVM == 0) - return JNI_ERR; - - jclass event = env->FindClass("org/inodes/gus/scummvm/Event"); - if (event == 0) - return JNI_ERR; - - FID_Event_type = env->GetFieldID(event, "type", "I"); - if (FID_Event_type == 0) - return JNI_ERR; - - FID_Event_synthetic = env->GetFieldID(event, "synthetic", "Z"); - if (FID_Event_synthetic == 0) - return JNI_ERR; - - FID_Event_kbd_keycode = env->GetFieldID(event, "kbd_keycode", "I"); - if (FID_Event_kbd_keycode == 0) - return JNI_ERR; - - FID_Event_kbd_ascii = env->GetFieldID(event, "kbd_ascii", "I"); - if (FID_Event_kbd_ascii == 0) - return JNI_ERR; - - FID_Event_kbd_flags = env->GetFieldID(event, "kbd_flags", "I"); - if (FID_Event_kbd_flags == 0) - return JNI_ERR; - - FID_Event_mouse_x = env->GetFieldID(event, "mouse_x", "I"); - if (FID_Event_mouse_x == 0) - return JNI_ERR; - - FID_Event_mouse_y = env->GetFieldID(event, "mouse_y", "I"); - if (FID_Event_mouse_y == 0) - return JNI_ERR; - - FID_Event_mouse_relative = env->GetFieldID(event, "mouse_relative", "Z"); - if (FID_Event_mouse_relative == 0) - return JNI_ERR; - - cls = env->FindClass("java/lang/Object"); - if (cls == 0) - return JNI_ERR; - - MID_Object_wait = env->GetMethodID(cls, "wait", "()V"); - if (MID_Object_wait == 0) - return JNI_ERR; - - return JNI_VERSION_1_2; -} - #endif + diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 855fb04b5d..7ff96186f9 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -23,8 +23,23 @@ * */ +#ifndef _ANDROID_H_ +#define _ANDROID_H_ + #if defined(__ANDROID__) +#include "common/fs.h" +#include "common/archive.h" +#include "audio/mixer_intern.h" +#include "graphics/surface.h" +#include "backends/base-backend.h" +#include "backends/plugins/posix/posix-provider.h" +#include "backends/fs/posix/posix-fs-factory.h" + +#include "backends/platform/android/texture.h" + +#include <pthread.h> + #include <android/log.h> #include <GLES/gl.h> @@ -46,7 +61,7 @@ extern const char *android_log_tag; #ifdef ANDROID_DEBUG_ENTER #define ENTER(fmt, args...) LOGD("%s(" fmt ")", __FUNCTION__, ##args) #else -#define ENTER(fmt, args...) /**/ +#define ENTER(fmt, args...) do { } while (false) #endif #ifdef ANDROID_DEBUG_GL @@ -58,13 +73,215 @@ extern void checkGlError(const char *expr, const char *file, int line); checkGlError(#x, __FILE__, __LINE__); \ } while (false) +#define GLTHREADCHECK \ + do { \ + assert(pthread_self() == _main_thread); \ + } while (false) + #else #define GLCALL(x) do { (x); } while (false) +#define GLTHREADCHECK do { } while (false) +#endif + +#ifdef DYNAMIC_MODULES +class AndroidPluginProvider : public POSIXPluginProvider { +protected: + virtual void addCustomDirectories(Common::FSList &dirs) const; +}; +#endif + +class OSystem_Android : public BaseBackend, public PaletteManager { +private: + // passed from the dark side + int _audio_sample_rate; + int _audio_buffer_size; + + int _screen_changeid; + int _egl_surface_width; + int _egl_surface_height; + + bool _force_redraw; + + // Game layer + GLESBaseTexture *_game_texture; + int _shake_offset; + Common::Rect _focus_rect; + + // Overlay layer + GLES4444Texture *_overlay_texture; + bool _show_overlay; + + // Mouse layer + GLESBaseTexture *_mouse_texture; + GLESPaletteTexture *_mouse_texture_palette; + GLES5551Texture *_mouse_texture_rgb; + Common::Point _mouse_hotspot; + uint32 _mouse_keycolor; + int _mouse_targetscale; + bool _show_mouse; + bool _use_mouse_palette; + + int _graphicsMode; + bool _fullscreen; + bool _ar_correction; + + pthread_t _main_thread; + + bool _timer_thread_exit; + pthread_t _timer_thread; + static void *timerThreadFunc(void *arg); + + bool _audio_thread_exit; + pthread_t _audio_thread; + static void *audioThreadFunc(void *arg); + + bool _enable_zoning; + bool _virtkeybd_on; + + Common::SaveFileManager *_savefile; + Audio::MixerImpl *_mixer; + Common::TimerManager *_timer; + FilesystemFactory *_fsFactory; + timeval _startTime; + + void initSurface(); + void deinitSurface(); + void initViewport(); + + void initOverlay(); + +#ifdef USE_RGB_COLOR + Common::String getPixelFormatName(const Graphics::PixelFormat &format) const; + void initTexture(GLESBaseTexture **texture, uint width, uint height, + const Graphics::PixelFormat *format); +#endif + + void setupKeymapper(); + void setCursorPaletteInternal(const byte *colors, uint start, uint num); + +public: + OSystem_Android(int audio_sample_rate, int audio_buffer_size); + virtual ~OSystem_Android(); + + virtual void initBackend(); + void addPluginDirectories(Common::FSList &dirs) const; + void enableZoning(bool enable) { _enable_zoning = enable; } + + virtual bool hasFeature(Feature f); + virtual void setFeatureState(Feature f, bool enable); + virtual bool getFeatureState(Feature f); + + virtual const GraphicsMode *getSupportedGraphicsModes() const; + virtual int getDefaultGraphicsMode() const; + virtual bool setGraphicsMode(int mode); + virtual int getGraphicsMode() const; + +#ifdef USE_RGB_COLOR + virtual Graphics::PixelFormat getScreenFormat() const; + virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const; #endif -// Fix JNIEXPORT declaration to actually do something useful -#undef JNIEXPORT -#define JNIEXPORT __attribute__ ((visibility("default"))) + virtual void initSize(uint width, uint height, + const Graphics::PixelFormat *format); + + enum FixupType { + kClear = 0, // glClear + kClearSwap, // glClear + swapBuffers + kClearUpdate // glClear + updateScreen + }; + + void clearScreen(FixupType type, byte count = 1); + + void updateScreenRect(); + virtual int getScreenChangeID() const; + + virtual int16 getHeight(); + virtual int16 getWidth(); + + virtual PaletteManager *getPaletteManager() { + return this; + } + +public: + void pushEvent(int type, int arg1, int arg2, int arg3, int arg4, int arg5); + +private: + Common::Queue<Common::Event> _event_queue; + MutexRef _event_queue_lock; + Common::Point _touch_pt_down, _touch_pt_dt; + int _eventScaleX; + int _eventScaleY; + bool _touchpad_mode; + int _touchpad_scale; + int _trackball_scale; + int _dpad_scale; + + void clipMouse(Common::Point &p); + void scaleMouse(Common::Point &p, int x, int y, bool deductDrawRect = true); + void updateEventScale(); + +protected: + // PaletteManager API + virtual void setPalette(const byte *colors, uint start, uint num); + virtual void grabPalette(byte *colors, uint start, uint num); + +public: + virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, + int w, int h); + virtual void updateScreen(); + virtual Graphics::Surface *lockScreen(); + virtual void unlockScreen(); + virtual void setShakePos(int shakeOffset); + virtual void fillScreen(uint32 col); + virtual void setFocusRectangle(const Common::Rect& rect); + virtual void clearFocusRectangle(); + + virtual void showOverlay(); + virtual void hideOverlay(); + virtual void clearOverlay(); + virtual void grabOverlay(OverlayColor *buf, int pitch); + virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, + int x, int y, int w, int h); + virtual int16 getOverlayHeight(); + virtual int16 getOverlayWidth(); + virtual Graphics::PixelFormat getOverlayFormat() const; + + virtual bool showMouse(bool visible); + + virtual void warpMouse(int x, int y); + virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, + int hotspotY, uint32 keycolor, + int cursorTargetScale, + const Graphics::PixelFormat *format); + virtual void setCursorPalette(const byte *colors, uint start, uint num); + virtual void disableCursorPalette(bool disable); + + virtual bool pollEvent(Common::Event &event); + virtual uint32 getMillis(); + virtual void delayMillis(uint msecs); + + virtual MutexRef createMutex(void); + virtual void lockMutex(MutexRef mutex); + virtual void unlockMutex(MutexRef mutex); + virtual void deleteMutex(MutexRef mutex); + + virtual void quit(); + + virtual void setWindowCaption(const char *caption); + virtual void displayMessageOnOSD(const char *msg); + virtual void showVirtualKeyboard(bool enable); + + virtual Common::SaveFileManager *getSavefileManager(); + virtual Audio::Mixer *getMixer(); + virtual void getTimeAndDate(TimeDate &t) const; + virtual Common::TimerManager *getTimerManager(); + virtual FilesystemFactory *getFilesystemFactory(); + virtual void logMessage(LogMessageType::Type type, const char *message); + virtual void addSysArchivesToSearchSet(Common::SearchSet &s, + int priority = 0); +}; + +#endif #endif diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk index 1bc3c3d21a..cb39f8acfe 100644 --- a/backends/platform/android/android.mk +++ b/backends/platform/android/android.mk @@ -6,6 +6,7 @@ ANDROID_PLUGIN_VERSIONCODE = 6 JAVA_FILES = \ ScummVM.java \ + ScummVMEvents.java \ ScummVMApplication.java \ ScummVMActivity.java \ EditableSurfaceView.java \ @@ -163,6 +164,10 @@ release/%.apk: %.apk androidrelease: $(addprefix release/, $(APK_MAIN) $(APK_PLUGINS)) +androidtestmain: $(APK_MAIN) + $(ADB) install -r $(APK_MAIN) + $(ADB) shell am start -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -n org.inodes.gus.scummvm/.Unpacker + androidtest: $(APK_MAIN) $(APK_PLUGINS) @set -e; for apk in $^; do \ $(ADB) install -r $$apk; \ diff --git a/backends/platform/android/asset-archive.cpp b/backends/platform/android/asset-archive.cpp index 71ce25aa72..26b1a6ad39 100644 --- a/backends/platform/android/asset-archive.cpp +++ b/backends/platform/android/asset-archive.cpp @@ -36,10 +36,9 @@ #include "common/archive.h" #include "common/debug.h" +#include "backends/platform/android/jni.h" #include "backends/platform/android/asset-archive.h" -extern JNIEnv *JNU_GetEnv(); - // Must match android.content.res.AssetManager.ACCESS_* const jint ACCESS_UNKNOWN = 0; const jint ACCESS_RANDOM = 1; @@ -100,7 +99,7 @@ JavaInputStream::JavaInputStream(JNIEnv *env, jobject is) : { _input_stream = env->NewGlobalRef(is); _buflen = 8192; - _buf = static_cast<jbyteArray>(env->NewGlobalRef(env->NewByteArray(_buflen))); + _buf = (jbyteArray)env->NewGlobalRef(env->NewByteArray(_buflen)); jclass cls = env->GetObjectClass(_input_stream); MID_mark = env->GetMethodID(cls, "mark", "(I)V"); @@ -124,7 +123,7 @@ JavaInputStream::JavaInputStream(JNIEnv *env, jobject is) : } JavaInputStream::~JavaInputStream() { - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); close(env); env->DeleteGlobalRef(_buf); @@ -139,11 +138,11 @@ void JavaInputStream::close(JNIEnv *env) { } uint32 JavaInputStream::read(void *dataPtr, uint32 dataSize) { - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); if (_buflen < jint(dataSize)) { _buflen = dataSize; - + env->DeleteGlobalRef(_buf); _buf = static_cast<jbyteArray>(env->NewGlobalRef(env->NewByteArray(_buflen))); } @@ -171,7 +170,7 @@ uint32 JavaInputStream::read(void *dataPtr, uint32 dataSize) { } bool JavaInputStream::seek(int32 offset, int whence) { - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); uint32 newpos; switch (whence) { @@ -305,7 +304,8 @@ AssetFdReadStream::AssetFdReadStream(JNIEnv *env, jobject assetfd) : _declared_len = env->CallLongMethod(_assetfd, MID_getDeclaredLength); jmethodID MID_getFileDescriptor = - env->GetMethodID(cls, "getFileDescriptor", "()Ljava/io/FileDescriptor;"); + env->GetMethodID(cls, "getFileDescriptor", + "()Ljava/io/FileDescriptor;"); assert(MID_getFileDescriptor); jobject javafd = env->CallObjectMethod(_assetfd, MID_getFileDescriptor); assert(javafd); @@ -318,7 +318,7 @@ AssetFdReadStream::AssetFdReadStream(JNIEnv *env, jobject assetfd) : } AssetFdReadStream::~AssetFdReadStream() { - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); env->CallVoidMethod(_assetfd, MID_close); if (env->ExceptionCheck()) @@ -369,7 +369,7 @@ bool AssetFdReadStream::seek(int32 offset, int whence) { } AndroidAssetArchive::AndroidAssetArchive(jobject am) { - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); _am = env->NewGlobalRef(am); jclass cls = env->GetObjectClass(_am); @@ -377,8 +377,8 @@ AndroidAssetArchive::AndroidAssetArchive(jobject am) { "(Ljava/lang/String;I)Ljava/io/InputStream;"); assert(MID_open); - MID_openFd = env->GetMethodID(cls, "openFd", - "(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;"); + MID_openFd = env->GetMethodID(cls, "openFd", "(Ljava/lang/String;)" + "Landroid/content/res/AssetFileDescriptor;"); assert(MID_openFd); MID_list = env->GetMethodID(cls, "list", @@ -387,12 +387,12 @@ AndroidAssetArchive::AndroidAssetArchive(jobject am) { } AndroidAssetArchive::~AndroidAssetArchive() { - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); env->DeleteGlobalRef(_am); } bool AndroidAssetArchive::hasFile(const Common::String &name) { - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); jstring path = env->NewStringUTF(name.c_str()); jobject result = env->CallObjectMethod(_am, MID_open, path, ACCESS_UNKNOWN); if (env->ExceptionCheck()) { @@ -412,7 +412,7 @@ bool AndroidAssetArchive::hasFile(const Common::String &name) { } int AndroidAssetArchive::listMembers(Common::ArchiveMemberList &member_list) { - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); Common::List<Common::String> dirlist; dirlist.push_back(""); @@ -422,7 +422,8 @@ int AndroidAssetArchive::listMembers(Common::ArchiveMemberList &member_list) { dirlist.pop_back(); jstring jpath = env->NewStringUTF(dir.c_str()); - jobjectArray jpathlist = static_cast<jobjectArray>(env->CallObjectMethod(_am, MID_list, jpath)); + jobjectArray jpathlist = + (jobjectArray)env->CallObjectMethod(_am, MID_list, jpath); if (env->ExceptionCheck()) { warning("Error while calling AssetManager->list(%s). Ignoring.", @@ -469,7 +470,7 @@ Common::ArchiveMemberPtr AndroidAssetArchive::getMember(const Common::String &na } Common::SeekableReadStream *AndroidAssetArchive::createReadStreamForMember(const Common::String &path) const { - JNIEnv *env = JNU_GetEnv(); + JNIEnv *env = JNI::getEnv(); jstring jpath = env->NewStringUTF(path.c_str()); // Try openFd() first ... diff --git a/backends/platform/android/asset-archive.h b/backends/platform/android/asset-archive.h index 28e48426e9..6ec86e4cd0 100644 --- a/backends/platform/android/asset-archive.h +++ b/backends/platform/android/asset-archive.h @@ -23,6 +23,9 @@ * */ +#ifndef _ANDROID_ASSET_H_ +#define _ANDROID_ASSET_H_ + #if defined(__ANDROID__) #include <jni.h> @@ -51,3 +54,5 @@ private: }; #endif +#endif + diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp new file mode 100644 index 0000000000..1715e6a8a7 --- /dev/null +++ b/backends/platform/android/events.cpp @@ -0,0 +1,661 @@ +/* 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$ + * + */ + +#if defined(__ANDROID__) + +#include "common/events.h" + +#include "backends/platform/android/android.h" +#include "backends/platform/android/jni.h" + +// $ANDROID_NDK/platforms/android-9/arch-arm/usr/include/android/keycodes.h +// http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=libs/ui/Input.cpp +// http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/java/android/view/KeyEvent.java + +// event type +enum { + JE_SYS_KEY = 0, + JE_KEY = 1, + JE_DOWN = 2, + JE_SCROLL = 3, + JE_TAP = 4, + JE_DOUBLE_TAP = 5, + JE_BALL = 6, + JE_QUIT = 0x1000 +}; + +// action type +enum { + JACTION_DOWN = 0, + JACTION_UP = 1, + JACTION_MULTIPLE = 2 +}; + +// system keys +enum { + JKEYCODE_SOFT_RIGHT = 2, + JKEYCODE_HOME = 3, + JKEYCODE_BACK = 4, + JKEYCODE_CALL = 5, + JKEYCODE_ENDCALL = 6, + JKEYCODE_VOLUME_UP = 24, + JKEYCODE_VOLUME_DOWN = 25, + JKEYCODE_POWER = 26, + JKEYCODE_CAMERA = 27, + JKEYCODE_HEADSETHOOK = 79, + JKEYCODE_FOCUS = 80, + JKEYCODE_MENU = 82, + JKEYCODE_SEARCH = 84, + JKEYCODE_MUTE = 91, + JKEYCODE_MEDIA_PLAY_PAUSE = 85, + JKEYCODE_MEDIA_STOP = 86, + JKEYCODE_MEDIA_NEXT = 87, + JKEYCODE_MEDIA_PREVIOUS = 88, + JKEYCODE_MEDIA_REWIND = 89, + JKEYCODE_MEDIA_FAST_FORWARD = 90 +}; + +// five-way navigation control +enum { + JKEYCODE_DPAD_UP = 19, + JKEYCODE_DPAD_DOWN = 20, + JKEYCODE_DPAD_LEFT = 21, + JKEYCODE_DPAD_RIGHT = 22, + JKEYCODE_DPAD_CENTER = 23 +}; + +// meta modifier +enum { + JMETA_SHIFT = 0x01, + JMETA_ALT = 0x02, + JMETA_SYM = 0x04, + JMETA_CTRL = 0x1000 +}; + +// map android key codes to our kbd codes +static const Common::KeyCode jkeymap[] = { + Common::KEYCODE_INVALID, // KEYCODE_UNKNOWN + Common::KEYCODE_INVALID, // KEYCODE_SOFT_LEFT + Common::KEYCODE_INVALID, // KEYCODE_SOFT_RIGHT + Common::KEYCODE_INVALID, // KEYCODE_HOME + Common::KEYCODE_INVALID, // KEYCODE_BACK + Common::KEYCODE_INVALID, // KEYCODE_CALL + Common::KEYCODE_INVALID, // KEYCODE_ENDCALL + Common::KEYCODE_0, // KEYCODE_0 + Common::KEYCODE_1, // KEYCODE_1 + Common::KEYCODE_2, // KEYCODE_2 + Common::KEYCODE_3, // KEYCODE_3 + Common::KEYCODE_4, // KEYCODE_4 + Common::KEYCODE_5, // KEYCODE_5 + Common::KEYCODE_6, // KEYCODE_6 + Common::KEYCODE_7, // KEYCODE_7 + Common::KEYCODE_8, // KEYCODE_8 + Common::KEYCODE_9, // KEYCODE_9 + Common::KEYCODE_ASTERISK, // KEYCODE_STAR + Common::KEYCODE_HASH, // KEYCODE_POUND + Common::KEYCODE_INVALID, // KEYCODE_DPAD_UP + Common::KEYCODE_INVALID, // KEYCODE_DPAD_DOWN + Common::KEYCODE_INVALID, // KEYCODE_DPAD_LEFT + Common::KEYCODE_INVALID, // KEYCODE_DPAD_RIGHT + Common::KEYCODE_INVALID, // KEYCODE_DPAD_CENTER + Common::KEYCODE_INVALID, // KEYCODE_VOLUME_UP + Common::KEYCODE_INVALID, // KEYCODE_VOLUME_DOWN + Common::KEYCODE_INVALID, // KEYCODE_POWER + Common::KEYCODE_INVALID, // KEYCODE_CAMERA + Common::KEYCODE_INVALID, // KEYCODE_CLEAR + Common::KEYCODE_a, // KEYCODE_A + Common::KEYCODE_b, // KEYCODE_B + Common::KEYCODE_c, // KEYCODE_C + Common::KEYCODE_d, // KEYCODE_D + Common::KEYCODE_e, // KEYCODE_E + Common::KEYCODE_f, // KEYCODE_F + Common::KEYCODE_g, // KEYCODE_G + Common::KEYCODE_h, // KEYCODE_H + Common::KEYCODE_i, // KEYCODE_I + Common::KEYCODE_j, // KEYCODE_J + Common::KEYCODE_k, // KEYCODE_K + Common::KEYCODE_l, // KEYCODE_L + Common::KEYCODE_m, // KEYCODE_M + Common::KEYCODE_n, // KEYCODE_N + Common::KEYCODE_o, // KEYCODE_O + Common::KEYCODE_p, // KEYCODE_P + Common::KEYCODE_q, // KEYCODE_Q + Common::KEYCODE_r, // KEYCODE_R + Common::KEYCODE_s, // KEYCODE_S + Common::KEYCODE_t, // KEYCODE_T + Common::KEYCODE_u, // KEYCODE_U + Common::KEYCODE_v, // KEYCODE_V + Common::KEYCODE_w, // KEYCODE_W + Common::KEYCODE_x, // KEYCODE_X + Common::KEYCODE_y, // KEYCODE_Y + Common::KEYCODE_z, // KEYCODE_Z + Common::KEYCODE_COMMA, // KEYCODE_COMMA + Common::KEYCODE_PERIOD, // KEYCODE_PERIOD + Common::KEYCODE_LALT, // KEYCODE_ALT_LEFT + Common::KEYCODE_RALT, // KEYCODE_ALT_RIGHT + Common::KEYCODE_LSHIFT, // KEYCODE_SHIFT_LEFT + Common::KEYCODE_RSHIFT, // KEYCODE_SHIFT_RIGHT + Common::KEYCODE_TAB, // KEYCODE_TAB + Common::KEYCODE_SPACE, // KEYCODE_SPACE + Common::KEYCODE_LCTRL, // KEYCODE_SYM + Common::KEYCODE_INVALID, // KEYCODE_EXPLORER + Common::KEYCODE_INVALID, // KEYCODE_ENVELOPE + Common::KEYCODE_RETURN, // KEYCODE_ENTER + Common::KEYCODE_BACKSPACE, // KEYCODE_DEL + Common::KEYCODE_BACKQUOTE, // KEYCODE_GRAVE + Common::KEYCODE_MINUS, // KEYCODE_MINUS + Common::KEYCODE_EQUALS, // KEYCODE_EQUALS + Common::KEYCODE_LEFTPAREN, // KEYCODE_LEFT_BRACKET + Common::KEYCODE_RIGHTPAREN, // KEYCODE_RIGHT_BRACKET + Common::KEYCODE_BACKSLASH, // KEYCODE_BACKSLASH + Common::KEYCODE_SEMICOLON, // KEYCODE_SEMICOLON + Common::KEYCODE_QUOTE, // KEYCODE_APOSTROPHE + Common::KEYCODE_SLASH, // KEYCODE_SLASH + Common::KEYCODE_AT, // KEYCODE_AT + Common::KEYCODE_INVALID, // KEYCODE_NUM + Common::KEYCODE_INVALID, // KEYCODE_HEADSETHOOK + Common::KEYCODE_INVALID, // KEYCODE_FOCUS + Common::KEYCODE_PLUS, // KEYCODE_PLUS + Common::KEYCODE_INVALID, // KEYCODE_MENU + Common::KEYCODE_INVALID, // KEYCODE_NOTIFICATION + Common::KEYCODE_INVALID, // KEYCODE_SEARCH + Common::KEYCODE_INVALID, // KEYCODE_MEDIA_PLAY_PAUSE + Common::KEYCODE_INVALID, // KEYCODE_MEDIA_STOP + Common::KEYCODE_INVALID, // KEYCODE_MEDIA_NEXT + Common::KEYCODE_INVALID, // KEYCODE_MEDIA_PREVIOUS + Common::KEYCODE_INVALID, // KEYCODE_MEDIA_REWIND + Common::KEYCODE_INVALID, // KEYCODE_MEDIA_FAST_FORWARD + Common::KEYCODE_INVALID, // KEYCODE_MUTE + Common::KEYCODE_PAGEUP, // KEYCODE_PAGE_UP + Common::KEYCODE_PAGEDOWN // KEYCODE_PAGE_DOWN +}; + +// floating point. use sparingly +template <class T> +static inline T scalef(T in, float numerator, float denominator) { + return static_cast<float>(in) * numerator / denominator; +} + +void OSystem_Android::setupKeymapper() { +#ifdef ENABLE_KEYMAPPER + using namespace Common; + + Keymapper *mapper = getEventManager()->getKeymapper(); + + HardwareKeySet *keySet = new HardwareKeySet(); + + keySet->addHardwareKey( + new HardwareKey("n", KeyState(KEYCODE_n), "n (vk)", + kTriggerLeftKeyType, + kVirtualKeyboardActionType)); + + mapper->registerHardwareKeySet(keySet); + + Keymap *globalMap = new Keymap("global"); + Action *act; + + act = new Action(globalMap, "VIRT", "Display keyboard", + kVirtualKeyboardActionType); + act->addKeyEvent(KeyState(KEYCODE_F7, ASCII_F7, 0)); + + mapper->addGlobalKeymap(globalMap); + + mapper->pushKeymap("global"); +#endif +} + +void OSystem_Android::warpMouse(int x, int y) { + ENTER("%d, %d", x, y); + + Common::Event e; + + e.type = Common::EVENT_MOUSEMOVE; + e.mouse.x = x; + e.mouse.y = y; + + clipMouse(e.mouse); + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); +} + +void OSystem_Android::clipMouse(Common::Point &p) { + const GLESBaseTexture *tex; + + if (_show_overlay) + tex = _overlay_texture; + else + tex = _game_texture; + + p.x = CLIP(p.x, int16(0), int16(tex->width())); + p.y = CLIP(p.y, int16(0), int16(tex->height())); +} + +void OSystem_Android::scaleMouse(Common::Point &p, int x, int y, + bool deductDrawRect) { + const GLESBaseTexture *tex; + + if (_show_overlay) + tex = _overlay_texture; + else + tex = _game_texture; + + const Common::Rect &r = tex->getDrawRect(); + + if (_touchpad_mode) { + x = x * 100 / _touchpad_scale; + y = y * 100 / _touchpad_scale; + } + + if (deductDrawRect) { + x -= r.left; + y -= r.top; + } + + p.x = scalef(x, tex->width(), r.width()); + p.y = scalef(y, tex->height(), r.height()); +} + +void OSystem_Android::updateEventScale() { + const GLESBaseTexture *tex; + + if (_show_overlay) + tex = _overlay_texture; + else + tex = _game_texture; + + _eventScaleY = 100 * 480 / tex->height(); + _eventScaleX = 100 * 640 / tex->width(); +} + +void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, + int arg4, int arg5) { + Common::Event e; + + switch (type) { + case JE_SYS_KEY: + switch (arg1) { + case JACTION_DOWN: + e.type = Common::EVENT_KEYDOWN; + break; + case JACTION_UP: + e.type = Common::EVENT_KEYUP; + break; + default: + LOGE("unhandled jaction on system key: %d", arg1); + return; + } + + switch (arg2) { + case JKEYCODE_BACK: + e.kbd.keycode = Common::KEYCODE_ESCAPE; + e.kbd.ascii = Common::ASCII_ESCAPE; + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + + return; + + // special case. we'll only get it's up event + case JKEYCODE_MENU: + e.type = Common::EVENT_MAINMENU; + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + + return; + + default: + LOGW("unmapped system key: %d", arg2); + return; + } + + break; + + case JE_KEY: + // five-way first + switch (arg2) { + case JKEYCODE_DPAD_UP: + case JKEYCODE_DPAD_DOWN: + case JKEYCODE_DPAD_LEFT: + case JKEYCODE_DPAD_RIGHT: + { + if (arg1 != JACTION_DOWN) + return; + + e.type = Common::EVENT_MOUSEMOVE; + e.synthetic = true; + + e.mouse = getEventManager()->getMousePos(); + + int16 *c; + int s; + + if (arg2 == JKEYCODE_DPAD_UP || arg2 == JKEYCODE_DPAD_DOWN) { + c = &e.mouse.y; + s = _eventScaleY; + } else { + c = &e.mouse.x; + s = _eventScaleX; + } + + // the longer the button held, the faster the pointer is + // TODO put these values in some option dlg? + int f = CLIP(arg5, 1, 8) * _dpad_scale * 100 / s; + + *c += ((arg2 == JKEYCODE_DPAD_UP || + arg2 == JKEYCODE_DPAD_LEFT) ? -1 : 1) * f; + + clipMouse(e.mouse); + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + } + + return; + + case JKEYCODE_DPAD_CENTER: + switch (arg1) { + case JACTION_DOWN: + e.type = Common::EVENT_LBUTTONDOWN; + break; + case JACTION_UP: + e.type = Common::EVENT_LBUTTONUP; + break; + default: + LOGE("unhandled jaction on dpad key: %d", arg1); + return; + } + + { + const Common::Point &m = getEventManager()->getMousePos(); + + e.mouse = m; + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + } + + return; + } + + switch (arg1) { + case JACTION_DOWN: + e.type = Common::EVENT_KEYDOWN; + break; + case JACTION_UP: + e.type = Common::EVENT_KEYUP; + break; + default: + LOGE("unhandled jaction on key: %d", arg1); + return; + } + + if (arg2 < 1 || arg2 > ARRAYSIZE(jkeymap)) { + LOGE("received invalid keycode: %d", arg2); + return; + } + + if (arg5 > 0) + e.synthetic = true; + + e.kbd.keycode = jkeymap[arg2]; + e.kbd.ascii = arg3; + + if (arg4 & JMETA_SHIFT) + e.kbd.flags |= Common::KBD_SHIFT; + if (arg4 & JMETA_ALT) + e.kbd.flags |= Common::KBD_ALT; + if (arg4 & (JMETA_SYM | JMETA_CTRL)) + e.kbd.flags |= Common::KBD_CTRL; + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + + return; + + case JE_DOWN: + _touch_pt_down = getEventManager()->getMousePos(); + break; + + case JE_SCROLL: + e.type = Common::EVENT_MOUSEMOVE; + + if (_touchpad_mode) { + scaleMouse(e.mouse, arg3 - arg1, arg4 - arg2, false); + e.mouse += _touch_pt_down; + clipMouse(e.mouse); + } else { + scaleMouse(e.mouse, arg3, arg4); + clipMouse(e.mouse); + } + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + + return; + + case JE_TAP: + e.type = Common::EVENT_MOUSEMOVE; + + if (_touchpad_mode) { + e.mouse = getEventManager()->getMousePos(); + } else { + scaleMouse(e.mouse, arg1, arg2); + clipMouse(e.mouse); + } + + { + Common::EventType down, up; + + // TODO put these values in some option dlg? + if (arg3 > 1000) { + down = Common::EVENT_MBUTTONDOWN; + up = Common::EVENT_MBUTTONUP; + } else if (arg3 > 500) { + down = Common::EVENT_RBUTTONDOWN; + up = Common::EVENT_RBUTTONUP; + } else { + down = Common::EVENT_LBUTTONDOWN; + up = Common::EVENT_LBUTTONUP; + } + + lockMutex(_event_queue_lock); + + if (!_touchpad_mode) + _event_queue.push(e); + + e.type = down; + _event_queue.push(e); + e.type = up; + _event_queue.push(e); + + unlockMutex(_event_queue_lock); + } + + return; + + case JE_DOUBLE_TAP: + e.type = Common::EVENT_MOUSEMOVE; + + if (_touchpad_mode) { + e.mouse = getEventManager()->getMousePos(); + } else { + scaleMouse(e.mouse, arg1, arg2); + clipMouse(e.mouse); + } + + { + Common::EventType dptype = Common::EVENT_INVALID; + + switch (arg3) { + case JACTION_DOWN: + dptype = Common::EVENT_LBUTTONDOWN; + _touch_pt_dt.x = arg1; + _touch_pt_dt.y = arg2; + break; + case JACTION_UP: + dptype = Common::EVENT_LBUTTONUP; + break; + case JACTION_MULTIPLE: + // held and moved + dptype = Common::EVENT_MOUSEMOVE; + + if (_touchpad_mode) { + scaleMouse(e.mouse, arg1 - _touch_pt_dt.x, + arg2 - _touch_pt_dt.y, false); + e.mouse += _touch_pt_down; + + clipMouse(e.mouse); + } + + break; + default: + LOGE("unhandled jaction on double tap: %d", arg3); + return; + } + + lockMutex(_event_queue_lock); + _event_queue.push(e); + e.type = dptype; + _event_queue.push(e); + unlockMutex(_event_queue_lock); + } + + return; + + case JE_BALL: + e.type = Common::EVENT_MOUSEMOVE; + + e.mouse = getEventManager()->getMousePos(); + + // already multiplied by 100 + e.mouse.x += arg1 * _trackball_scale / _eventScaleX; + e.mouse.y += arg2 * _trackball_scale / _eventScaleY; + + clipMouse(e.mouse); + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + + return; + + case JE_QUIT: + e.type = Common::EVENT_QUIT; + + lockMutex(_event_queue_lock); + _event_queue.push(e); + unlockMutex(_event_queue_lock); + + return; + + default: + LOGE("unknown jevent type: %d", type); + + break; + } +} + +bool OSystem_Android::pollEvent(Common::Event &event) { + //ENTER(); + + if (pthread_self() == _main_thread) { + if (_screen_changeid != JNI::surface_changeid) { + if (JNI::egl_surface_width > 0 && JNI::egl_surface_height > 0) { + if (_egl_surface_width > 0 && _egl_surface_height > 0) { + // surface still alive but changed + _screen_changeid = JNI::surface_changeid; + _egl_surface_width = JNI::egl_surface_width; + _egl_surface_height = JNI::egl_surface_height; + + initViewport(); + updateScreenRect(); + updateEventScale(); + + // double buffered, flip twice + clearScreen(kClearUpdate, 2); + + event.type = Common::EVENT_SCREEN_CHANGED; + + return true; + } else { + // new surface + initSurface(); + updateScreenRect(); + updateEventScale(); + + // double buffered, flip twice + clearScreen(kClearUpdate, 2); + + event.type = Common::EVENT_SCREEN_CHANGED; + + return true; + } + } else { + // surface lost + deinitSurface(); + } + } + + if (JNI::pause) { + deinitSurface(); + + LOGD("main thread going to sleep"); + sem_wait(&JNI::pause_sem); + LOGD("main thread woke up"); + } + } + + lockMutex(_event_queue_lock); + + if (_event_queue.empty()) { + unlockMutex(_event_queue_lock); + return false; + } + + event = _event_queue.pop(); + + unlockMutex(_event_queue_lock); + + if (event.type == Common::EVENT_MOUSEMOVE) { + const Common::Point &m = getEventManager()->getMousePos(); + + if (m != event.mouse) + _force_redraw = true; + } + + return true; +} + +#endif + diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp new file mode 100644 index 0000000000..d7e31fcad7 --- /dev/null +++ b/backends/platform/android/gfx.cpp @@ -0,0 +1,810 @@ +/* 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$ + * + */ + +#if defined(__ANDROID__) + +#include "common/endian.h" +#include "graphics/conversion.h" + +#include "backends/platform/android/android.h" +#include "backends/platform/android/jni.h" + +static inline GLfixed xdiv(int numerator, int denominator) { + assert(numerator < (1 << 16)); + return (numerator << 16) / denominator; +} + +const OSystem::GraphicsMode *OSystem_Android::getSupportedGraphicsModes() const { + static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { + { "default", "Default", 0 }, + { "filter", "Linear filtering", 1 }, + { 0, 0, 0 }, + }; + + return s_supportedGraphicsModes; +} + +int OSystem_Android::getDefaultGraphicsMode() const { + return 0; +} + +bool OSystem_Android::setGraphicsMode(int mode) { + ENTER("%d", mode); + + if (_game_texture) + _game_texture->setLinearFilter(mode == 1); + + if (_overlay_texture) + _overlay_texture->setLinearFilter(mode == 1); + + _graphicsMode = mode; + + return true; +} + +int OSystem_Android::getGraphicsMode() const { + return _graphicsMode; +} + +#ifdef USE_RGB_COLOR +Graphics::PixelFormat OSystem_Android::getScreenFormat() const { + return _game_texture->getPixelFormat(); +} + +Common::List<Graphics::PixelFormat> OSystem_Android::getSupportedFormats() const { + Common::List<Graphics::PixelFormat> res; + res.push_back(GLES565Texture::pixelFormat()); + res.push_back(GLES5551Texture::pixelFormat()); + res.push_back(GLES4444Texture::pixelFormat()); + res.push_back(Graphics::PixelFormat::createFormatCLUT8()); + + return res; +} + +Common::String OSystem_Android::getPixelFormatName(const Graphics::PixelFormat &format) const { + if (format.bytesPerPixel == 1) + return "CLUT8"; + + if (format.aLoss == 8) + return Common::String::format("RGB%u%u%u", + 8 - format.rLoss, + 8 - format.gLoss, + 8 - format.bLoss); + + return Common::String::format("RGBA%u%u%u%u", + 8 - format.rLoss, + 8 - format.gLoss, + 8 - format.bLoss, + 8 - format.aLoss); +} + +void OSystem_Android::initTexture(GLESBaseTexture **texture, + uint width, uint height, + const Graphics::PixelFormat *format) { + assert(texture); + Graphics::PixelFormat format_clut8 = + Graphics::PixelFormat::createFormatCLUT8(); + Graphics::PixelFormat format_current; + Graphics::PixelFormat format_new; + + if (*texture) + format_current = (*texture)->getPixelFormat(); + else + format_current = Graphics::PixelFormat(); + + if (format) + format_new = *format; + else + format_new = format_clut8; + + if (format_current != format_new) { + if (*texture) + LOGD("switching pixel format from: %s", + getPixelFormatName((*texture)->getPixelFormat()).c_str()); + + delete *texture; + + if (format_new == GLES565Texture::pixelFormat()) + *texture = new GLES565Texture(); + else if (format_new == GLES5551Texture::pixelFormat()) + *texture = new GLES5551Texture(); + else if (format_new == GLES4444Texture::pixelFormat()) + *texture = new GLES4444Texture(); + else { + // TODO what now? + if (format_new != format_clut8) + LOGE("unsupported pixel format: %s", + getPixelFormatName(format_new).c_str()); + + *texture = new GLESFakePalette565Texture; + } + + LOGD("new pixel format: %s", + getPixelFormatName((*texture)->getPixelFormat()).c_str()); + } + + (*texture)->allocBuffer(width, height); + (*texture)->fillBuffer(0); +} +#endif + +void OSystem_Android::initSurface() { + LOGD("initializing surface"); + + assert(!JNI::haveSurface()); + + _screen_changeid = JNI::surface_changeid; + _egl_surface_width = JNI::egl_surface_width; + _egl_surface_height = JNI::egl_surface_height; + + assert(_egl_surface_width > 0 && _egl_surface_height > 0); + + JNI::initSurface(); + + // Initialise OpenGLES context. + GLESTexture::initGLExtensions(); + + if (_game_texture) + _game_texture->reinit(); + + if (_overlay_texture) { + _overlay_texture->reinit(); + initOverlay(); + } + + if (_mouse_texture) + _mouse_texture->reinit(); +} + +void OSystem_Android::deinitSurface() { + if (!JNI::haveSurface()) + return; + + LOGD("deinitializing surface"); + + _screen_changeid = JNI::surface_changeid; + _egl_surface_width = 0; + _egl_surface_height = 0; + + // release texture resources + if (_game_texture) + _game_texture->release(); + + if (_overlay_texture) + _overlay_texture->release(); + + if (_mouse_texture) + _mouse_texture->release(); + + JNI::deinitSurface(); +} + +void OSystem_Android::initViewport() { + LOGD("initializing viewport"); + + assert(JNI::haveSurface()); + + // Turn off anything that looks like 3D ;) + GLCALL(glDisable(GL_CULL_FACE)); + GLCALL(glDisable(GL_DEPTH_TEST)); + GLCALL(glDisable(GL_LIGHTING)); + GLCALL(glDisable(GL_FOG)); + GLCALL(glDisable(GL_DITHER)); + + GLCALL(glShadeModel(GL_FLAT)); + GLCALL(glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST)); + + GLCALL(glEnable(GL_BLEND)); + GLCALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + + GLCALL(glEnableClientState(GL_VERTEX_ARRAY)); + GLCALL(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); + + GLCALL(glEnable(GL_TEXTURE_2D)); + + GLCALL(glViewport(0, 0, _egl_surface_width, _egl_surface_height)); + + GLCALL(glMatrixMode(GL_PROJECTION)); + GLCALL(glLoadIdentity()); + GLCALL(glOrthof(0, _egl_surface_width, _egl_surface_height, 0, -1, 1)); + GLCALL(glMatrixMode(GL_MODELVIEW)); + GLCALL(glLoadIdentity()); + + clearFocusRectangle(); +} + +void OSystem_Android::initOverlay() { + int overlay_width = _egl_surface_width; + int overlay_height = _egl_surface_height; + + // the 'normal' theme layout uses a max height of 400 pixels. if the + // surface is too big we use only a quarter of the size so that the widgets + // don't get too small. if the surface height has less than 800 pixels, this + // enforces the 'lowres' layout, which will be scaled back up by factor 2x, + // but this looks way better than the 'normal' layout scaled by some + // calculated factors + if (overlay_height > 480) { + overlay_width /= 2; + overlay_height /= 2; + } + + LOGI("overlay size is %ux%u", overlay_width, overlay_height); + + _overlay_texture->allocBuffer(overlay_width, overlay_height); + _overlay_texture->fillBuffer(0); + _overlay_texture->setDrawRect(0, 0, + _egl_surface_width, _egl_surface_height); +} + +void OSystem_Android::initSize(uint width, uint height, + const Graphics::PixelFormat *format) { + ENTER("%d, %d, %p", width, height, format); + + GLTHREADCHECK; + +#ifdef USE_RGB_COLOR + initTexture(&_game_texture, width, height, format); +#else + _game_texture->allocBuffer(width, height); + _game_texture->fillBuffer(0); +#endif + + updateScreenRect(); + updateEventScale(); + + // Don't know mouse size yet - it gets reallocated in + // setMouseCursor. We need the palette allocated before + // setMouseCursor however, so just take a guess at the desired + // size (it's small). + _mouse_texture_palette->allocBuffer(20, 20); + + clearScreen(kClear); +} + +void OSystem_Android::clearScreen(FixupType type, byte count) { + assert(count > 0); + + GLCALL(glDisable(GL_SCISSOR_TEST)); + + for (byte i = 0; i < count; ++i) { + // clear screen + GLCALL(glClearColorx(0, 0, 0, 1 << 16)); + GLCALL(glClear(GL_COLOR_BUFFER_BIT)); + + switch (type) { + case kClear: + break; + + case kClearSwap: + JNI::swapBuffers(); + break; + + case kClearUpdate: + _force_redraw = true; + updateScreen(); + break; + } + } + + if (!_show_overlay) + GLCALL(glEnable(GL_SCISSOR_TEST)); +} + +void OSystem_Android::updateScreenRect() { + Common::Rect rect(0, 0, _egl_surface_width, _egl_surface_height); + + _overlay_texture->setDrawRect(rect); + + uint16 w = _game_texture->width(); + uint16 h = _game_texture->height(); + + if (w && h && !_fullscreen) { + if (_ar_correction && w == 320 && h == 200) + h = 240; + + float dpi[2]; + JNI::getDPI(dpi); + + float screen_ar; + if (dpi[0] != 0.0 && dpi[1] != 0.0) { + // horizontal orientation + screen_ar = (dpi[1] * _egl_surface_width) / + (dpi[0] * _egl_surface_height); + } else { + screen_ar = float(_egl_surface_width) / float(_egl_surface_height); + } + + float game_ar = float(w) / float(h); + + if (screen_ar > game_ar) { + rect.setWidth(round(_egl_surface_height * game_ar)); + rect.moveTo((_egl_surface_width - rect.width()) / 2, 0); + } else { + rect.setHeight(round(_egl_surface_width / game_ar)); + rect.moveTo((_egl_surface_height - rect.height()) / 2, 0); + } + } + + glScissor(rect.left, rect.top, rect.width(), rect.height()); + + _game_texture->setDrawRect(rect); +} + +int OSystem_Android::getScreenChangeID() const { + return _screen_changeid; +} + +int16 OSystem_Android::getHeight() { + return _game_texture->height(); +} + +int16 OSystem_Android::getWidth() { + return _game_texture->width(); +} + +void OSystem_Android::setPalette(const byte *colors, uint start, uint num) { + ENTER("%p, %u, %u", colors, start, num); + +#ifdef USE_RGB_COLOR + assert(_game_texture->hasPalette()); +#endif + + GLTHREADCHECK; + + if (!_use_mouse_palette) + setCursorPaletteInternal(colors, start, num); + + const Graphics::PixelFormat &pf = _game_texture->getPalettePixelFormat(); + byte *p = _game_texture->palette() + start * 2; + + for (uint i = 0; i < num; ++i, colors += 3, p += 2) + WRITE_UINT16(p, pf.RGBToColor(colors[0], colors[1], colors[2])); +} + +void OSystem_Android::grabPalette(byte *colors, uint start, uint num) { + ENTER("%p, %u, %u", colors, start, num); + +#ifdef USE_RGB_COLOR + assert(_game_texture->hasPalette()); +#endif + + GLTHREADCHECK; + + const Graphics::PixelFormat &pf = _game_texture->getPalettePixelFormat(); + const byte *p = _game_texture->palette_const() + start * 2; + + for (uint i = 0; i < num; ++i, colors += 3, p += 2) + pf.colorToRGB(READ_UINT16(p), colors[0], colors[1], colors[2]); +} + +void OSystem_Android::copyRectToScreen(const byte *buf, int pitch, + int x, int y, int w, int h) { + ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h); + + GLTHREADCHECK; + + _game_texture->updateBuffer(x, y, w, h, buf, pitch); +} + +void OSystem_Android::updateScreen() { + //ENTER(); + + GLTHREADCHECK; + + if (!JNI::haveSurface()) + return; + + if (!_force_redraw && + !_game_texture->dirty() && + !_overlay_texture->dirty() && + !_mouse_texture->dirty()) + return; + + _force_redraw = false; + + // clear pointer leftovers in dead areas + if (_show_overlay && !_fullscreen) + clearScreen(kClear); + + GLCALL(glPushMatrix()); + + if (_shake_offset != 0 || + (!_focus_rect.isEmpty() && + !Common::Rect(_game_texture->width(), + _game_texture->height()).contains(_focus_rect))) { + // These are the only cases where _game_texture doesn't + // cover the entire screen. + clearScreen(kClear); + + // Move everything up by _shake_offset (game) pixels + GLCALL(glTranslatex(0, -_shake_offset << 16, 0)); + } + +// TODO this doesnt work on those sucky drivers, do it differently +// if (_show_overlay) +// GLCALL(glColor4ub(0x9f, 0x9f, 0x9f, 0x9f)); + + if (_focus_rect.isEmpty()) { + _game_texture->drawTextureRect(); + } else { + GLCALL(glPushMatrix()); + + GLCALL(glScalex(xdiv(_egl_surface_width, _focus_rect.width()), + xdiv(_egl_surface_height, _focus_rect.height()), + 1 << 16)); + GLCALL(glTranslatex(-_focus_rect.left << 16, + -_focus_rect.top << 16, 0)); + GLCALL(glScalex(xdiv(_game_texture->width(), _egl_surface_width), + xdiv(_game_texture->height(), _egl_surface_height), + 1 << 16)); + + _game_texture->drawTextureRect(); + + GLCALL(glPopMatrix()); + } + + int cs = _mouse_targetscale; + + if (_show_overlay) { +// TODO see above +// GLCALL(glColor4ub(0xff, 0xff, 0xff, 0xff)); + + // ugly, but the modern theme sets a wacko factor, only god knows why + cs = 1; + + GLCALL(_overlay_texture->drawTextureRect()); + } + + if (_show_mouse) { + GLCALL(glPushMatrix()); + + const Common::Point &mouse = getEventManager()->getMousePos(); + + // Scale up ScummVM -> OpenGL (pixel) coordinates + if (_show_overlay) { + GLCALL(glScalex(xdiv(_egl_surface_width, + _overlay_texture->width()), + xdiv(_egl_surface_height, + _overlay_texture->height()), + 1 << 16)); + } else { + const Common::Rect &r = _game_texture->getDrawRect(); + + GLCALL(glTranslatex(r.left << 16, + r.top << 16, + 0)); + GLCALL(glScalex(xdiv(r.width(), _game_texture->width()), + xdiv(r.height(), _game_texture->height()), + 1 << 16)); + } + + GLCALL(glTranslatex((-_mouse_hotspot.x * cs) << 16, + (-_mouse_hotspot.y * cs) << 16, + 0)); + + // Note the extra half texel to position the mouse in + // the middle of the x,y square: + GLCALL(glTranslatex((mouse.x << 16) | 1 << 15, + (mouse.y << 16) | 1 << 15, 0)); + + GLCALL(glScalex(cs << 16, cs << 16, 1 << 16)); + + _mouse_texture->drawTextureOrigin(); + + GLCALL(glPopMatrix()); + } + + GLCALL(glPopMatrix()); + + if (!JNI::swapBuffers()) + LOGW("swapBuffers failed: 0x%x", glGetError()); +} + +Graphics::Surface *OSystem_Android::lockScreen() { + ENTER(); + + GLTHREADCHECK; + + Graphics::Surface *surface = _game_texture->surface(); + assert(surface->pixels); + + return surface; +} + +void OSystem_Android::unlockScreen() { + ENTER(); + + GLTHREADCHECK; + + assert(_game_texture->dirty()); +} + +void OSystem_Android::setShakePos(int shake_offset) { + ENTER("%d", shake_offset); + + if (_shake_offset != shake_offset) { + _shake_offset = shake_offset; + _force_redraw = true; + } +} + +void OSystem_Android::fillScreen(uint32 col) { + ENTER("%u", col); + + GLTHREADCHECK; + + _game_texture->fillBuffer(col); +} + +void OSystem_Android::setFocusRectangle(const Common::Rect& rect) { + ENTER("%d, %d, %d, %d", rect.left, rect.top, rect.right, rect.bottom); + + if (_enable_zoning) { + _focus_rect = rect; + _force_redraw = true; + } +} + +void OSystem_Android::clearFocusRectangle() { + ENTER(); + + if (_enable_zoning) { + _focus_rect = Common::Rect(); + _force_redraw = true; + } +} + +void OSystem_Android::showOverlay() { + ENTER(); + + _show_overlay = true; + _force_redraw = true; + + updateEventScale(); + + warpMouse(_overlay_texture->width() / 2, _overlay_texture->height() / 2); + + GLCALL(glDisable(GL_SCISSOR_TEST)); +} + +void OSystem_Android::hideOverlay() { + ENTER(); + + clearScreen(kClear); + + _show_overlay = false; + _force_redraw = true; + + updateEventScale(); + + warpMouse(_game_texture->width() / 2, _game_texture->height() / 2); + + GLCALL(glEnable(GL_SCISSOR_TEST)); +} + +void OSystem_Android::clearOverlay() { + ENTER(); + + GLTHREADCHECK; + + _overlay_texture->fillBuffer(0); + + // breaks more than it fixes, disabled for now + // Shouldn't need this, but works around a 'blank screen' bug on Nexus1 + //updateScreen(); +} + +void OSystem_Android::grabOverlay(OverlayColor *buf, int pitch) { + ENTER("%p, %d", buf, pitch); + + GLTHREADCHECK; + + const Graphics::Surface *surface = _overlay_texture->surface_const(); + assert(surface->bytesPerPixel == sizeof(buf[0])); + + const byte *src = (const byte *)surface->pixels; + uint h = surface->h; + + do { + memcpy(buf, src, surface->w * surface->bytesPerPixel); + src += surface->pitch; + // This 'pitch' is pixels not bytes + buf += pitch; + } while (--h); +} + +void OSystem_Android::copyRectToOverlay(const OverlayColor *buf, int pitch, + int x, int y, int w, int h) { + ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h); + + GLTHREADCHECK; + + // This 'pitch' is pixels not bytes + _overlay_texture->updateBuffer(x, y, w, h, buf, pitch * sizeof(buf[0])); + + // Shouldn't need this, but works around a 'blank screen' bug on Nexus1? + //updateScreen(); +} + +int16 OSystem_Android::getOverlayHeight() { + return _overlay_texture->height(); +} + +int16 OSystem_Android::getOverlayWidth() { + return _overlay_texture->width(); +} + +Graphics::PixelFormat OSystem_Android::getOverlayFormat() const { + return _overlay_texture->getPixelFormat(); +} + +bool OSystem_Android::showMouse(bool visible) { + ENTER("%d", visible); + + _show_mouse = visible; + + return true; +} + +void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, + int hotspotX, int hotspotY, + uint32 keycolor, int cursorTargetScale, + const Graphics::PixelFormat *format) { + ENTER("%p, %u, %u, %d, %d, %u, %d, %p", buf, w, h, hotspotX, hotspotY, + keycolor, cursorTargetScale, format); + + GLTHREADCHECK; + +#ifdef USE_RGB_COLOR + if (format && format->bytesPerPixel > 1) { + if (_mouse_texture != _mouse_texture_rgb) + LOGD("switching to rgb mouse cursor"); + + _mouse_texture_rgb = new GLES5551Texture(); + _mouse_texture = _mouse_texture_rgb; + } else { + if (_mouse_texture != _mouse_texture_palette) + LOGD("switching to paletted mouse cursor"); + + _mouse_texture = _mouse_texture_palette; + + delete _mouse_texture_rgb; + _mouse_texture_rgb = 0; + } +#endif + + _mouse_texture->allocBuffer(w, h); + + if (_mouse_texture == _mouse_texture_palette) { + assert(keycolor < 256); + + byte *p = _mouse_texture_palette->palette() + _mouse_keycolor * 2; + + WRITE_UINT16(p, READ_UINT16(p) | 1); + _mouse_keycolor = keycolor; + WRITE_UINT16(_mouse_texture_palette->palette() + keycolor * 2, 0); + } + + if (w == 0 || h == 0) { + _show_mouse = false; + return; + } + + if (_mouse_texture == _mouse_texture_palette) { + _mouse_texture->updateBuffer(0, 0, w, h, buf, w); + } else { + uint16 pitch = _mouse_texture->pitch(); + + byte *tmp = new byte[pitch * h]; + + // meh, a 16bit cursor without alpha bits... this is so silly + if (!crossBlit(tmp, buf, pitch, w * 2, w, h, + _mouse_texture->getPixelFormat(), + *format)) { + LOGE("crossblit failed"); + + delete[] tmp; + + _show_mouse = false; + + return; + } + + uint16 *s = (uint16 *)buf; + uint16 *d = (uint16 *)tmp; + for (uint16 y = 0; y < h; ++y, d += pitch / 2 - w) + for (uint16 x = 0; x < w; ++x, d++) + if (*s++ != (keycolor & 0xffff)) + *d |= 1; + + _mouse_texture->updateBuffer(0, 0, w, h, tmp, pitch); + + delete[] tmp; + } + + _mouse_hotspot = Common::Point(hotspotX, hotspotY); + _mouse_targetscale = cursorTargetScale; +} + +void OSystem_Android::setCursorPaletteInternal(const byte *colors, + uint start, uint num) { + const Graphics::PixelFormat &pf = + _mouse_texture_palette->getPalettePixelFormat(); + byte *p = _mouse_texture_palette->palette() + start * 2; + + for (uint i = 0; i < num; ++i, colors += 3, p += 2) + WRITE_UINT16(p, pf.RGBToColor(colors[0], colors[1], colors[2])); + + WRITE_UINT16(_mouse_texture_palette->palette() + _mouse_keycolor * 2, 0); +} + +void OSystem_Android::setCursorPalette(const byte *colors, + uint start, uint num) { + ENTER("%p, %u, %u", colors, start, num); + + GLTHREADCHECK; + + if (!_mouse_texture->hasPalette()) { + LOGD("switching to paletted mouse cursor"); + + _mouse_texture = _mouse_texture_palette; + + delete _mouse_texture_rgb; + _mouse_texture_rgb = 0; + } + + setCursorPaletteInternal(colors, start, num); + _use_mouse_palette = true; +} + +void OSystem_Android::disableCursorPalette(bool disable) { + ENTER("%d", disable); + + // when disabling the cursor palette, and we're running a clut8 game, + // it expects the game palette to be used for the cursor + if (disable && _game_texture->hasPalette()) { + const byte *src = _game_texture->palette_const(); + byte *dst = _mouse_texture_palette->palette(); + + const Graphics::PixelFormat &pf_src = + _game_texture->getPalettePixelFormat(); + const Graphics::PixelFormat &pf_dst = + _mouse_texture_palette->getPalettePixelFormat(); + + uint8 r, g, b; + + for (uint i = 0; i < 256; ++i, src += 2, dst += 2) { + pf_src.colorToRGB(READ_UINT16(src), r, g, b); + WRITE_UINT16(dst, pf_dst.RGBToColor(r, g, b)); + } + + WRITE_UINT16(_mouse_texture_palette->palette() + _mouse_keycolor * 2, 0); + } + + _use_mouse_palette = !disable; +} + +#endif + diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp new file mode 100644 index 0000000000..92cb04904c --- /dev/null +++ b/backends/platform/android/jni.cpp @@ -0,0 +1,602 @@ +/* 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$ + * + */ + +#if defined(__ANDROID__) + +#include "base/main.h" +#include "common/config-manager.h" +#include "engines/engine.h" + +#include "backends/platform/android/android.h" +#include "backends/platform/android/asset-archive.h" +#include "backends/platform/android/jni.h" + +__attribute__ ((visibility("default"))) +jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { + return JNI::onLoad(vm); +} + +JavaVM *JNI::_vm = 0; +jobject JNI::_jobj = 0; +jobject JNI::_jobj_audio_track = 0; +jobject JNI::_jobj_egl = 0; +jobject JNI::_jobj_egl_display = 0; +jobject JNI::_jobj_egl_surface = 0; + +Common::Archive *JNI::_asset_archive = 0; +OSystem_Android *JNI::_system = 0; + +bool JNI::pause = false; +sem_t JNI::pause_sem = { 0 }; + +int JNI::surface_changeid = 0; +int JNI::egl_surface_width = 0; +int JNI::egl_surface_height = 0; +bool JNI::_ready_for_events = 0; + +jmethodID JNI::_MID_getDPI = 0; +jmethodID JNI::_MID_displayMessageOnOSD = 0; +jmethodID JNI::_MID_setWindowCaption = 0; +jmethodID JNI::_MID_showVirtualKeyboard = 0; +jmethodID JNI::_MID_getSysArchives = 0; +jmethodID JNI::_MID_getPluginDirectories = 0; +jmethodID JNI::_MID_initSurface = 0; +jmethodID JNI::_MID_deinitSurface = 0; + +jmethodID JNI::_MID_EGL10_eglSwapBuffers = 0; + +jmethodID JNI::_MID_AudioTrack_flush = 0; +jmethodID JNI::_MID_AudioTrack_pause = 0; +jmethodID JNI::_MID_AudioTrack_play = 0; +jmethodID JNI::_MID_AudioTrack_stop = 0; +jmethodID JNI::_MID_AudioTrack_write = 0; + +const JNINativeMethod JNI::_natives[] = { + { "create", "(Landroid/content/res/AssetManager;" + "Ljavax/microedition/khronos/egl/EGL10;" + "Ljavax/microedition/khronos/egl/EGLDisplay;" + "Landroid/media/AudioTrack;II)V", + (void *)JNI::create }, + { "destroy", "()V", + (void *)JNI::destroy }, + { "setSurface", "(II)V", + (void *)JNI::setSurface }, + { "main", "([Ljava/lang/String;)I", + (void *)JNI::main }, + { "pushEvent", "(IIIIII)V", + (void *)JNI::pushEvent }, + { "enableZoning", "(Z)V", + (void *)JNI::enableZoning }, + { "setPause", "(Z)V", + (void *)JNI::setPause } +}; + +JNI::JNI() { +} + +JNI::~JNI() { +} + +jint JNI::onLoad(JavaVM *vm) { + _vm = vm; + + JNIEnv *env; + + if (_vm->GetEnv((void **)&env, JNI_VERSION_1_2)) + return JNI_ERR; + + jclass cls = env->FindClass("org/inodes/gus/scummvm/ScummVM"); + if (cls == 0) + return JNI_ERR; + + if (env->RegisterNatives(cls, _natives, ARRAYSIZE(_natives)) < 0) + return JNI_ERR; + + return JNI_VERSION_1_2; +} + +JNIEnv *JNI::getEnv() { + JNIEnv *env = 0; + + jint res = _vm->GetEnv((void **)&env, JNI_VERSION_1_2); + + if (res != JNI_OK) { + LOGE("GetEnv() failed: %d", res); + abort(); + } + + return env; +} + +void JNI::attachThread() { + JNIEnv *env = 0; + + jint res = _vm->AttachCurrentThread(&env, 0); + + if (res != JNI_OK) { + LOGE("AttachCurrentThread() failed: %d", res); + abort(); + } +} + +void JNI::detachThread() { + jint res = _vm->DetachCurrentThread(); + + if (res != JNI_OK) { + LOGE("DetachCurrentThread() failed: %d", res); + abort(); + } +} + +void JNI::setReadyForEvents(bool ready) { + _ready_for_events = ready; +} + +void JNI::throwByName(JNIEnv *env, const char *name, const char *msg) { + jclass cls = env->FindClass(name); + + // if cls is 0, an exception has already been thrown + if (cls != 0) + env->ThrowNew(cls, msg); + + env->DeleteLocalRef(cls); +} + +void JNI::throwRuntimeException(JNIEnv *env, const char *msg) { + throwByName(env, "java/lang/RuntimeException", msg); +} + +// calls to the dark side + +void JNI::getDPI(float *values) { + values[0] = 0.0; + values[1] = 0.0; + + JNIEnv *env = JNI::getEnv(); + + jfloatArray array = env->NewFloatArray(2); + + env->CallVoidMethod(_jobj, _MID_getDPI, array); + + if (env->ExceptionCheck()) { + LOGE("Failed to get DPIs"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + } else { + jfloat *res = env->GetFloatArrayElements(array, 0); + + if (res) { + values[0] = res[0]; + values[1] = res[1]; + + env->ReleaseFloatArrayElements(array, res, 0); + } + } + + env->DeleteLocalRef(array); +} + +void JNI::displayMessageOnOSD(const char *msg) { + JNIEnv *env = JNI::getEnv(); + jstring java_msg = env->NewStringUTF(msg); + + env->CallVoidMethod(_jobj, _MID_displayMessageOnOSD, java_msg); + + if (env->ExceptionCheck()) { + LOGE("Failed to display OSD message"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + } + + env->DeleteLocalRef(java_msg); +} + +void JNI::setWindowCaption(const char *caption) { + JNIEnv *env = JNI::getEnv(); + jstring java_caption = env->NewStringUTF(caption); + + env->CallVoidMethod(_jobj, _MID_setWindowCaption, java_caption); + + if (env->ExceptionCheck()) { + LOGE("Failed to set window caption"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + } + + env->DeleteLocalRef(java_caption); +} + +void JNI::showVirtualKeyboard(bool enable) { + JNIEnv *env = JNI::getEnv(); + + env->CallVoidMethod(_jobj, _MID_showVirtualKeyboard, enable); + + if (env->ExceptionCheck()) { + LOGE("Error trying to show virtual keyboard"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + } +} + +void JNI::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { + JNIEnv *env = JNI::getEnv(); + + s.add("ASSET", _asset_archive, priority, false); + + jobjectArray array = + (jobjectArray)env->CallObjectMethod(_jobj, _MID_getSysArchives); + + if (env->ExceptionCheck()) { + LOGE("Error finding system archive path"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + + return; + } + + jsize size = env->GetArrayLength(array); + for (jsize i = 0; i < size; ++i) { + jstring path_obj = (jstring)env->GetObjectArrayElement(array, i); + const char *path = env->GetStringUTFChars(path_obj, 0); + + if (path != 0) { + s.addDirectory(path, path, priority); + env->ReleaseStringUTFChars(path_obj, path); + } + + env->DeleteLocalRef(path_obj); + } +} + +void JNI::getPluginDirectories(Common::FSList &dirs) { + JNIEnv *env = JNI::getEnv(); + + jobjectArray array = + (jobjectArray)env->CallObjectMethod(_jobj, _MID_getPluginDirectories); + + if (env->ExceptionCheck()) { + LOGE("Error finding plugin directories"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + + return; + } + + jsize size = env->GetArrayLength(array); + for (jsize i = 0; i < size; ++i) { + jstring path_obj = (jstring)env->GetObjectArrayElement(array, i); + + if (path_obj == 0) + continue; + + const char *path = env->GetStringUTFChars(path_obj, 0); + + if (path == 0) { + LOGE("Error getting string characters from plugin directory"); + + env->ExceptionClear(); + env->DeleteLocalRef(path_obj); + + continue; + } + + dirs.push_back(Common::FSNode(path)); + + env->ReleaseStringUTFChars(path_obj, path); + env->DeleteLocalRef(path_obj); + } +} + +bool JNI::initSurface() { + JNIEnv *env = JNI::getEnv(); + + jobject obj = env->CallObjectMethod(_jobj, _MID_initSurface); + + if (!obj || env->ExceptionCheck()) { + LOGE("initSurface failed"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + + return false; + } + + _jobj_egl_surface = env->NewGlobalRef(obj); + + return true; +} + +void JNI::deinitSurface() { + JNIEnv *env = JNI::getEnv(); + + env->CallVoidMethod(_jobj, _MID_deinitSurface); + + if (env->ExceptionCheck()) { + LOGE("deinitSurface failed"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + } + + env->DeleteGlobalRef(_jobj_egl_surface); + _jobj_egl_surface = 0; +} + +void JNI::setAudioPause() { + JNIEnv *env = JNI::getEnv(); + + env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_flush); + + if (env->ExceptionCheck()) { + LOGE("Error flushing AudioTrack"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + } + + env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_pause); + + if (env->ExceptionCheck()) { + LOGE("Error setting AudioTrack: pause"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + } +} + +void JNI::setAudioPlay() { + JNIEnv *env = JNI::getEnv(); + + env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_play); + + if (env->ExceptionCheck()) { + LOGE("Error setting AudioTrack: play"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + } +} + +void JNI::setAudioStop() { + JNIEnv *env = JNI::getEnv(); + + env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_stop); + + if (env->ExceptionCheck()) { + LOGE("Error setting AudioTrack: stop"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + } +} + +// natives for the dark side + +void JNI::create(JNIEnv *env, jobject self, jobject asset_manager, + jobject egl, jobject egl_display, + jobject at, jint audio_sample_rate, jint audio_buffer_size) { + assert(!_system); + + pause = false; + // initial value of zero! + sem_init(&pause_sem, 0, 0); + + _asset_archive = new AndroidAssetArchive(asset_manager); + assert(_asset_archive); + + _system = new OSystem_Android(audio_sample_rate, audio_buffer_size); + assert(_system); + + // weak global ref to allow class to be unloaded + // ... except dalvik implements NewWeakGlobalRef only on froyo + //_jobj = env->NewWeakGlobalRef(self); + + _jobj = env->NewGlobalRef(self); + + jclass cls = env->GetObjectClass(_jobj); + +#define FIND_METHOD(prefix, name, signature) do { \ + _MID_ ## prefix ## name = env->GetMethodID(cls, #name, signature); \ + if (_MID_ ## prefix ## name == 0) \ + return; \ + } while (0) + + FIND_METHOD(, setWindowCaption, "(Ljava/lang/String;)V"); + FIND_METHOD(, getDPI, "([F)V"); + FIND_METHOD(, displayMessageOnOSD, "(Ljava/lang/String;)V"); + FIND_METHOD(, showVirtualKeyboard, "(Z)V"); + FIND_METHOD(, getSysArchives, "()[Ljava/lang/String;"); + FIND_METHOD(, getPluginDirectories, "()[Ljava/lang/String;"); + FIND_METHOD(, initSurface, "()Ljavax/microedition/khronos/egl/EGLSurface;"); + FIND_METHOD(, deinitSurface, "()V"); + + _jobj_egl = env->NewGlobalRef(egl); + _jobj_egl_display = env->NewGlobalRef(egl_display); + + cls = env->GetObjectClass(_jobj_egl); + + FIND_METHOD(EGL10_, eglSwapBuffers, + "(Ljavax/microedition/khronos/egl/EGLDisplay;" + "Ljavax/microedition/khronos/egl/EGLSurface;)Z"); + + _jobj_audio_track = env->NewGlobalRef(at); + + cls = env->GetObjectClass(_jobj_audio_track); + + FIND_METHOD(AudioTrack_, flush, "()V"); + FIND_METHOD(AudioTrack_, pause, "()V"); + FIND_METHOD(AudioTrack_, play, "()V"); + FIND_METHOD(AudioTrack_, stop, "()V"); + FIND_METHOD(AudioTrack_, write, "([BII)I"); + +#undef FIND_METHOD + + g_system = _system; +} + +void JNI::destroy(JNIEnv *env, jobject self) { + delete _asset_archive; + _asset_archive = 0; + + delete _system; + g_system = 0; + _system = 0; + + sem_destroy(&pause_sem); + + // see above + //JNI::getEnv()->DeleteWeakGlobalRef(_jobj); + + JNI::getEnv()->DeleteGlobalRef(_jobj_egl_display); + JNI::getEnv()->DeleteGlobalRef(_jobj_egl); + JNI::getEnv()->DeleteGlobalRef(_jobj_audio_track); + JNI::getEnv()->DeleteGlobalRef(_jobj); +} + +void JNI::setSurface(JNIEnv *env, jobject self, jint width, jint height) { + egl_surface_width = width; + egl_surface_height = height; + surface_changeid++; +} + +jint JNI::main(JNIEnv *env, jobject self, jobjectArray args) { + assert(_system); + + const int MAX_NARGS = 32; + int res = -1; + + int argc = env->GetArrayLength(args); + if (argc > MAX_NARGS) { + throwByName(env, "java/lang/IllegalArgumentException", + "too many arguments"); + return 0; + } + + char *argv[MAX_NARGS]; + + // note use in cleanup loop below + int nargs; + + for (nargs = 0; nargs < argc; ++nargs) { + jstring arg = (jstring)env->GetObjectArrayElement(args, nargs); + + if (arg == 0) { + argv[nargs] = 0; + } else { + const char *cstr = env->GetStringUTFChars(arg, 0); + + argv[nargs] = const_cast<char *>(cstr); + + // exception already thrown? + if (cstr == 0) + goto cleanup; + } + + env->DeleteLocalRef(arg); + } + +#ifdef DYNAMIC_MODULES + PluginManager::instance().addPluginProvider(new AndroidPluginProvider()); +#endif + + LOGI("Entering scummvm_main with %d args", argc); + + res = scummvm_main(argc, argv); + + LOGI("scummvm_main exited with code %d", res); + + _system->quit(); + +cleanup: + nargs--; + + for (int i = 0; i < nargs; ++i) { + if (argv[i] == 0) + continue; + + jstring arg = (jstring)env->GetObjectArrayElement(args, nargs); + + // Exception already thrown? + if (arg == 0) + return res; + + env->ReleaseStringUTFChars(arg, argv[i]); + env->DeleteLocalRef(arg); + } + + return res; +} + +void JNI::pushEvent(JNIEnv *env, jobject self, int type, int arg1, int arg2, + int arg3, int arg4, int arg5) { + // drop events until we're ready and after we quit + if (!_ready_for_events) { + LOGW("dropping event"); + return; + } + + assert(_system); + + _system->pushEvent(type, arg1, arg2, arg3, arg4, arg5); +} + +void JNI::enableZoning(JNIEnv *env, jobject self, jboolean enable) { + assert(_system); + + _system->enableZoning(enable); +} + +void JNI::setPause(JNIEnv *env, jobject self, jboolean value) { + if (!_system) + return; + + if (g_engine) { + LOGD("pauseEngine: %d", value); + + g_engine->pauseEngine(value); + + if (value && + g_engine->hasFeature(Engine::kSupportsSavingDuringRuntime) && + g_engine->canSaveGameStateCurrently()) + g_engine->saveGameState(0, "Android parachute"); + } + + pause = value; + + if (!pause) { + // wake up all threads + for (uint i = 0; i < 3; ++i) + sem_post(&pause_sem); + } +} + +#endif + diff --git a/backends/platform/android/jni.h b/backends/platform/android/jni.h new file mode 100644 index 0000000000..d029f1a2a8 --- /dev/null +++ b/backends/platform/android/jni.h @@ -0,0 +1,151 @@ +/* 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 _ANDROID_JNI_H_ +#define _ANDROID_JNI_H_ + +#if defined(__ANDROID__) + +#include <jni.h> +#include <semaphore.h> + +#include "common/fs.h" +#include "common/archive.h" + +class OSystem_Android; + +class JNI { +private: + JNI(); + virtual ~JNI(); + +public: + static bool pause; + static sem_t pause_sem; + + static int surface_changeid; + static int egl_surface_width; + static int egl_surface_height; + + static jint onLoad(JavaVM *vm); + + static JNIEnv *getEnv(); + + static void attachThread(); + static void detachThread(); + + static void setReadyForEvents(bool ready); + + static void getPluginDirectories(Common::FSList &dirs); + static void setWindowCaption(const char *caption); + static void getDPI(float *values); + static void displayMessageOnOSD(const char *msg); + static void showVirtualKeyboard(bool enable); + static void addSysArchivesToSearchSet(Common::SearchSet &s, int priority); + + static inline bool haveSurface(); + static inline bool swapBuffers(); + static bool initSurface(); + static void deinitSurface(); + + static void setAudioPause(); + static void setAudioPlay(); + static void setAudioStop(); + + static inline int writeAudio(JNIEnv *env, jbyteArray &data, int offset, + int size); + +private: + static JavaVM *_vm; + // back pointer to (java) peer instance + static jobject _jobj; + static jobject _jobj_audio_track; + static jobject _jobj_egl; + static jobject _jobj_egl_display; + static jobject _jobj_egl_surface; + + static Common::Archive *_asset_archive; + static OSystem_Android *_system; + + static bool _ready_for_events; + + static jmethodID _MID_getDPI; + static jmethodID _MID_displayMessageOnOSD; + static jmethodID _MID_setWindowCaption; + static jmethodID _MID_showVirtualKeyboard; + static jmethodID _MID_getSysArchives; + static jmethodID _MID_getPluginDirectories; + static jmethodID _MID_initSurface; + static jmethodID _MID_deinitSurface; + + static jmethodID _MID_EGL10_eglSwapBuffers; + + static jmethodID _MID_AudioTrack_flush; + static jmethodID _MID_AudioTrack_pause; + static jmethodID _MID_AudioTrack_play; + static jmethodID _MID_AudioTrack_stop; + static jmethodID _MID_AudioTrack_write; + + static const JNINativeMethod _natives[]; + + static void throwByName(JNIEnv *env, const char *name, const char *msg); + static void throwRuntimeException(JNIEnv *env, const char *msg); + + // natives for the dark side + static void create(JNIEnv *env, jobject self, jobject asset_manager, + jobject egl, jobject egl_display, + jobject at, jint audio_sample_rate, + jint audio_buffer_size); + static void destroy(JNIEnv *env, jobject self); + + static void setSurface(JNIEnv *env, jobject self, jint width, jint height); + static jint main(JNIEnv *env, jobject self, jobjectArray args); + + static void pushEvent(JNIEnv *env, jobject self, int type, int arg1, + int arg2, int arg3, int arg4, int arg5); + static void enableZoning(JNIEnv *env, jobject self, jboolean enable); + + static void setPause(JNIEnv *env, jobject self, jboolean value); +}; + +inline bool JNI::haveSurface() { + return _jobj_egl_surface != 0; +} + +inline bool JNI::swapBuffers() { + JNIEnv *env = JNI::getEnv(); + + return env->CallBooleanMethod(_jobj_egl, _MID_EGL10_eglSwapBuffers, + _jobj_egl_display, _jobj_egl_surface); +} + +inline int JNI::writeAudio(JNIEnv *env, jbyteArray &data, int offset, int size) { + return env->CallIntMethod(_jobj_audio_track, _MID_AudioTrack_write, data, + offset, size); +} + +#endif +#endif + diff --git a/backends/platform/android/module.mk b/backends/platform/android/module.mk index 8b120b21ff..2fe4b40585 100644 --- a/backends/platform/android/module.mk +++ b/backends/platform/android/module.mk @@ -1,9 +1,12 @@ MODULE := backends/platform/android MODULE_OBJS := \ - android.o \ + jni.o \ + texture.o \ asset-archive.o \ - video.o + android.o \ + gfx.o \ + events.o # We don't use rules.mk but rather manually update OBJS and MODULE_DIRS. MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) diff --git a/backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java b/backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java index 5b71d4a3a5..cede7eedd4 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java +++ b/backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java @@ -19,13 +19,13 @@ public class EditableSurfaceView extends SurfaceView { } public EditableSurfaceView(Context context, AttributeSet attrs, - int defStyle) { + int defStyle) { super(context, attrs, defStyle); } @Override public boolean onCheckIsTextEditor() { - return true; + return false; } private class MyInputConnection extends BaseInputConnection { @@ -40,7 +40,9 @@ public class EditableSurfaceView extends SurfaceView { getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(getWindowToken(), 0); } - return super.performEditorAction(actionCode); // Sends enter key + + // Sends enter key + return super.performEditorAction(actionCode); } } @@ -49,11 +51,12 @@ public class EditableSurfaceView extends SurfaceView { outAttrs.initialCapsMode = 0; outAttrs.initialSelEnd = outAttrs.initialSelStart = -1; outAttrs.inputType = (InputType.TYPE_CLASS_TEXT | - InputType.TYPE_TEXT_VARIATION_NORMAL | - InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE); + InputType.TYPE_TEXT_VARIATION_NORMAL | + InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE); outAttrs.imeOptions = (EditorInfo.IME_ACTION_DONE | - EditorInfo.IME_FLAG_NO_EXTRACT_UI); + EditorInfo.IME_FLAG_NO_EXTRACT_UI); return new MyInputConnection(); } } + diff --git a/backends/platform/android/org/inodes/gus/scummvm/Event.java b/backends/platform/android/org/inodes/gus/scummvm/Event.java deleted file mode 100644 index f9c7aba93b..0000000000 --- a/backends/platform/android/org/inodes/gus/scummvm/Event.java +++ /dev/null @@ -1,330 +0,0 @@ -package org.inodes.gus.scummvm; - -import android.view.KeyEvent; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -public class Event { - // Common::EventType enum. - // Must be kept in sync with common/events.h - public final static int EVENT_INVALID = 0; - public final static int EVENT_KEYDOWN = 1; - public final static int EVENT_KEYUP = 2; - public final static int EVENT_MOUSEMOVE = 3; - public final static int EVENT_LBUTTONDOWN = 4; - public final static int EVENT_LBUTTONUP = 5; - public final static int EVENT_RBUTTONDOWN = 6; - public final static int EVENT_RBUTTONUP = 7; - public final static int EVENT_WHEELUP = 8; - public final static int EVENT_WHEELDOWN = 9; - public final static int EVENT_QUIT = 10; - public final static int EVENT_SCREEN_CHANGED = 11; - public final static int EVENT_PREDICTIVE_DIALOG = 12; - public final static int EVENT_MBUTTONDOWN = 13; - public final static int EVENT_MBUTTONUP = 14; - public final static int EVENT_MAINMENU = 15; - public final static int EVENT_RTL = 16; - - // common/keyboard.h - public final static int ASCII_F1 = 315; - public final static int ASCII_F2 = 316; - public final static int ASCII_F3 = 317; - public final static int ASCII_F4 = 318; - public final static int ASCII_F5 = 319; - public final static int ASCII_F6 = 320; - public final static int ASCII_F7 = 321; - public final static int ASCII_F8 = 322; - public final static int ASCII_F9 = 323; - public final static int ASCII_F10 = 324; - public final static int ASCII_F11 = 325; - public final static int ASCII_F12 = 326; - public final static int KBD_CTRL = 1 << 0; - public final static int KBD_ALT = 1 << 1; - public final static int KBD_SHIFT = 1 << 2; - - public final static int KEYCODE_INVALID = 0; - public final static int KEYCODE_BACKSPACE = 8; - public final static int KEYCODE_TAB = 9; - public final static int KEYCODE_CLEAR = 12; - public final static int KEYCODE_RETURN = 13; - public final static int KEYCODE_PAUSE = 19; - public final static int KEYCODE_ESCAPE = 27; - public final static int KEYCODE_SPACE = 32; - public final static int KEYCODE_EXCLAIM = 33; - public final static int KEYCODE_QUOTEDBL = 34; - public final static int KEYCODE_HASH = 35; - public final static int KEYCODE_DOLLAR = 36; - public final static int KEYCODE_AMPERSAND = 38; - public final static int KEYCODE_QUOTE = 39; - public final static int KEYCODE_LEFTPAREN = 40; - public final static int KEYCODE_RIGHTPAREN = 41; - public final static int KEYCODE_ASTERISK = 42; - public final static int KEYCODE_PLUS = 43; - public final static int KEYCODE_COMMA = 44; - public final static int KEYCODE_MINUS = 45; - public final static int KEYCODE_PERIOD = 46; - public final static int KEYCODE_SLASH = 47; - public final static int KEYCODE_0 = 48; - public final static int KEYCODE_1 = 49; - public final static int KEYCODE_2 = 50; - public final static int KEYCODE_3 = 51; - public final static int KEYCODE_4 = 52; - public final static int KEYCODE_5 = 53; - public final static int KEYCODE_6 = 54; - public final static int KEYCODE_7 = 55; - public final static int KEYCODE_8 = 56; - public final static int KEYCODE_9 = 57; - public final static int KEYCODE_COLON = 58; - public final static int KEYCODE_SEMICOLON = 59; - public final static int KEYCODE_LESS = 60; - public final static int KEYCODE_EQUALS = 61; - public final static int KEYCODE_GREATER = 62; - public final static int KEYCODE_QUESTION = 63; - public final static int KEYCODE_AT = 64; - public final static int KEYCODE_LEFTBRACKET = 91; - public final static int KEYCODE_BACKSLASH = 92; - public final static int KEYCODE_RIGHTBRACKET = 93; - public final static int KEYCODE_CARET = 94; - public final static int KEYCODE_UNDERSCORE = 95; - public final static int KEYCODE_BACKQUOTE = 96; - public final static int KEYCODE_a = 97; - public final static int KEYCODE_b = 98; - public final static int KEYCODE_c = 99; - public final static int KEYCODE_d = 100; - public final static int KEYCODE_e = 101; - public final static int KEYCODE_f = 102; - public final static int KEYCODE_g = 103; - public final static int KEYCODE_h = 104; - public final static int KEYCODE_i = 105; - public final static int KEYCODE_j = 106; - public final static int KEYCODE_k = 107; - public final static int KEYCODE_l = 108; - public final static int KEYCODE_m = 109; - public final static int KEYCODE_n = 110; - public final static int KEYCODE_o = 111; - public final static int KEYCODE_p = 112; - public final static int KEYCODE_q = 113; - public final static int KEYCODE_r = 114; - public final static int KEYCODE_s = 115; - public final static int KEYCODE_t = 116; - public final static int KEYCODE_u = 117; - public final static int KEYCODE_v = 118; - public final static int KEYCODE_w = 119; - public final static int KEYCODE_x = 120; - public final static int KEYCODE_y = 121; - public final static int KEYCODE_z = 122; - public final static int KEYCODE_DELETE = 127; - // Numeric keypad - public final static int KEYCODE_KP0 = 256; - public final static int KEYCODE_KP1 = 257; - public final static int KEYCODE_KP2 = 258; - public final static int KEYCODE_KP3 = 259; - public final static int KEYCODE_KP4 = 260; - public final static int KEYCODE_KP5 = 261; - public final static int KEYCODE_KP6 = 262; - public final static int KEYCODE_KP7 = 263; - public final static int KEYCODE_KP8 = 264; - public final static int KEYCODE_KP9 = 265; - public final static int KEYCODE_KP_PERIOD = 266; - public final static int KEYCODE_KP_DIVIDE = 267; - public final static int KEYCODE_KP_MULTIPLY = 268; - public final static int KEYCODE_KP_MINUS = 269; - public final static int KEYCODE_KP_PLUS = 270; - public final static int KEYCODE_KP_ENTER = 271; - public final static int KEYCODE_KP_EQUALS = 272; - // Arrows + Home/End pad - public final static int KEYCODE_UP = 273; - public final static int KEYCODE_DOWN = 274; - public final static int KEYCODE_RIGHT = 275; - public final static int KEYCODE_LEFT = 276; - public final static int KEYCODE_INSERT = 277; - public final static int KEYCODE_HOME = 278; - public final static int KEYCODE_END = 279; - public final static int KEYCODE_PAGEUP = 280; - public final static int KEYCODE_PAGEDOWN = 281; - // Function keys - public final static int KEYCODE_F1 = 282; - public final static int KEYCODE_F2 = 283; - public final static int KEYCODE_F3 = 284; - public final static int KEYCODE_F4 = 285; - public final static int KEYCODE_F5 = 286; - public final static int KEYCODE_F6 = 287; - public final static int KEYCODE_F7 = 288; - public final static int KEYCODE_F8 = 289; - public final static int KEYCODE_F9 = 290; - public final static int KEYCODE_F10 = 291; - public final static int KEYCODE_F11 = 292; - public final static int KEYCODE_F12 = 293; - public final static int KEYCODE_F13 = 294; - public final static int KEYCODE_F14 = 295; - public final static int KEYCODE_F15 = 296; - // Key state modifier keys - public final static int KEYCODE_NUMLOCK = 300; - public final static int KEYCODE_CAPSLOCK = 301; - public final static int KEYCODE_SCROLLOCK = 302; - public final static int KEYCODE_RSHIFT = 303; - public final static int KEYCODE_LSHIFT = 304; - public final static int KEYCODE_RCTRL = 305; - public final static int KEYCODE_LCTRL = 306; - public final static int KEYCODE_RALT = 307; - public final static int KEYCODE_LALT = 308; - public final static int KEYCODE_RMETA = 309; - public final static int KEYCODE_LMETA = 310; - public final static int KEYCODE_LSUPER = 311; // Left "Windows" key - public final static int KEYCODE_RSUPER = 312; // Right "Windows" key - public final static int KEYCODE_MODE = 313; // "Alt Gr" key - public final static int KEYCODE_COMPOSE = 314; // Multi-key compose key - // Miscellaneous function keys - public final static int KEYCODE_HELP = 315; - public final static int KEYCODE_PRINT = 316; - public final static int KEYCODE_SYSREQ = 317; - public final static int KEYCODE_BREAK = 318; - public final static int KEYCODE_MENU = 319; - public final static int KEYCODE_POWER = 320; // Power Macintosh power key - public final static int KEYCODE_EURO = 321; // Some european keyboards - public final static int KEYCODE_UNDO = 322; // Atari keyboard has Undo - - // Android KeyEvent keycode -> ScummVM keycode - public final static Map<Integer, Integer> androidKeyMap; - static { - Map<Integer, Integer> map = new HashMap<Integer, Integer>(); - - map.put(KeyEvent.KEYCODE_DEL, KEYCODE_BACKSPACE); - map.put(KeyEvent.KEYCODE_TAB, KEYCODE_TAB); - map.put(KeyEvent.KEYCODE_CLEAR, KEYCODE_CLEAR); - map.put(KeyEvent.KEYCODE_ENTER, KEYCODE_RETURN); - //map.put(??, KEYCODE_PAUSE); - map.put(KeyEvent.KEYCODE_BACK, KEYCODE_ESCAPE); - map.put(KeyEvent.KEYCODE_SPACE, KEYCODE_SPACE); - //map.put(??, KEYCODE_EXCLAIM); - //map.put(??, KEYCODE_QUOTEDBL); - map.put(KeyEvent.KEYCODE_POUND, KEYCODE_HASH); - //map.put(??, KEYCODE_DOLLAR); - //map.put(??, KEYCODE_AMPERSAND); - map.put(KeyEvent.KEYCODE_APOSTROPHE, KEYCODE_QUOTE); - //map.put(??, KEYCODE_LEFTPAREN); - //map.put(??, KEYCODE_RIGHTPAREN); - //map.put(??, KEYCODE_ASTERISK); - map.put(KeyEvent.KEYCODE_PLUS, KEYCODE_PLUS); - map.put(KeyEvent.KEYCODE_COMMA, KEYCODE_COMMA); - map.put(KeyEvent.KEYCODE_MINUS, KEYCODE_MINUS); - map.put(KeyEvent.KEYCODE_PERIOD, KEYCODE_PERIOD); - map.put(KeyEvent.KEYCODE_SLASH, KEYCODE_SLASH); - map.put(KeyEvent.KEYCODE_0, KEYCODE_0); - map.put(KeyEvent.KEYCODE_1, KEYCODE_1); - map.put(KeyEvent.KEYCODE_2, KEYCODE_2); - map.put(KeyEvent.KEYCODE_3, KEYCODE_3); - map.put(KeyEvent.KEYCODE_4, KEYCODE_4); - map.put(KeyEvent.KEYCODE_5, KEYCODE_5); - map.put(KeyEvent.KEYCODE_6, KEYCODE_6); - map.put(KeyEvent.KEYCODE_7, KEYCODE_7); - map.put(KeyEvent.KEYCODE_8, KEYCODE_8); - map.put(KeyEvent.KEYCODE_9, KEYCODE_9); - //map.put(??, KEYCODE_COLON); - map.put(KeyEvent.KEYCODE_SEMICOLON, KEYCODE_SEMICOLON); - //map.put(??, KEYCODE_LESS); - map.put(KeyEvent.KEYCODE_EQUALS, KEYCODE_EQUALS); - //map.put(??, KEYCODE_GREATER); - //map.put(??, KEYCODE_QUESTION); - map.put(KeyEvent.KEYCODE_AT, KEYCODE_AT); - map.put(KeyEvent.KEYCODE_LEFT_BRACKET, KEYCODE_LEFTBRACKET); - map.put(KeyEvent.KEYCODE_BACKSLASH, KEYCODE_BACKSLASH); - map.put(KeyEvent.KEYCODE_RIGHT_BRACKET, KEYCODE_RIGHTBRACKET); - //map.put(??, KEYCODE_CARET); - //map.put(??, KEYCODE_UNDERSCORE); - //map.put(??, KEYCODE_BACKQUOTE); - map.put(KeyEvent.KEYCODE_A, KEYCODE_a); - map.put(KeyEvent.KEYCODE_B, KEYCODE_b); - map.put(KeyEvent.KEYCODE_C, KEYCODE_c); - map.put(KeyEvent.KEYCODE_D, KEYCODE_d); - map.put(KeyEvent.KEYCODE_E, KEYCODE_e); - map.put(KeyEvent.KEYCODE_F, KEYCODE_f); - map.put(KeyEvent.KEYCODE_G, KEYCODE_g); - map.put(KeyEvent.KEYCODE_H, KEYCODE_h); - map.put(KeyEvent.KEYCODE_I, KEYCODE_i); - map.put(KeyEvent.KEYCODE_J, KEYCODE_j); - map.put(KeyEvent.KEYCODE_K, KEYCODE_k); - map.put(KeyEvent.KEYCODE_L, KEYCODE_l); - map.put(KeyEvent.KEYCODE_M, KEYCODE_m); - map.put(KeyEvent.KEYCODE_N, KEYCODE_n); - map.put(KeyEvent.KEYCODE_O, KEYCODE_o); - map.put(KeyEvent.KEYCODE_P, KEYCODE_p); - map.put(KeyEvent.KEYCODE_Q, KEYCODE_q); - map.put(KeyEvent.KEYCODE_R, KEYCODE_r); - map.put(KeyEvent.KEYCODE_S, KEYCODE_s); - map.put(KeyEvent.KEYCODE_T, KEYCODE_t); - map.put(KeyEvent.KEYCODE_U, KEYCODE_u); - map.put(KeyEvent.KEYCODE_V, KEYCODE_v); - map.put(KeyEvent.KEYCODE_W, KEYCODE_w); - map.put(KeyEvent.KEYCODE_X, KEYCODE_x); - map.put(KeyEvent.KEYCODE_Y, KEYCODE_y); - map.put(KeyEvent.KEYCODE_Z, KEYCODE_z); - //map.put(KeyEvent.KEYCODE_DEL, KEYCODE_DELETE); use BACKSPACE instead - //map.put(??, KEYCODE_KP_*); - map.put(KeyEvent.KEYCODE_DPAD_UP, KEYCODE_UP); - map.put(KeyEvent.KEYCODE_DPAD_DOWN, KEYCODE_DOWN); - map.put(KeyEvent.KEYCODE_DPAD_RIGHT, KEYCODE_RIGHT); - map.put(KeyEvent.KEYCODE_DPAD_LEFT, KEYCODE_LEFT); - //map.put(??, KEYCODE_INSERT); - //map.put(??, KEYCODE_HOME); - //map.put(??, KEYCODE_END); - //map.put(??, KEYCODE_PAGEUP); - //map.put(??, KEYCODE_PAGEDOWN); - //map.put(??, KEYCODE_F{1-15}); - map.put(KeyEvent.KEYCODE_NUM, KEYCODE_NUMLOCK); - //map.put(??, KEYCODE_CAPSLOCK); - //map.put(??, KEYCODE_SCROLLLOCK); - map.put(KeyEvent.KEYCODE_SHIFT_RIGHT, KEYCODE_RSHIFT); - map.put(KeyEvent.KEYCODE_SHIFT_LEFT, KEYCODE_LSHIFT); - //map.put(??, KEYCODE_RCTRL); - //map.put(??, KEYCODE_LCTRL); - map.put(KeyEvent.KEYCODE_ALT_RIGHT, KEYCODE_RALT); - map.put(KeyEvent.KEYCODE_ALT_LEFT, KEYCODE_LALT); - // ?? META, SUPER - // ?? MODE, COMPOSE - // ?? HELP, PRINT, SYSREQ, BREAK, EURO, UNDO - map.put(KeyEvent.KEYCODE_MENU, KEYCODE_MENU); - map.put(KeyEvent.KEYCODE_POWER, KEYCODE_POWER); - - androidKeyMap = Collections.unmodifiableMap(map); - } - - public int type; - public boolean synthetic; - public int kbd_keycode; - public int kbd_ascii; - public int kbd_flags; - public int mouse_x; - public int mouse_y; - public boolean mouse_relative; // Used for trackball events - - public Event() { - type = EVENT_INVALID; - synthetic = false; - } - - public Event(int type) { - this.type = type; - synthetic = false; - } - - public static Event KeyboardEvent(int type, int keycode, int ascii, - int flags) { - Event e = new Event(); - e.type = type; - e.kbd_keycode = keycode; - e.kbd_ascii = ascii; - e.kbd_flags = flags; - return e; - } - - public static Event MouseEvent(int type, int x, int y) { - Event e = new Event(); - e.type = type; - e.mouse_x = x; - e.mouse_y = y; - return e; - } -} diff --git a/backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java b/backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java index c94ab0a3ff..3c91d9f5dc 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java +++ b/backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java @@ -28,7 +28,7 @@ public class PluginProvider extends BroadcastReceiver { try { info = context.getPackageManager() .getReceiverInfo(new ComponentName(context, this.getClass()), - PackageManager.GET_META_DATA); + PackageManager.GET_META_DATA); } catch (PackageManager.NameNotFoundException e) { Log.e(LOG_TAG, "Error finding my own info?", e); return; @@ -38,17 +38,17 @@ public class PluginProvider extends BroadcastReceiver { if (mylib != null) { ArrayList<String> all_libs = extras.getStringArrayList(ScummVMApplication.EXTRA_UNPACK_LIBS); - all_libs.add(new Uri.Builder() - .scheme("plugin") - .authority(context.getPackageName()) - .path(mylib) - .toString()); + .scheme("plugin") + .authority(context.getPackageName()) + .path(mylib) + .toString()); extras.putStringArrayList(ScummVMApplication.EXTRA_UNPACK_LIBS, - all_libs); + all_libs); } setResultExtras(extras); } } + diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java index 0e905f43a5..fe225af48b 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java @@ -1,446 +1,427 @@ package org.inodes.gus.scummvm; -import android.content.Context; +import android.util.Log; import android.content.res.AssetManager; +import android.view.SurfaceHolder; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTrack; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Process; -import android.util.Log; -import android.view.Surface; -import android.view.SurfaceHolder; -import javax.microedition.khronos.opengles.GL; import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.egl.EGL10; -import javax.microedition.khronos.egl.EGL11; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.egl.EGLSurface; import java.io.File; -import java.util.concurrent.Semaphore; -import java.util.Map; import java.util.LinkedHashMap; +public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { + final protected static String LOG_TAG = "ScummVM"; + final private AssetManager _asset_manager; + final private Object _sem_surface; + + private EGL10 _egl; + private EGLDisplay _egl_display = EGL10.EGL_NO_DISPLAY; + private EGLConfig _egl_config; + private EGLContext _egl_context = EGL10.EGL_NO_CONTEXT; + private EGLSurface _egl_surface = EGL10.EGL_NO_SURFACE; + + private SurfaceHolder _surface_holder; + private AudioTrack _audio_track; + private int _sample_rate = 0; + private int _buffer_size = 0; + + private String[] _args; + + final private native void create(AssetManager _asset_manager, + EGL10 egl, EGLDisplay egl_display, + AudioTrack audio_track, + int sample_rate, int buffer_size); + final private native void destroy(); + final private native void setSurface(int width, int height); + final private native int main(String[] args); + + // pause the engine and all native threads + final public native void setPause(boolean pause); + final public native void enableZoning(boolean enable); + // Feed an event to ScummVM. Safe to call from other threads. + final public native void pushEvent(int type, int arg1, int arg2, int arg3, + int arg4, int arg5); -// At least in Android 2.1, eglCreateWindowSurface() requires an -// EGLNativeWindowSurface object, which is hidden deep in the bowels -// of libui. Until EGL is properly exposed, it's probably safer to -// use the Java versions of most EGL functions :( - -public class ScummVM implements SurfaceHolder.Callback { - protected final static String LOG_TAG = "ScummVM"; + // Callbacks from C++ peer instance + abstract protected void getDPI(float[] values); + abstract protected void displayMessageOnOSD(String msg); + abstract protected void setWindowCaption(String caption); + abstract protected String[] getPluginDirectories(); + abstract protected void showVirtualKeyboard(boolean enable); + abstract protected String[] getSysArchives(); - private final int AUDIO_FRAME_SIZE = 2 * 2; // bytes. 16bit audio * stereo - public static class AudioSetupException extends Exception {} + public ScummVM(AssetManager asset_manager, SurfaceHolder holder) { + _asset_manager = asset_manager; + _sem_surface = new Object(); - private long nativeScummVM; // native code hangs itself here - boolean scummVMRunning = false; + holder.addCallback(this); + } - private native void create(AssetManager am); + // SurfaceHolder callback + final public void surfaceCreated(SurfaceHolder holder) { + Log.d(LOG_TAG, "surfaceCreated"); - public ScummVM(Context context) { - create(context.getAssets()); // Init C++ code, set nativeScummVM + // no need to do anything, surfaceChanged() will be called in any case } - private native void nativeDestroy(); + // SurfaceHolder callback + final public void surfaceChanged(SurfaceHolder holder, int format, + int width, int height) { + Log.d(LOG_TAG, String.format("surfaceChanged: %dx%d (%d)", + width, height, format)); - public synchronized void destroy() { - if (nativeScummVM != 0) { - nativeDestroy(); - nativeScummVM = 0; + synchronized(_sem_surface) { + _surface_holder = holder; + _sem_surface.notifyAll(); } - } - protected void finalize() { - destroy(); - } - // Surface creation: - // GUI thread: create surface, release lock - // ScummVM thread: acquire lock (block), read surface - // - // Surface deletion: - // GUI thread: post event, acquire lock (block), return - // ScummVM thread: read event, free surface, release lock - // - // In other words, ScummVM thread does this: - // acquire lock - // setup surface - // when SCREEN_CHANGED arrives: - // destroy surface - // release lock - // back to acquire lock - static final int configSpec[] = { - EGL10.EGL_RED_SIZE, 5, - EGL10.EGL_GREEN_SIZE, 5, - EGL10.EGL_BLUE_SIZE, 5, - EGL10.EGL_DEPTH_SIZE, 0, - EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT, - EGL10.EGL_NONE, - }; - EGL10 egl; - EGLDisplay eglDisplay = EGL10.EGL_NO_DISPLAY; - EGLConfig eglConfig; - EGLContext eglContext = EGL10.EGL_NO_CONTEXT; - EGLSurface eglSurface = EGL10.EGL_NO_SURFACE; - Semaphore surfaceLock = new Semaphore(0, true); - SurfaceHolder nativeSurface; - - public void surfaceCreated(SurfaceHolder holder) { - nativeSurface = holder; - surfaceLock.release(); + // store values for the native code + setSurface(width, height); } - public void surfaceChanged(SurfaceHolder holder, int format, - int width, int height) { - // Disabled while I debug GL problems - pushEvent(new Event(Event.EVENT_SCREEN_CHANGED)); - } + // SurfaceHolder callback + final public void surfaceDestroyed(SurfaceHolder holder) { + Log.d(LOG_TAG, "surfaceDestroyed"); - public void surfaceDestroyed(SurfaceHolder holder) { - try { - surfaceLock.acquire(); - } catch (InterruptedException e) { - Log.e(LOG_TAG, "Interrupted while waiting for surface lock", e); + synchronized(_sem_surface) { + _surface_holder = null; + _sem_surface.notifyAll(); } + + // clear values for the native code + setSurface(0, 0); } - // For debugging - private static final Map<String, Integer> attribs; - static { - attribs = new LinkedHashMap<String, Integer>(); - attribs.put("CONFIG_ID", EGL10.EGL_CONFIG_ID); - attribs.put("BUFFER_SIZE", EGL10.EGL_BUFFER_SIZE); - attribs.put("RED_SIZE", EGL10.EGL_RED_SIZE); - attribs.put("GREEN_SIZE", EGL10.EGL_GREEN_SIZE); - attribs.put("BLUE_SIZE", EGL10.EGL_BLUE_SIZE); - attribs.put("ALPHA_SIZE", EGL10.EGL_ALPHA_SIZE); - //attribs.put("BIND_TO_RGB", EGL10.EGL_BIND_TO_TEXTURE_RGB); - //attribs.put("BIND_TO_RGBA", EGL10.EGL_BIND_TO_TEXTURE_RGBA); - attribs.put("CONFIG_CAVEAT", EGL10.EGL_CONFIG_CAVEAT); - attribs.put("DEPTH_SIZE", EGL10.EGL_DEPTH_SIZE); - attribs.put("LEVEL", EGL10.EGL_LEVEL); - attribs.put("MAX_PBUFFER_WIDTH", EGL10.EGL_MAX_PBUFFER_WIDTH); - attribs.put("MAX_PBUFFER_HEIGHT", EGL10.EGL_MAX_PBUFFER_HEIGHT); - attribs.put("MAX_PBUFFER_PIXELS", EGL10.EGL_MAX_PBUFFER_PIXELS); - //attribs.put("MAX_SWAP_INTERVAL", EGL10.EGL_MAX_SWAP_INTERVAL); - //attribs.put("MIN_SWAP_INTERVAL", EGL10.EGL_MIN_SWAP_INTERVAL); - attribs.put("NATIVE_RENDERABLE", EGL10.EGL_NATIVE_RENDERABLE); - attribs.put("NATIVE_VISUAL_ID", EGL10.EGL_NATIVE_VISUAL_ID); - attribs.put("NATIVE_VISUAL_TYPE", EGL10.EGL_NATIVE_VISUAL_TYPE); - attribs.put("SAMPLE_BUFFERS", EGL10.EGL_SAMPLE_BUFFERS); - attribs.put("SAMPLES", EGL10.EGL_SAMPLES); - attribs.put("STENCIL_SIZE", EGL10.EGL_STENCIL_SIZE); - attribs.put("SURFACE_TYPE", EGL10.EGL_SURFACE_TYPE); - attribs.put("TRANSPARENT_TYPE", EGL10.EGL_TRANSPARENT_TYPE); - attribs.put("TRANSPARENT_RED_VALUE", EGL10.EGL_TRANSPARENT_RED_VALUE); - attribs.put("TRANSPARENT_GREEN_VALUE", EGL10.EGL_TRANSPARENT_GREEN_VALUE); - attribs.put("TRANSPARENT_BLUE_VALUE", EGL10.EGL_TRANSPARENT_BLUE_VALUE); + final public void setArgs(String[] args) { + _args = args; } - private void dumpEglConfig(EGLConfig config) { - int[] value = new int[1]; - for (Map.Entry<String, Integer> entry : attribs.entrySet()) { - egl.eglGetConfigAttrib(eglDisplay, config, - entry.getValue(), value); - if (value[0] == EGL10.EGL_NONE) - Log.d(LOG_TAG, entry.getKey() + ": NONE"); - else - Log.d(LOG_TAG, String.format("%s: %d", entry.getKey(), value[0])); + + final public void run() { + try { + initAudio(); + initEGL(); + + // wait for the surfaceChanged callback + synchronized(_sem_surface) { + while (_surface_holder == null) + _sem_surface.wait(); + } + } catch (Exception e) { + deinitEGL(); + deinitAudio(); + + throw new RuntimeException("Error preparing the ScummVM thread", e); } + + create(_asset_manager, _egl, _egl_display, + _audio_track, _sample_rate, _buffer_size); + + int res = main(_args); + + destroy(); + + deinitEGL(); + deinitAudio(); + + // On exit, tear everything down for a fresh restart next time. + System.exit(res); } - // Called by ScummVM thread (from initBackend) - private void createScummVMGLContext() { - egl = (EGL10)EGLContext.getEGL(); - eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + final private void initEGL() throws Exception { + _egl = (EGL10)EGLContext.getEGL(); + _egl_display = _egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + int[] version = new int[2]; - egl.eglInitialize(eglDisplay, version); + _egl.eglInitialize(_egl_display, version); + int[] num_config = new int[1]; - egl.eglChooseConfig(eglDisplay, configSpec, null, 0, num_config); + _egl.eglGetConfigs(_egl_display, null, 0, num_config); final int numConfigs = num_config[0]; + if (numConfigs <= 0) - throw new IllegalArgumentException("No configs match configSpec"); + throw new IllegalArgumentException("No EGL configs"); EGLConfig[] configs = new EGLConfig[numConfigs]; - egl.eglChooseConfig(eglDisplay, configSpec, configs, numConfigs, - num_config); - - if (false) { - Log.d(LOG_TAG, String.format("Found %d EGL configurations.", numConfigs)); - for (EGLConfig config : configs) - dumpEglConfig(config); - } + _egl.eglGetConfigs(_egl_display, configs, numConfigs, num_config); // Android's eglChooseConfig is busted in several versions and - // devices so we have to filter/rank the configs again ourselves. - eglConfig = chooseEglConfig(configs); - if (false) { - Log.d(LOG_TAG, String.format("Chose EGL config from %d possibilities.", numConfigs)); - dumpEglConfig(eglConfig); - } + // devices so we have to filter/rank the configs ourselves. + _egl_config = chooseEglConfig(configs); - eglContext = egl.eglCreateContext(eglDisplay, eglConfig, - EGL10.EGL_NO_CONTEXT, null); - if (eglContext == EGL10.EGL_NO_CONTEXT) - throw new RuntimeException("Failed to create context"); - } + _egl_context = _egl.eglCreateContext(_egl_display, _egl_config, + EGL10.EGL_NO_CONTEXT, null); - private EGLConfig chooseEglConfig(EGLConfig[] configs) { - int best = 0; - int bestScore = -1; - int[] value = new int[1]; + if (_egl_context == EGL10.EGL_NO_CONTEXT) + throw new Exception(String.format("Failed to create context: 0x%x", + _egl.eglGetError())); + } - for (int i = 0; i < configs.length; i++) { - EGLConfig config = configs[i]; - int score = 10000; - egl.eglGetConfigAttrib(eglDisplay, config, - EGL10.EGL_SURFACE_TYPE, value); - if ((value[0] & EGL10.EGL_WINDOW_BIT) == 0) - continue; // must have - - egl.eglGetConfigAttrib(eglDisplay, config, - EGL10.EGL_CONFIG_CAVEAT, value); - if (value[0] != EGL10.EGL_NONE) - score -= 1000; + // Callback from C++ peer instance + final protected EGLSurface initSurface() throws Exception { + _egl_surface = _egl.eglCreateWindowSurface(_egl_display, _egl_config, + _surface_holder, null); - // Must be at least 555, but then smaller is better - final int[] colorBits = {EGL10.EGL_RED_SIZE, - EGL10.EGL_GREEN_SIZE, - EGL10.EGL_BLUE_SIZE, - EGL10.EGL_ALPHA_SIZE}; - for (int component : colorBits) { - egl.eglGetConfigAttrib(eglDisplay, config, - component, value); - if (value[0] >= 5) - score += 10; // boost if >5 bits accuracy - score -= value[0]; // penalize for wasted bits - } + if (_egl_surface == EGL10.EGL_NO_SURFACE) + throw new Exception(String.format( + "eglCreateWindowSurface failed: 0x%x", _egl.eglGetError())); - egl.eglGetConfigAttrib(eglDisplay, config, - EGL10.EGL_DEPTH_SIZE, value); - score -= value[0]; // penalize for wasted bits + _egl.eglMakeCurrent(_egl_display, _egl_surface, _egl_surface, + _egl_context); - if (score > bestScore) { - best = i; - bestScore = score; - } - } + GL10 gl = (GL10)_egl_context.getGL(); - if (bestScore < 0) { - Log.e(LOG_TAG, "Unable to find an acceptable EGL config, expect badness."); - return configs[0]; - } + Log.i(LOG_TAG, String.format("Using EGL %s (%s); GL %s/%s (%s)", + _egl.eglQueryString(_egl_display, EGL10.EGL_VERSION), + _egl.eglQueryString(_egl_display, EGL10.EGL_VENDOR), + gl.glGetString(GL10.GL_VERSION), + gl.glGetString(GL10.GL_RENDERER), + gl.glGetString(GL10.GL_VENDOR))); - return configs[best]; + return _egl_surface; } - // Called by ScummVM thread - static private boolean _log_version = true; - protected void setupScummVMSurface() { - try { - surfaceLock.acquire(); - } catch (InterruptedException e) { - Log.e(LOG_TAG, "Interrupted while waiting for surface lock", e); - return; - } - eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, - nativeSurface, null); - if (eglSurface == EGL10.EGL_NO_SURFACE) - Log.e(LOG_TAG, "CreateWindowSurface failed!"); - egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); - - GL10 gl = (GL10)eglContext.getGL(); - - if (_log_version) { - Log.i(LOG_TAG, String.format("Using EGL %s (%s); GL %s/%s (%s)", - egl.eglQueryString(eglDisplay, EGL10.EGL_VERSION), - egl.eglQueryString(eglDisplay, EGL10.EGL_VENDOR), - gl.glGetString(GL10.GL_VERSION), - gl.glGetString(GL10.GL_RENDERER), - gl.glGetString(GL10.GL_VENDOR))); - _log_version = false; // only log this once + // Callback from C++ peer instance + final protected void deinitSurface() { + if (_egl_display != EGL10.EGL_NO_DISPLAY) { + _egl.eglMakeCurrent(_egl_display, EGL10.EGL_NO_SURFACE, + EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); + + if (_egl_surface != EGL10.EGL_NO_SURFACE) + _egl.eglDestroySurface(_egl_display, _egl_surface); } - int[] value = new int[1]; - egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_WIDTH, value); - int width = value[0]; - egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_HEIGHT, value); - int height = value[0]; - Log.i(LOG_TAG, String.format("New surface is %dx%d", width, height)); - setSurfaceSize(width, height); + _egl_surface = EGL10.EGL_NO_SURFACE; } - // Called by ScummVM thread - protected void destroyScummVMSurface() { - if (eglSurface != null) { - egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, - EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); - egl.eglDestroySurface(eglDisplay, eglSurface); - eglSurface = EGL10.EGL_NO_SURFACE; + final private void deinitEGL() { + if (_egl_display != EGL10.EGL_NO_DISPLAY) { + _egl.eglMakeCurrent(_egl_display, EGL10.EGL_NO_SURFACE, + EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); + + if (_egl_surface != EGL10.EGL_NO_SURFACE) + _egl.eglDestroySurface(_egl_display, _egl_surface); + + if (_egl_context != EGL10.EGL_NO_CONTEXT) + _egl.eglDestroyContext(_egl_display, _egl_context); + + _egl.eglTerminate(_egl_display); } - surfaceLock.release(); + _egl_surface = EGL10.EGL_NO_SURFACE; + _egl_context = EGL10.EGL_NO_CONTEXT; + _egl_config = null; + _egl_display = EGL10.EGL_NO_DISPLAY; + _egl = null; } - public void setSurface(SurfaceHolder holder) { - holder.addCallback(this); - } + final private void initAudio() throws Exception { + _sample_rate = AudioTrack.getNativeOutputSampleRate( + AudioManager.STREAM_MUSIC); + _buffer_size = AudioTrack.getMinBufferSize(_sample_rate, + AudioFormat.CHANNEL_CONFIGURATION_STEREO, + AudioFormat.ENCODING_PCM_16BIT); + + // ~50ms + int buffer_size_want = (_sample_rate * 2 * 2 / 20) & ~1023; - final public boolean swapBuffers() { - if (!egl.eglSwapBuffers(eglDisplay, eglSurface)) { - int error = egl.eglGetError(); - Log.w(LOG_TAG, String.format("eglSwapBuffers exited with error 0x%x", error)); - if (error == EGL11.EGL_CONTEXT_LOST) - return false; + if (_buffer_size < buffer_size_want) { + Log.w(LOG_TAG, String.format( + "adjusting audio buffer size (was: %d)", _buffer_size)); + + _buffer_size = buffer_size_want; } - return true; - } - // Set scummvm config options - final public native static void loadConfigFile(String path); - final public native static void setConfMan(String key, int value); - final public native static void setConfMan(String key, String value); - final public native void enableZoning(boolean enable); - final public native void setSurfaceSize(int width, int height); + Log.i(LOG_TAG, String.format("Using %d bytes buffer for %dHz audio", + _buffer_size, _sample_rate)); - // Feed an event to ScummVM. Safe to call from other threads. - final public native void pushEvent(Event e); + _audio_track = new AudioTrack(AudioManager.STREAM_MUSIC, + _sample_rate, + AudioFormat.CHANNEL_CONFIGURATION_STEREO, + AudioFormat.ENCODING_PCM_16BIT, + _buffer_size, + AudioTrack.MODE_STREAM); - final private native void audioMixCallback(byte[] buf); + if (_audio_track.getState() != AudioTrack.STATE_INITIALIZED) + throw new Exception( + String.format("Error initialising AudioTrack: %d", + _audio_track.getState())); + } - // Runs the actual ScummVM program and returns when it does. - // This should not be called from multiple threads simultaneously... - final public native int scummVMMain(String[] argv); + final private void deinitAudio() { + if (_audio_track != null) + _audio_track.stop(); - // Callbacks from C++ peer instance - //protected GraphicsMode[] getSupportedGraphicsModes() {} - protected void displayMessageOnOSD(String msg) {} - protected void setWindowCaption(String caption) {} - protected void showVirtualKeyboard(boolean enable) {} - protected String[] getSysArchives() { return new String[0]; } - protected String[] getPluginDirectories() { return new String[0]; } - protected void initBackend() throws AudioSetupException { - createScummVMGLContext(); - initAudio(); + _audio_track = null; + _buffer_size = 0; + _sample_rate = 0; } - private static class AudioThread extends Thread { - final private int buf_size; - private boolean is_paused = false; - final private ScummVM scummvm; - final private AudioTrack audio_track; - - AudioThread(ScummVM scummvm, AudioTrack audio_track, int buf_size) { - super("AudioThread"); - this.scummvm = scummvm; - this.audio_track = audio_track; - this.buf_size = buf_size; - setPriority(Thread.MAX_PRIORITY); - setDaemon(true); - } + private static final int[] s_eglAttribs = { + EGL10.EGL_CONFIG_ID, + EGL10.EGL_BUFFER_SIZE, + EGL10.EGL_RED_SIZE, + EGL10.EGL_GREEN_SIZE, + EGL10.EGL_BLUE_SIZE, + EGL10.EGL_ALPHA_SIZE, + EGL10.EGL_CONFIG_CAVEAT, + EGL10.EGL_DEPTH_SIZE, + EGL10.EGL_LEVEL, + EGL10.EGL_MAX_PBUFFER_WIDTH, + EGL10.EGL_MAX_PBUFFER_HEIGHT, + EGL10.EGL_MAX_PBUFFER_PIXELS, + EGL10.EGL_NATIVE_RENDERABLE, + EGL10.EGL_NATIVE_VISUAL_ID, + EGL10.EGL_NATIVE_VISUAL_TYPE, + EGL10.EGL_SAMPLE_BUFFERS, + EGL10.EGL_SAMPLES, + EGL10.EGL_STENCIL_SIZE, + EGL10.EGL_SURFACE_TYPE, + EGL10.EGL_TRANSPARENT_TYPE, + EGL10.EGL_TRANSPARENT_RED_VALUE, + EGL10.EGL_TRANSPARENT_GREEN_VALUE, + EGL10.EGL_TRANSPARENT_BLUE_VALUE + }; - public void pauseAudio() { - synchronized (this) { - is_paused = true; + final private class EglAttribs extends LinkedHashMap<Integer, Integer> { + public EglAttribs(EGLConfig config) { + super(s_eglAttribs.length); + + int[] value = new int[1]; + + for (int i : s_eglAttribs) { + _egl.eglGetConfigAttrib(_egl_display, config, i, value); + + put(i, value[0]); } - audio_track.pause(); } - public void resumeAudio() { - synchronized (this) { - is_paused = false; - notifyAll(); - } - audio_track.play(); + private int weightBits(int attr, int size) { + final int value = get(attr); + + int score = 0; + + if (value == size || (size > 0 && value > size)) + score += 10; + + // penalize for wasted bits + score -= value - size; + + return score; } - public void run() { - byte[] buf = new byte[buf_size]; - audio_track.play(); - int offset = 0; - try { - while (true) { - synchronized (this) { - while (is_paused) - wait(); - } - - if (offset == buf.length) { - // Grab new audio data - scummvm.audioMixCallback(buf); - offset = 0; - } - int len = buf.length - offset; - int ret = audio_track.write(buf, offset, len); - if (ret < 0) { - Log.w(LOG_TAG, String.format( - "AudioTrack.write(%dB) returned error %d", - buf.length, ret)); - break; - } else if (ret != len) { - Log.w(LOG_TAG, String.format( - "Short audio write. Wrote %dB, not %dB", - ret, buf.length)); - // Buffer is full, so yield cpu for a while - Thread.sleep(100); - } - offset += ret; - } - } catch (InterruptedException e) { - Log.e(LOG_TAG, "Audio thread interrupted", e); - } + public int weight() { + int score = 10000; + + if (get(EGL10.EGL_CONFIG_CAVEAT) != EGL10.EGL_NONE) + score -= 1000; + + // less MSAA is better + score -= get(EGL10.EGL_SAMPLES) * 100; + + // Must be at least 565, but then smaller is better + score += weightBits(EGL10.EGL_RED_SIZE, 5); + score += weightBits(EGL10.EGL_GREEN_SIZE, 6); + score += weightBits(EGL10.EGL_BLUE_SIZE, 5); + score += weightBits(EGL10.EGL_ALPHA_SIZE, 0); + score += weightBits(EGL10.EGL_DEPTH_SIZE, 0); + score += weightBits(EGL10.EGL_STENCIL_SIZE, 0); + + return score; } - } - private AudioThread audio_thread; - final public int audioSampleRate() { - return AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC); - } + public String toString() { + String s; - private void initAudio() throws AudioSetupException { - int sample_rate = audioSampleRate(); - int buf_size = - AudioTrack.getMinBufferSize(sample_rate, - AudioFormat.CHANNEL_CONFIGURATION_STEREO, - AudioFormat.ENCODING_PCM_16BIT); - if (buf_size < 0) { - int guess = AUDIO_FRAME_SIZE * sample_rate / 100; // 10ms of audio - Log.w(LOG_TAG, String.format( - "Unable to get min audio buffer size (error %d). Guessing %dB.", - buf_size, guess)); - buf_size = guess; + if (get(EGL10.EGL_ALPHA_SIZE) > 0) + s = String.format("[%d] RGBA%d%d%d%d", + get(EGL10.EGL_CONFIG_ID), + get(EGL10.EGL_RED_SIZE), + get(EGL10.EGL_GREEN_SIZE), + get(EGL10.EGL_BLUE_SIZE), + get(EGL10.EGL_ALPHA_SIZE)); + else + s = String.format("[%d] RGB%d%d%d", + get(EGL10.EGL_CONFIG_ID), + get(EGL10.EGL_RED_SIZE), + get(EGL10.EGL_GREEN_SIZE), + get(EGL10.EGL_BLUE_SIZE)); + + if (get(EGL10.EGL_DEPTH_SIZE) > 0) + s += String.format(" D%d", get(EGL10.EGL_DEPTH_SIZE)); + + if (get(EGL10.EGL_STENCIL_SIZE) > 0) + s += String.format(" S%d", get(EGL10.EGL_STENCIL_SIZE)); + + if (get(EGL10.EGL_SAMPLES) > 0) + s += String.format(" MSAAx%d", get(EGL10.EGL_SAMPLES)); + + if ((get(EGL10.EGL_SURFACE_TYPE) & EGL10.EGL_WINDOW_BIT) > 0) + s += " W"; + if ((get(EGL10.EGL_SURFACE_TYPE) & EGL10.EGL_PBUFFER_BIT) > 0) + s += " P"; + if ((get(EGL10.EGL_SURFACE_TYPE) & EGL10.EGL_PIXMAP_BIT) > 0) + s += " X"; + + switch (get(EGL10.EGL_CONFIG_CAVEAT)) { + case EGL10.EGL_NONE: + break; + + case EGL10.EGL_SLOW_CONFIG: + s += " SLOW"; + break; + + case EGL10.EGL_NON_CONFORMANT_CONFIG: + s += " NON_CONFORMANT"; + + default: + s += String.format(" unknown CAVEAT 0x%x", + get(EGL10.EGL_CONFIG_CAVEAT)); + } + + return s; } - Log.d(LOG_TAG, String.format("Using %dB buffer for %dHZ audio", - buf_size, sample_rate)); - AudioTrack audio_track = - new AudioTrack(AudioManager.STREAM_MUSIC, - sample_rate, - AudioFormat.CHANNEL_CONFIGURATION_STEREO, - AudioFormat.ENCODING_PCM_16BIT, - buf_size, - AudioTrack.MODE_STREAM); - if (audio_track.getState() != AudioTrack.STATE_INITIALIZED) { - Log.e(LOG_TAG, "Error initialising Android audio system."); - throw new AudioSetupException(); + }; + + final private EGLConfig chooseEglConfig(EGLConfig[] configs) { + EGLConfig res = configs[0]; + int bestScore = -1; + + Log.d(LOG_TAG, "EGL configs:"); + + for (EGLConfig config : configs) { + EglAttribs attr = new EglAttribs(config); + + // must have + if ((attr.get(EGL10.EGL_SURFACE_TYPE) & EGL10.EGL_WINDOW_BIT) == 0) + continue; + + int score = attr.weight(); + + Log.d(LOG_TAG, String.format("%s (%d)", attr.toString(), score)); + + if (score > bestScore) { + res = config; + bestScore = score; + } } - audio_thread = new AudioThread(this, audio_track, buf_size); - audio_thread.start(); - } + if (bestScore < 0) + Log.e(LOG_TAG, + "Unable to find an acceptable EGL config, expect badness."); - public void pause() { - audio_thread.pauseAudio(); - // TODO: need to pause engine too - } + Log.d(LOG_TAG, String.format("Chosen EGL config: %s", + new EglAttribs(res).toString())); - public void resume() { - // TODO: need to resume engine too - audio_thread.resumeAudio(); + return res; } static { @@ -448,15 +429,16 @@ public class ScummVM implements SurfaceHolder.Callback { final boolean sleep_for_debugger = false; if (sleep_for_debugger) { try { - Thread.sleep(20*1000); + Thread.sleep(20 * 1000); } catch (InterruptedException e) { } } - //System.loadLibrary("scummvm"); File cache_dir = ScummVMApplication.getLastCacheDir(); String libname = System.mapLibraryName("scummvm"); File libpath = new File(cache_dir, libname); + System.load(libpath.getPath()); } } + diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java index fae35b6695..1978b690d0 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java @@ -3,41 +3,27 @@ package org.inodes.gus.scummvm; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; -import android.content.res.Configuration; import android.media.AudioManager; import android.os.Bundle; import android.os.Environment; -import android.os.Handler; -import android.os.Message; import android.util.DisplayMetrics; import android.util.Log; -import android.view.KeyEvent; -import android.view.MotionEvent; import android.view.SurfaceView; -import android.view.View; -import android.view.ViewConfiguration; +import android.view.SurfaceHolder; +import android.view.MotionEvent; import android.view.inputmethod.InputMethodManager; import android.widget.Toast; -import java.io.IOException; - public class ScummVMActivity extends Activity { - private boolean _do_right_click; - private boolean _last_click_was_right; - - // game pixels to move per trackball/dpad event. - // FIXME: replace this with proper mouse acceleration - private final static int TRACKBALL_SCALE = 2; private class MyScummVM extends ScummVM { - private boolean scummvmRunning = false; - private boolean usingSmallScreen() { // Multiple screen sizes came in with Android 1.6. Have // to use reflection in order to continue supporting 1.5 // devices :( DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); + try { // This 'density' term is very confusing. int DENSITY_LOW = metrics.getClass().getField("DENSITY_LOW").getInt(null); @@ -48,27 +34,22 @@ public class ScummVMActivity extends Activity { } } - public MyScummVM() { - super(ScummVMActivity.this); + public MyScummVM(SurfaceHolder holder) { + super(ScummVMActivity.this.getAssets(), holder); // Enable ScummVM zoning on 'small' screens. - enableZoning(usingSmallScreen()); + // FIXME make this optional for the user + // disabled for now since it crops too much + //enableZoning(usingSmallScreen()); } @Override - protected void initBackend() throws ScummVM.AudioSetupException { - synchronized (this) { - scummvmRunning = true; - notifyAll(); - } - super.initBackend(); - } + protected void getDPI(float[] values) { + DisplayMetrics metrics = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(metrics); - public void waitUntilRunning() throws InterruptedException { - synchronized (this) { - while (!scummvmRunning) - wait(); - } + values[0] = metrics.xdpi; + values[1] = metrics.ydpi; } @Override @@ -95,24 +76,28 @@ public class ScummVMActivity extends Activity { @Override protected void showVirtualKeyboard(final boolean enable) { - if (getResources().getConfiguration().keyboard == - Configuration.KEYBOARD_NOKEYS) { - runOnUiThread(new Runnable() { - public void run() { - showKeyboard(enable); - } - }); - } + runOnUiThread(new Runnable() { + public void run() { + showKeyboard(enable); + } + }); + } + + @Override + protected String[] getSysArchives() { + return new String[0]; } + } - private MyScummVM scummvm; - private Thread scummvm_thread; + + private MyScummVM _scummvm; + private ScummVMEvents _events; + private Thread _scummvm_thread; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - _do_right_click = false; setVolumeControlStream(AudioManager.STREAM_MUSIC); setContentView(R.layout.main); @@ -126,336 +111,110 @@ public class ScummVMActivity extends Activity { .setIcon(android.R.drawable.ic_dialog_alert) .setMessage(R.string.no_sdcard) .setNegativeButton(R.string.quit, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int which) { - finish(); - } - }) + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + finish(); + } + }) .show(); + return; } SurfaceView main_surface = (SurfaceView)findViewById(R.id.main_surface); - - main_surface.setOnTouchListener(new View.OnTouchListener() { - public boolean onTouch(View v, MotionEvent event) { - return onTouchEvent(event); - } - }); - main_surface.setOnKeyListener(new View.OnKeyListener() { - public boolean onKey(View v, int code, KeyEvent ev) { - return onKeyDown(code, ev); - } - }); + main_surface.requestFocus(); - // Start ScummVM - scummvm = new MyScummVM(); - scummvm_thread = new Thread(new Runnable() { - public void run() { - try { - runScummVM(); - } catch (Exception e) { - Log.e(ScummVM.LOG_TAG, "Fatal error in ScummVM thread", e); - new AlertDialog.Builder(ScummVMActivity.this) - .setTitle("Error") - .setMessage(e.toString()) - .setIcon(android.R.drawable.ic_dialog_alert) - .show(); - finish(); - } - } - }, "ScummVM"); - scummvm_thread.start(); - - // Block UI thread until ScummVM has started. In particular, - // this means that surface and event callbacks should be safe - // after this point. - try { - scummvm.waitUntilRunning(); - } catch (InterruptedException e) { - Log.e(ScummVM.LOG_TAG, "Interrupted while waiting for ScummVM.initBackend", e); - finish(); - } + getFilesDir().mkdirs(); - scummvm.setSurface(main_surface.getHolder()); - } + // Start ScummVM + _scummvm = new MyScummVM(main_surface.getHolder()); - // Runs in another thread - private void runScummVM() throws IOException { - getFilesDir().mkdirs(); - String[] args = { - "ScummVM-lib", + _scummvm.setArgs(new String[] { + "ScummVM", "--config=" + getFileStreamPath("scummvmrc").getPath(), "--path=" + Environment.getExternalStorageDirectory().getPath(), "--gui-theme=scummmodern", "--savepath=" + getDir("saves", 0).getPath() - }; + }); - int ret = scummvm.scummVMMain(args); + _events = new ScummVMEvents(this, _scummvm); - // On exit, tear everything down for a fresh - // restart next time. - System.exit(ret); - } + main_surface.setOnKeyListener(_events); + main_surface.setOnTouchListener(_events); - private boolean was_paused = false; + _scummvm_thread = new Thread(_scummvm, "ScummVM"); + _scummvm_thread.start(); + } @Override - public void onPause() { - if (scummvm != null) { - was_paused = true; - scummvm.pause(); - } - super.onPause(); + public void onStart() { + Log.d(ScummVM.LOG_TAG, "onStart"); + + super.onStart(); } @Override public void onResume() { + Log.d(ScummVM.LOG_TAG, "onResume"); + super.onResume(); - if (scummvm != null && was_paused) - scummvm.resume(); - was_paused = false; + + if (_scummvm != null) + _scummvm.setPause(false); } @Override - public void onStop() { - if (scummvm != null) { - scummvm.pushEvent(new Event(Event.EVENT_QUIT)); - try { - scummvm_thread.join(1000); // 1s timeout - } catch (InterruptedException e) { - Log.i(ScummVM.LOG_TAG, "Error while joining ScummVM thread", e); - } - } - super.onStop(); - } + public void onPause() { + Log.d(ScummVM.LOG_TAG, "onPause"); - static final int MSG_MENU_LONG_PRESS = 1; - private final Handler keycodeMenuTimeoutHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - if (msg.what == MSG_MENU_LONG_PRESS) { - InputMethodManager imm = (InputMethodManager) - getSystemService(INPUT_METHOD_SERVICE); - if (imm != null) - imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); - } - } - }; + super.onPause(); - @Override - public boolean onKeyUp(int keyCode, KeyEvent kevent) { - return onKeyDown(keyCode, kevent); + if (_scummvm != null) + _scummvm.setPause(true); } @Override - public boolean onKeyMultiple(int keyCode, int repeatCount, - KeyEvent kevent) { - return onKeyDown(keyCode, kevent); + public void onStop() { + Log.d(ScummVM.LOG_TAG, "onStop"); + + super.onStop(); } @Override - public boolean onKeyDown(int keyCode, KeyEvent kevent) { - // Filter out "special" keys - switch (keyCode) { - case KeyEvent.KEYCODE_MENU: - // Have to reimplement hold-down-menu-brings-up-softkeybd - // ourselves, since we are otherwise hijacking the menu - // key :( - // See com.android.internal.policy.impl.PhoneWindow.onKeyDownPanel() - // for the usual Android implementation of this feature. - if (kevent.getRepeatCount() > 0) - // Ignore keyrepeat for menu - return false; - boolean timeout_fired = false; - if (getResources().getConfiguration().keyboard == - Configuration.KEYBOARD_NOKEYS) { - timeout_fired = !keycodeMenuTimeoutHandler.hasMessages(MSG_MENU_LONG_PRESS); - keycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); - if (kevent.getAction() == KeyEvent.ACTION_DOWN) { - keycodeMenuTimeoutHandler.sendMessageDelayed( - keycodeMenuTimeoutHandler.obtainMessage(MSG_MENU_LONG_PRESS), - ViewConfiguration.getLongPressTimeout()); - return true; - } - } - if (kevent.getAction() == KeyEvent.ACTION_UP) { - if (!timeout_fired) - scummvm.pushEvent(new Event(Event.EVENT_MAINMENU)); - return true; - } - return false; - case KeyEvent.KEYCODE_CAMERA: - case KeyEvent.KEYCODE_SEARCH: - _do_right_click = (kevent.getAction() == KeyEvent.ACTION_DOWN); - return true; - case KeyEvent.KEYCODE_DPAD_CENTER: - case KeyEvent.KEYCODE_DPAD_UP: - case KeyEvent.KEYCODE_DPAD_DOWN: - case KeyEvent.KEYCODE_DPAD_LEFT: - case KeyEvent.KEYCODE_DPAD_RIGHT: { - // HTC Hero doesn't seem to generate - // MotionEvent.ACTION_DOWN events on trackball press :( - // We'll have to just fake one here. - // Some other handsets lack a trackball, so the DPAD is - // the only way of moving the cursor. - int motion_action; - // FIXME: this logic is a mess. - if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { - switch (kevent.getAction()) { - case KeyEvent.ACTION_DOWN: - motion_action = MotionEvent.ACTION_DOWN; - break; - case KeyEvent.ACTION_UP: - motion_action = MotionEvent.ACTION_UP; - break; - default: // ACTION_MULTIPLE - return false; - } - } else - motion_action = MotionEvent.ACTION_MOVE; - - Event e = new Event(getEventType(motion_action)); - e.mouse_x = 0; - e.mouse_y = 0; - e.mouse_relative = true; - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_UP: - e.mouse_y = -TRACKBALL_SCALE; - break; - case KeyEvent.KEYCODE_DPAD_DOWN: - e.mouse_y = TRACKBALL_SCALE; - break; - case KeyEvent.KEYCODE_DPAD_LEFT: - e.mouse_x = -TRACKBALL_SCALE; - break; - case KeyEvent.KEYCODE_DPAD_RIGHT: - e.mouse_x = TRACKBALL_SCALE; - break; - } - scummvm.pushEvent(e); - return true; - } - case KeyEvent.KEYCODE_BACK: - // skip isSystem() check and fall through to main code - break; - default: - if (kevent.isSystem()) - return false; - } + public void onDestroy() { + Log.d(ScummVM.LOG_TAG, "onDestroy"); - // FIXME: what do I need to do for composed characters? - - Event e = new Event(); - - switch (kevent.getAction()) { - case KeyEvent.ACTION_DOWN: - e.type = Event.EVENT_KEYDOWN; - e.synthetic = false; - break; - case KeyEvent.ACTION_UP: - e.type = Event.EVENT_KEYUP; - e.synthetic = false; - break; - case KeyEvent.ACTION_MULTIPLE: - // e.type is handled below - e.synthetic = true; - break; - default: - return false; - } + super.onDestroy(); - e.kbd_keycode = Event.androidKeyMap.containsKey(keyCode) ? - Event.androidKeyMap.get(keyCode) : Event.KEYCODE_INVALID; - e.kbd_ascii = kevent.getUnicodeChar(); - if (e.kbd_ascii == 0) - e.kbd_ascii = e.kbd_keycode; // scummvm keycodes are mostly ascii - - - e.kbd_flags = 0; - if (kevent.isAltPressed()) - e.kbd_flags |= Event.KBD_ALT; - if (kevent.isSymPressed()) // no ctrl key in android, so use sym (?) - e.kbd_flags |= Event.KBD_CTRL; - if (kevent.isShiftPressed()) { - if (keyCode >= KeyEvent.KEYCODE_0 && - keyCode <= KeyEvent.KEYCODE_9) { - // Shift+number -> convert to F* key - int offset = keyCode == KeyEvent.KEYCODE_0 ? - 10 : keyCode - KeyEvent.KEYCODE_1; // turn 0 into 10 - e.kbd_keycode = Event.KEYCODE_F1 + offset; - e.kbd_ascii = Event.ASCII_F1 + offset; - } else - e.kbd_flags |= Event.KBD_SHIFT; - } + if (_events != null) { + _events.sendQuitEvent(); - if (kevent.getAction() == KeyEvent.ACTION_MULTIPLE) { - for (int i = 0; i <= kevent.getRepeatCount(); i++) { - e.type = Event.EVENT_KEYDOWN; - scummvm.pushEvent(e); - e.type = Event.EVENT_KEYUP; - scummvm.pushEvent(e); + try { + // 1s timeout + _scummvm_thread.join(1000); + } catch (InterruptedException e) { + Log.i(ScummVM.LOG_TAG, "Error while joining ScummVM thread", e); } - } else - scummvm.pushEvent(e); - - return true; - } - private int getEventType(int action) { - switch (action) { - case MotionEvent.ACTION_DOWN: - _last_click_was_right = _do_right_click; - return _last_click_was_right ? - Event.EVENT_RBUTTONDOWN : Event.EVENT_LBUTTONDOWN; - case MotionEvent.ACTION_UP: - return _last_click_was_right ? - Event.EVENT_RBUTTONUP : Event.EVENT_LBUTTONUP; - case MotionEvent.ACTION_MOVE: - return Event.EVENT_MOUSEMOVE; - default: - return Event.EVENT_INVALID; + _scummvm = null; } } @Override - public boolean onTrackballEvent(MotionEvent event) { - int type = getEventType(event.getAction()); - if (type == Event.EVENT_INVALID) - return false; - - Event e = new Event(type); - e.mouse_x = - (int)(event.getX() * event.getXPrecision()) * TRACKBALL_SCALE; - e.mouse_y = - (int)(event.getY() * event.getYPrecision()) * TRACKBALL_SCALE; - e.mouse_relative = true; - scummvm.pushEvent(e); - - return true; - } + public boolean onTrackballEvent(MotionEvent e) { + if (_events != null) + return _events.onTrackballEvent(e); - @Override - public boolean onTouchEvent(MotionEvent event) { - int type = getEventType(event.getAction()); - if (type == Event.EVENT_INVALID) - return false; - - Event e = new Event(type); - e.mouse_x = (int)event.getX(); - e.mouse_y = (int)event.getY(); - e.mouse_relative = false; - scummvm.pushEvent(e); - - return true; + return false; } private void showKeyboard(boolean show) { SurfaceView main_surface = (SurfaceView)findViewById(R.id.main_surface); InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); + if (show) imm.showSoftInput(main_surface, InputMethodManager.SHOW_IMPLICIT); else @@ -463,3 +222,4 @@ public class ScummVMActivity extends Activity { InputMethodManager.HIDE_IMPLICIT_ONLY); } } + diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java index 37a9d09e1a..f9eec72eac 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java @@ -8,22 +8,24 @@ public class ScummVMApplication extends Application { public final static String ACTION_PLUGIN_QUERY = "org.inodes.gus.scummvm.action.PLUGIN_QUERY"; public final static String EXTRA_UNPACK_LIBS = "org.inodes.gus.scummvm.extra.UNPACK_LIBS"; - private static File cache_dir; + private static File _cache_dir; @Override public void onCreate() { super.onCreate(); + // This is still on /data :( - cache_dir = getCacheDir(); + _cache_dir = getCacheDir(); // This is mounted noexec :( //cache_dir = new File(Environment.getExternalStorageDirectory(), - // "/.ScummVM.tmp"); + // "/.ScummVM.tmp"); // This is owned by download manager and requires special // permissions to access :( //cache_dir = Environment.getDownloadCacheDirectory(); } public static File getLastCacheDir() { - return cache_dir; + return _cache_dir; } } + diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java new file mode 100644 index 0000000000..3d3fdeece4 --- /dev/null +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java @@ -0,0 +1,201 @@ +package org.inodes.gus.scummvm; + +import android.os.Handler; +import android.os.Message; +import android.util.Log; +import android.content.Context; +import android.view.KeyEvent; +import android.view.KeyCharacterMap; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.GestureDetector; +import android.view.inputmethod.InputMethodManager; + +public class ScummVMEvents implements + android.view.View.OnKeyListener, + android.view.View.OnTouchListener, + android.view.GestureDetector.OnGestureListener, + android.view.GestureDetector.OnDoubleTapListener { + + public static final int JE_SYS_KEY = 0; + public static final int JE_KEY = 1; + public static final int JE_DOWN = 2; + public static final int JE_SCROLL = 3; + public static final int JE_TAP = 4; + public static final int JE_DOUBLE_TAP = 5; + public static final int JE_BALL = 6; + public static final int JE_QUIT = 0x1000; + + final protected Context _context; + final protected ScummVM _scummvm; + final protected GestureDetector _gd; + final protected int _longPress; + final protected int _slop; + + public ScummVMEvents(Context context, ScummVM scummvm) { + _context = context; + _scummvm = scummvm; + + _gd = new GestureDetector(context, this); + _gd.setOnDoubleTapListener(this); + _gd.setIsLongpressEnabled(false); + + _longPress = ViewConfiguration.getLongPressTimeout(); + _slop = ViewConfiguration.get(context).getScaledTouchSlop(); + + } + + final public void sendQuitEvent() { + _scummvm.pushEvent(JE_QUIT, 0, 0, 0, 0, 0); + } + + public boolean onTrackballEvent(MotionEvent e) { + _scummvm.pushEvent(JE_BALL, (int)(e.getX() * e.getXPrecision() * 100), + (int)(e.getY() * e.getYPrecision() * 100), 0, 0, 0); + return true; + } + + final static int MSG_MENU_LONG_PRESS = 1; + + final private Handler keyHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (msg.what == MSG_MENU_LONG_PRESS) { + InputMethodManager imm = (InputMethodManager) + _context.getSystemService(_context.INPUT_METHOD_SERVICE); + + if (imm != null) + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + } + } + }; + + // OnKeyListener + final public boolean onKey(View v, int keyCode, KeyEvent e) { + final int action = e.getAction(); + + if (e.isSystem()) { + // filter what we handle + switch (keyCode) { + case KeyEvent.KEYCODE_BACK: + case KeyEvent.KEYCODE_MENU: + break; + + default: + return false; + } + + // no repeats for system keys + if (e.getRepeatCount() > 0) + return false; + + // Have to reimplement hold-down-menu-brings-up-softkeybd + // ourselves, since we are otherwise hijacking the menu key :( + // See com.android.internal.policy.impl.PhoneWindow.onKeyDownPanel() + // for the usual Android implementation of this feature. + if (keyCode == KeyEvent.KEYCODE_MENU) { + final boolean fired = + !keyHandler.hasMessages(MSG_MENU_LONG_PRESS); + + keyHandler.removeMessages(MSG_MENU_LONG_PRESS); + + if (action == KeyEvent.ACTION_DOWN) { + keyHandler.sendMessageDelayed(keyHandler.obtainMessage( + MSG_MENU_LONG_PRESS), _longPress); + return true; + } + + if (fired) + return true; + + // only send up events of the menu button to the native side + if (action != KeyEvent.ACTION_UP) + return true; + } + + _scummvm.pushEvent(JE_SYS_KEY, action, keyCode, 0, 0, 0); + + return true; + } + + // sequence of characters + if (action == KeyEvent.ACTION_MULTIPLE && + keyCode == KeyEvent.KEYCODE_UNKNOWN) { + KeyCharacterMap m = KeyCharacterMap.load(e.getDeviceId()); + + for (KeyEvent s : m.getEvents(e.getCharacters().toCharArray())) { + _scummvm.pushEvent(JE_KEY, s.getAction(), s.getKeyCode(), + s.getUnicodeChar() & KeyCharacterMap.COMBINING_ACCENT_MASK, + s.getMetaState(), s.getRepeatCount()); + } + + return true; + } + + _scummvm.pushEvent(JE_KEY, action, keyCode, + e.getUnicodeChar() & KeyCharacterMap.COMBINING_ACCENT_MASK, + e.getMetaState(), e.getRepeatCount()); + + return true; + } + + // OnTouchListener + final public boolean onTouch(View v, MotionEvent e) { + return _gd.onTouchEvent(e); + } + + // OnGestureListener + final public boolean onDown(MotionEvent e) { + _scummvm.pushEvent(JE_DOWN, (int)e.getX(), (int)e.getY(), 0, 0, 0); + return true; + } + + final public boolean onFling(MotionEvent e1, MotionEvent e2, + float velocityX, float velocityY) { + //Log.d(ScummVM.LOG_TAG, String.format("onFling: %s -> %s (%.3f %.3f)", + // e1.toString(), e2.toString(), + // velocityX, velocityY)); + + return true; + } + + final public void onLongPress(MotionEvent e) { + // disabled, interferes with drag&drop + } + + final public boolean onScroll(MotionEvent e1, MotionEvent e2, + float distanceX, float distanceY) { + _scummvm.pushEvent(JE_SCROLL, (int)e1.getX(), (int)e1.getY(), + (int)e2.getX(), (int)e2.getY(), _slop); + + return true; + } + + final public void onShowPress(MotionEvent e) { + } + + final public boolean onSingleTapUp(MotionEvent e) { + _scummvm.pushEvent(JE_TAP, (int)e.getX(), (int)e.getY(), + (int)(e.getEventTime() - e.getDownTime()), 0, 0); + + return true; + } + + // OnDoubleTapListener + final public boolean onDoubleTap(MotionEvent e) { + return true; + } + + final public boolean onDoubleTapEvent(MotionEvent e) { + _scummvm.pushEvent(JE_DOUBLE_TAP, (int)e.getX(), (int)e.getY(), + e.getAction(), _slop, 0); + + return true; + } + + final public boolean onSingleTapConfirmed(MotionEvent e) { + return true; + } +} + diff --git a/backends/platform/android/org/inodes/gus/scummvm/Unpacker.java b/backends/platform/android/org/inodes/gus/scummvm/Unpacker.java index 8811b1f3ae..c4b2ad7f5d 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/Unpacker.java +++ b/backends/platform/android/org/inodes/gus/scummvm/Unpacker.java @@ -370,3 +370,4 @@ public class Unpacker extends Activity { } } } + diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp new file mode 100644 index 0000000000..691c384a18 --- /dev/null +++ b/backends/platform/android/texture.cpp @@ -0,0 +1,571 @@ +/* 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$ + * + */ + +#if defined(__ANDROID__) + +#include "base/main.h" +#include "graphics/surface.h" + +#include "common/rect.h" +#include "common/array.h" +#include "common/util.h" +#include "common/tokenizer.h" + +#include "backends/platform/android/texture.h" +#include "backends/platform/android/android.h" + +// Supported GL extensions +static bool npot_supported = false; +#ifdef GL_OES_draw_texture +static bool draw_tex_supported = false; +#endif + +static inline GLfixed xdiv(int numerator, int denominator) { + assert(numerator < (1 << 16)); + return (numerator << 16) / denominator; +} + +template <class T> +static T nextHigher2(T k) { + if (k == 0) + return 1; + --k; + + for (uint i = 1; i < sizeof(T) * CHAR_BIT; i <<= 1) + k = k | k >> i; + + return k + 1; +} + +void GLESBaseTexture::initGLExtensions() { + const char *ext_string = + reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)); + + LOGI("Extensions: %s", ext_string); + + Common::StringTokenizer tokenizer(ext_string, " "); + while (!tokenizer.empty()) { + Common::String token = tokenizer.nextToken(); + + if (token == "GL_ARB_texture_non_power_of_two") + npot_supported = true; + +#ifdef GL_OES_draw_texture + if (token == "GL_OES_draw_texture") + draw_tex_supported = true; +#endif + } +} + +GLESBaseTexture::GLESBaseTexture(GLenum glFormat, GLenum glType, + Graphics::PixelFormat pixelFormat) : + _glFormat(glFormat), + _glType(glType), + _glFilter(GL_NEAREST), + _texture_name(0), + _surface(), + _texture_width(0), + _texture_height(0), + _draw_rect(), + _all_dirty(false), + _dirty_rect(), + _pixelFormat(pixelFormat), + _palettePixelFormat() +{ + GLCALL(glGenTextures(1, &_texture_name)); +} + +GLESBaseTexture::~GLESBaseTexture() { + release(); +} + +void GLESBaseTexture::release() { + LOGD("Destroying texture %u", _texture_name); + + GLCALL(glDeleteTextures(1, &_texture_name)); + _texture_name = 0; +} + +void GLESBaseTexture::reinit() { + GLCALL(glGenTextures(1, &_texture_name)); + + initSize(); + + setDirty(); +} + +void GLESBaseTexture::initSize() { + // Allocate room for the texture now, but pixel data gets uploaded + // later (perhaps with multiple TexSubImage2D operations). + GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); + GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _glFilter)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _glFilter)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, _glFormat, + _texture_width, _texture_height, + 0, _glFormat, _glType, 0)); +} + +void GLESBaseTexture::setLinearFilter(bool value) { + if (value) + _glFilter = GL_LINEAR; + else + _glFilter = GL_NEAREST; + + GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); + + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _glFilter)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _glFilter)); +} + +void GLESBaseTexture::allocBuffer(GLuint w, GLuint h) { + _surface.w = w; + _surface.h = h; + _surface.bytesPerPixel = _pixelFormat.bytesPerPixel; + + if (w == _texture_width && h == _texture_height) + return; + + if (npot_supported) { + _texture_width = _surface.w; + _texture_height = _surface.h; + } else { + _texture_width = nextHigher2(_surface.w); + _texture_height = nextHigher2(_surface.h); + } + + initSize(); +} + +void GLESBaseTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { + GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); + +#ifdef GL_OES_draw_texture + // Great extension, but only works under specific conditions. + // Still a work-in-progress - disabled for now. + if (false && draw_tex_supported && !hasPalette()) { + //GLCALL(glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)); + const GLint crop[4] = { 0, _surface.h, _surface.w, -_surface.h }; + + GLCALL(glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop)); + + // Android GLES bug? + GLCALL(glColor4ub(0xff, 0xff, 0xff, 0xff)); + + GLCALL(glDrawTexiOES(x, y, 0, w, h)); + } else +#endif + { + const GLfixed tex_width = xdiv(_surface.w, _texture_width); + const GLfixed tex_height = xdiv(_surface.h, _texture_height); + const GLfixed texcoords[] = { + 0, 0, + tex_width, 0, + 0, tex_height, + tex_width, tex_height, + }; + + GLCALL(glTexCoordPointer(2, GL_FIXED, 0, texcoords)); + + const GLshort vertices[] = { + x, y, + x + w, y, + x, y + h, + x + w, y + h, + }; + + GLCALL(glVertexPointer(2, GL_SHORT, 0, vertices)); + + assert(ARRAYSIZE(vertices) == ARRAYSIZE(texcoords)); + GLCALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, ARRAYSIZE(vertices) / 2)); + } + + clearDirty(); +} + +const Graphics::PixelFormat &GLESBaseTexture::getPixelFormat() const { + return _pixelFormat; +} + +GLESTexture::GLESTexture(GLenum glFormat, GLenum glType, + Graphics::PixelFormat pixelFormat) : + GLESBaseTexture(glFormat, glType, pixelFormat), + _pixels(0), + _buf(0) { +} + +GLESTexture::~GLESTexture() { + delete[] _buf; + delete[] _pixels; +} + +void GLESTexture::allocBuffer(GLuint w, GLuint h) { + GLuint oldw = _surface.w; + GLuint oldh = _surface.h; + + GLESBaseTexture::allocBuffer(w, h); + + if (_surface.w == oldw && _surface.h == oldh) + return; + + delete[] _buf; + delete[] _pixels; + + _pixels = new byte[w * h * _surface.bytesPerPixel]; + assert(_pixels); + + _surface.pixels = _pixels; + _surface.pitch = w * _pixelFormat.bytesPerPixel; + + _buf = new byte[w * h * _surface.bytesPerPixel]; + assert(_buf); +} + +void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, + const void *buf, int pitch_buf) { + setDirtyRect(Common::Rect(x, y, x + w, y + h)); + + const byte *src = (const byte *)buf; + byte *dst = _pixels + y * _surface.pitch + x * _surface.bytesPerPixel; + + do { + memcpy(dst, src, w * _surface.bytesPerPixel); + dst += _surface.pitch; + src += pitch_buf; + } while (--h); +} + +void GLESTexture::fillBuffer(uint32 color) { + assert(_surface.pixels); + + if (_pixelFormat.bytesPerPixel == 1 || + ((color & 0xff) == ((color >> 8) & 0xff))) + memset(_pixels, color & 0xff, _surface.pitch * _surface.h); + else + Common::set_to(_pixels, _pixels + _surface.pitch * _surface.h, + (uint16)color); + + setDirty(); +} + +void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { + if (_all_dirty) { + _dirty_rect.top = 0; + _dirty_rect.left = 0; + _dirty_rect.bottom = _surface.h; + _dirty_rect.right = _surface.w; + + _all_dirty = false; + } + + if (!_dirty_rect.isEmpty()) { + byte *_tex; + + int16 dwidth = _dirty_rect.width(); + int16 dheight = _dirty_rect.height(); + + if (dwidth == _surface.w) { + _tex = _pixels + _dirty_rect.top * _surface.pitch; + } else { + _tex = _buf; + + byte *src = _pixels + _dirty_rect.top * _surface.pitch + + _dirty_rect.left * _surface.bytesPerPixel; + byte *dst = _buf; + + uint16 l = dwidth * _surface.bytesPerPixel; + + for (uint16 i = 0; i < dheight; ++i) { + memcpy(dst, src, l); + src += _surface.pitch; + dst += l; + } + } + + GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); + GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); + + GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, + _dirty_rect.left, _dirty_rect.top, + dwidth, dheight, _glFormat, _glType, _tex)); + } + + GLESBaseTexture::drawTexture(x, y, w, h); +} + +GLES4444Texture::GLES4444Texture() : + GLESTexture(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, pixelFormat()) { +} + +GLES4444Texture::~GLES4444Texture() { +} + +GLES5551Texture::GLES5551Texture() : + GLESTexture(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, pixelFormat()) { +} + +GLES5551Texture::~GLES5551Texture() { +} + +GLES565Texture::GLES565Texture() : + GLESTexture(GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixelFormat()) { +} + +GLES565Texture::~GLES565Texture() { +} + +GLESPaletteTexture::GLESPaletteTexture(GLenum glFormat, GLenum glType, + Graphics::PixelFormat palettePixelFormat) : + GLESBaseTexture(glFormat, glType, + Graphics::PixelFormat::createFormatCLUT8()), + _texture(0) +{ + _palettePixelFormat = palettePixelFormat; + _paletteSize = _palettePixelFormat.bytesPerPixel * 256; +} + +GLESPaletteTexture::~GLESPaletteTexture() { + delete[] _texture; +} + +void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) { + GLuint oldw = _surface.w; + GLuint oldh = _surface.h; + + GLESBaseTexture::allocBuffer(w, h); + + if (_surface.w == oldw && _surface.h == oldh) + return; + + byte *new_buffer = new byte[_paletteSize + + _texture_width * _texture_height]; + assert(new_buffer); + + if (_texture) { + // preserve palette + memcpy(new_buffer, _texture, _paletteSize); + delete[] _texture; + } + + _texture = new_buffer; + _surface.pixels = _texture + _paletteSize; + _surface.pitch = _texture_width; +} + +void GLESPaletteTexture::fillBuffer(uint32 color) { + assert(_surface.pixels); + memset(_surface.pixels, color & 0xff, _surface.pitch * _surface.h); + setDirty(); +} + +void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, + const void *buf, int pitch_buf) { + setDirtyRect(Common::Rect(x, y, x + w, y + h)); + + const byte * src = static_cast<const byte *>(buf); + byte *dst = static_cast<byte *>(_surface.getBasePtr(x, y)); + + do { + memcpy(dst, src, w); + dst += _surface.pitch; + src += pitch_buf; + } while (--h); +} + +void GLESPaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, + GLshort h) { + if (dirty()) { + GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); + + const size_t texture_size = _paletteSize + + _texture_width * _texture_height; + + GLCALL(glCompressedTexImage2D(GL_TEXTURE_2D, 0, _glType, + _texture_width, _texture_height, + 0, texture_size, _texture)); + } + + GLESBaseTexture::drawTexture(x, y, w, h); +} + +GLESPalette888Texture::GLESPalette888Texture() : + GLESPaletteTexture(GL_RGB, GL_PALETTE8_RGB8_OES, + Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0)) { +} + +GLESPalette888Texture::~GLESPalette888Texture() { +} + +GLESPalette8888Texture::GLESPalette8888Texture() : + GLESPaletteTexture(GL_RGBA, GL_PALETTE8_RGBA8_OES, + Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)) { +} + +GLESPalette8888Texture::~GLESPalette8888Texture() { +} + +GLESPalette565Texture::GLESPalette565Texture() : + GLESPaletteTexture(GL_RGB, GL_PALETTE8_R5_G6_B5_OES, + Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)) { +} + +GLESPalette565Texture::~GLESPalette565Texture() { +} + +GLESPalette4444Texture::GLESPalette4444Texture() : + GLESPaletteTexture(GL_RGBA, GL_PALETTE8_RGBA4_OES, + Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0)) { +} + +GLESPalette4444Texture::~GLESPalette4444Texture() { +} + +GLESPalette5551Texture::GLESPalette5551Texture() : + GLESPaletteTexture(GL_RGBA, GL_PALETTE8_RGB5_A1_OES, + Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0)) { +} + +GLESPalette5551Texture::~GLESPalette5551Texture() { +} + +GLESFakePaletteTexture::GLESFakePaletteTexture(GLenum glFormat, GLenum glType, + Graphics::PixelFormat pixelFormat) : + GLESBaseTexture(glFormat, glType, pixelFormat), + _palette(0), + _pixels(0), + _buf(0) +{ + _palettePixelFormat = pixelFormat; + _fake_format = Graphics::PixelFormat::createFormatCLUT8(); + + _palette = new uint16[256]; + assert(_palette); + + memset(_palette, 0, 256 * 2); +} + +GLESFakePaletteTexture::~GLESFakePaletteTexture() { + delete[] _buf; + delete[] _pixels; + delete[] _palette; +} + +void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) { + GLuint oldw = _surface.w; + GLuint oldh = _surface.h; + + GLESBaseTexture::allocBuffer(w, h); + + if (_surface.w == oldw && _surface.h == oldh) + return; + + delete[] _buf; + delete[] _pixels; + + _pixels = new byte[w * h]; + assert(_pixels); + + // fixup surface, for the outside this is a CLUT8 surface + _surface.pixels = _pixels; + _surface.bytesPerPixel = 1; + _surface.pitch = w; + + _buf = new uint16[w * h]; + assert(_buf); +} + +void GLESFakePaletteTexture::fillBuffer(uint32 color) { + assert(_surface.pixels); + memset(_surface.pixels, color & 0xff, _surface.pitch * _surface.h); + setDirty(); +} + +void GLESFakePaletteTexture::updateBuffer(GLuint x, GLuint y, GLuint w, + GLuint h, const void *buf, + int pitch_buf) { + setDirtyRect(Common::Rect(x, y, x + w, y + h)); + + const byte *src = (const byte *)buf; + byte *dst = _pixels + y * _surface.pitch + x; + + do { + memcpy(dst, src, w); + dst += _surface.pitch; + src += pitch_buf; + } while (--h); +} + +void GLESFakePaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, + GLshort h) { + if (_all_dirty) { + _dirty_rect.top = 0; + _dirty_rect.left = 0; + _dirty_rect.bottom = _surface.h; + _dirty_rect.right = _surface.w; + + _all_dirty = false; + } + + if (!_dirty_rect.isEmpty()) { + int16 dwidth = _dirty_rect.width(); + int16 dheight = _dirty_rect.height(); + + byte *src = _pixels + _dirty_rect.top * _surface.pitch + + _dirty_rect.left; + uint16 *dst = _buf; + uint pitch_delta = _surface.pitch - dwidth; + + for (uint16 j = 0; j < dheight; ++j) { + for (uint16 i = 0; i < dwidth; ++i) + *dst++ = _palette[*src++]; + src += pitch_delta; + } + + GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); + + GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, + _dirty_rect.left, _dirty_rect.top, + dwidth, dheight, _glFormat, _glType, _buf)); + } + + GLESBaseTexture::drawTexture(x, y, w, h); +} + +const Graphics::PixelFormat &GLESFakePaletteTexture::getPixelFormat() const { + return _fake_format; +} + +GLESFakePalette565Texture::GLESFakePalette565Texture() : + GLESFakePaletteTexture(GL_RGB, GL_UNSIGNED_SHORT_5_6_5, + GLES565Texture::pixelFormat()) { +} + +GLESFakePalette565Texture::~GLESFakePalette565Texture() { +} + +#endif + diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h new file mode 100644 index 0000000000..64489da0a4 --- /dev/null +++ b/backends/platform/android/texture.h @@ -0,0 +1,331 @@ +/* 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 _ANDROID_TEXTURE_H_ +#define _ANDROID_TEXTURE_H_ + +#if defined(__ANDROID__) + +#include <GLES/gl.h> + +#include "graphics/surface.h" +#include "graphics/pixelformat.h" + +#include "common/rect.h" +#include "common/array.h" + +class GLESBaseTexture { +public: + static void initGLExtensions(); + +protected: + GLESBaseTexture(GLenum glFormat, GLenum glType, + Graphics::PixelFormat pixelFormat); + +public: + virtual ~GLESBaseTexture(); + + void release(); + void reinit(); + void initSize(); + + void setLinearFilter(bool value); + + virtual void allocBuffer(GLuint w, GLuint h); + + virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, + const void *buf, int pitch_buf) = 0; + virtual void fillBuffer(uint32 color) = 0; + + virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); + + inline void setDrawRect(const Common::Rect &rect) { + _draw_rect = rect; + } + + inline void setDrawRect(int16 w, int16 h) { + _draw_rect = Common::Rect(w, h); + } + + inline void setDrawRect(int16 x1, int16 y1, int16 x2, int16 y2) { + _draw_rect = Common::Rect(x1, y1, x2, y2); + } + + inline const Common::Rect &getDrawRect() const { + return _draw_rect; + } + + inline void drawTextureRect() { + drawTexture(_draw_rect.left, _draw_rect.top, + _draw_rect.width(), _draw_rect.height()); + } + + inline void drawTextureOrigin() { + drawTexture(0, 0, _surface.w, _surface.h); + } + + inline GLuint width() const { + return _surface.w; + } + + inline GLuint height() const { + return _surface.h; + } + + inline uint16 pitch() const { + return _surface.pitch; + } + + inline const Graphics::Surface *surface_const() const { + return &_surface; + } + + inline Graphics::Surface *surface() { + setDirty(); + return &_surface; + } + + virtual const byte *palette_const() const { + return 0; + }; + + virtual byte *palette() { + return 0; + }; + + inline bool hasPalette() const { + return _palettePixelFormat.bytesPerPixel > 0; + } + + inline bool dirty() const { + return _all_dirty || !_dirty_rect.isEmpty(); + } + + virtual const Graphics::PixelFormat &getPixelFormat() const; + + inline const Graphics::PixelFormat &getPalettePixelFormat() const { + return _palettePixelFormat; + } + +protected: + inline void setDirty() { + _all_dirty = true; + } + + inline void clearDirty() { + _all_dirty = false; + _dirty_rect.top = 0; + _dirty_rect.left = 0; + _dirty_rect.bottom = 0; + _dirty_rect.right = 0; + } + + inline void setDirtyRect(const Common::Rect& r) { + if (!_all_dirty) { + if (_dirty_rect.isEmpty()) + _dirty_rect = r; + else + _dirty_rect.extend(r); + } + } + + GLenum _glFormat; + GLenum _glType; + GLint _glFilter; + + GLuint _texture_name; + Graphics::Surface _surface; + GLuint _texture_width; + GLuint _texture_height; + + Common::Rect _draw_rect; + + bool _all_dirty; + Common::Rect _dirty_rect; + + Graphics::PixelFormat _pixelFormat; + Graphics::PixelFormat _palettePixelFormat; +}; + +class GLESTexture : public GLESBaseTexture { +protected: + GLESTexture(GLenum glFormat, GLenum glType, + Graphics::PixelFormat pixelFormat); + +public: + virtual ~GLESTexture(); + + virtual void allocBuffer(GLuint w, GLuint h); + + virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, + const void *buf, int pitch_buf); + virtual void fillBuffer(uint32 color); + + virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); + +protected: + byte *_pixels; + byte *_buf; +}; + +// RGBA4444 texture +class GLES4444Texture : public GLESTexture { +public: + GLES4444Texture(); + virtual ~GLES4444Texture(); + + static Graphics::PixelFormat pixelFormat() { + return Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0); + } +}; + +// RGBA5551 texture +class GLES5551Texture : public GLESTexture { +public: + GLES5551Texture(); + virtual ~GLES5551Texture(); + + static inline Graphics::PixelFormat pixelFormat() { + return Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0); + } +}; + +// RGB565 texture +class GLES565Texture : public GLESTexture { +public: + GLES565Texture(); + virtual ~GLES565Texture(); + + static inline Graphics::PixelFormat pixelFormat() { + return Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0); + } +}; + +class GLESPaletteTexture : public GLESBaseTexture { +protected: + GLESPaletteTexture(GLenum glFormat, GLenum glType, + Graphics::PixelFormat palettePixelFormat); + +public: + virtual ~GLESPaletteTexture(); + + virtual void allocBuffer(GLuint w, GLuint h); + virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, + const void *buf, int pitch_buf); + virtual void fillBuffer(uint32 color); + + virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); + + virtual const byte *palette_const() const { + return _texture; + }; + + virtual byte *palette() { + setDirty(); + return _texture; + }; + +protected: + byte *_texture; + size_t _paletteSize; +}; + +// RGB888 256-entry paletted texture +class GLESPalette888Texture : public GLESPaletteTexture { +public: + GLESPalette888Texture(); + virtual ~GLESPalette888Texture(); +}; + +// RGBA8888 256-entry paletted texture +class GLESPalette8888Texture : public GLESPaletteTexture { +public: + GLESPalette8888Texture(); + virtual ~GLESPalette8888Texture(); +}; + +// RGB565 256-entry paletted texture +class GLESPalette565Texture : public GLESPaletteTexture { +public: + GLESPalette565Texture(); + virtual ~GLESPalette565Texture(); +}; + +// RGBA4444 256-entry paletted texture +class GLESPalette4444Texture : public GLESPaletteTexture { +public: + GLESPalette4444Texture(); + virtual ~GLESPalette4444Texture(); +}; + +// RGBA5551 256-entry paletted texture +class GLESPalette5551Texture : public GLESPaletteTexture { +public: + GLESPalette5551Texture(); + virtual ~GLESPalette5551Texture(); +}; + +class GLESFakePaletteTexture : public GLESBaseTexture { +protected: + GLESFakePaletteTexture(GLenum glFormat, GLenum glType, + Graphics::PixelFormat pixelFormat); + +public: + virtual ~GLESFakePaletteTexture(); + + virtual void allocBuffer(GLuint w, GLuint h); + virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, + const void *buf, int pitch_buf); + virtual void fillBuffer(uint32 color); + + virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); + + virtual const byte *palette_const() const { + return (byte *)_palette; + }; + + virtual byte *palette() { + setDirty(); + return (byte *)_palette; + }; + + virtual const Graphics::PixelFormat &getPixelFormat() const; + +protected: + Graphics::PixelFormat _fake_format; + uint16 *_palette; + byte *_pixels; + uint16 *_buf; +}; + +class GLESFakePalette565Texture : public GLESFakePaletteTexture { +public: + GLESFakePalette565Texture(); + virtual ~GLESFakePalette565Texture(); +}; + +#endif +#endif + diff --git a/backends/platform/android/video.cpp b/backends/platform/android/video.cpp deleted file mode 100644 index f8427c2ac8..0000000000 --- a/backends/platform/android/video.cpp +++ /dev/null @@ -1,342 +0,0 @@ -/* 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$ - * - */ - -#if defined(__ANDROID__) - -#include "base/main.h" -#include "graphics/surface.h" - -#include "common/rect.h" -#include "common/array.h" -#include "common/util.h" -#include "common/tokenizer.h" - -#include "backends/platform/android/android.h" -#include "backends/platform/android/video.h" - -// Unfortunately, Android devices are too varied to make broad assumptions :/ -#define TEXSUBIMAGE_IS_EXPENSIVE 0 - -// Supported GL extensions -static bool npot_supported = false; -#ifdef GL_OES_draw_texture -static bool draw_tex_supported = false; -#endif - -static inline GLfixed xdiv(int numerator, int denominator) { - assert(numerator < (1 << 16)); - return (numerator << 16) / denominator; -} - -template <class T> -static T nextHigher2(T k) { - if (k == 0) - return 1; - --k; - - for (uint i = 1; i < sizeof(T) * CHAR_BIT; i <<= 1) - k = k | k >> i; - - return k + 1; -} - -void GLESTexture::initGLExtensions() { - const char *ext_string = - reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)); - - LOGI("Extensions: %s", ext_string); - - Common::StringTokenizer tokenizer(ext_string, " "); - while (!tokenizer.empty()) { - Common::String token = tokenizer.nextToken(); - - if (token == "GL_ARB_texture_non_power_of_two") - npot_supported = true; - -#ifdef GL_OES_draw_texture - if (token == "GL_OES_draw_texture") - draw_tex_supported = true; -#endif - } -} - -GLESTexture::GLESTexture() : - _texture_width(0), - _texture_height(0), - _all_dirty(true) -{ - GLCALL(glGenTextures(1, &_texture_name)); - - // This all gets reset later in allocBuffer: - _surface.w = 0; - _surface.h = 0; - _surface.pitch = _texture_width; - _surface.pixels = 0; - _surface.bytesPerPixel = 0; -} - -GLESTexture::~GLESTexture() { - debug("Destroying texture %u", _texture_name); - GLCALL(glDeleteTextures(1, &_texture_name)); -} - -void GLESTexture::reinitGL() { - GLCALL(glDeleteTextures(1, &_texture_name)); - GLCALL(glGenTextures(1, &_texture_name)); - - // bypass allocBuffer() shortcut to reinit the texture properly - _texture_width = 0; - _texture_height = 0; - - allocBuffer(_surface.w, _surface.h); - setDirty(); -} - -void GLESTexture::allocBuffer(GLuint w, GLuint h) { - int bpp = bytesPerPixel(); - _surface.w = w; - _surface.h = h; - _surface.bytesPerPixel = bpp; - - // Already allocated a sufficiently large buffer? - if (w <= _texture_width && h <= _texture_height) - return; - - if (npot_supported) { - _texture_width = _surface.w; - _texture_height = _surface.h; - } else { - _texture_width = nextHigher2(_surface.w); - _texture_height = nextHigher2(_surface.h); - } - - _surface.pitch = _texture_width * bpp; - - // Allocate room for the texture now, but pixel data gets uploaded - // later (perhaps with multiple TexSubImage2D operations). - GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); - GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); - GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); - GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); - GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); - GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, glFormat(), - _texture_width, _texture_height, - 0, glFormat(), glType(), 0)); -} - -void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, - const void *buf, int pitch) { - ENTER("%u, %u, %u, %u, %p, %d", x, y, w, h, buf, pitch); - - GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); - GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); - - setDirtyRect(Common::Rect(x, y, x+w, y+h)); - - if (static_cast<int>(w) * bytesPerPixel() == pitch) { - GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, - glFormat(), glType(), buf)); - } else { - // GLES removed the ability to specify pitch, so we - // have to do this ourselves. - if (h == 0) - return; - -#if TEXSUBIMAGE_IS_EXPENSIVE - byte tmpbuf[w * h * bytesPerPixel()]; - const byte *src = static_cast<const byte *>(buf); - byte *dst = tmpbuf; - GLuint count = h; - - do { - memcpy(dst, src, w * bytesPerPixel()); - dst += w * bytesPerPixel(); - src += pitch; - } while (--count); - - GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, - glFormat(), glType(), tmpbuf)); -#else - // This version avoids the intermediate copy at the expense of - // repeat glTexSubImage2D calls. On some devices this is worse. - const byte *src = static_cast<const byte *>(buf); - do { - GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, - w, 1, glFormat(), glType(), src)); - ++y; - src += pitch; - } while (--h); -#endif - } -} - -void GLESTexture::fillBuffer(byte x) { - int rowbytes = _surface.w * bytesPerPixel(); - byte tmpbuf[_surface.h * rowbytes]; - memset(tmpbuf, x, _surface.h * rowbytes); - updateBuffer(0, 0, _surface.w, _surface.h, tmpbuf, rowbytes); -} - -void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { - GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); - -#ifdef GL_OES_draw_texture - // Great extension, but only works under specific conditions. - // Still a work-in-progress - disabled for now. - if (false && draw_tex_supported && paletteSize() == 0) { - //GLCALL(glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)); - const GLint crop[4] = { 0, _surface.h, _surface.w, -_surface.h }; - - GLCALL(glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop)); - - // Android GLES bug? - GLCALL(glColor4ub(0xff, 0xff, 0xff, 0xff)); - - GLCALL(glDrawTexiOES(x, y, 0, w, h)); - } else -#endif - { - const GLfixed tex_width = xdiv(_surface.w, _texture_width); - const GLfixed tex_height = xdiv(_surface.h, _texture_height); - const GLfixed texcoords[] = { - 0, 0, - tex_width, 0, - 0, tex_height, - tex_width, tex_height, - }; - - GLCALL(glTexCoordPointer(2, GL_FIXED, 0, texcoords)); - - const GLshort vertices[] = { - x, y, - x + w, y, - x, y + h, - x + w, y + h, - }; - - GLCALL(glVertexPointer(2, GL_SHORT, 0, vertices)); - - assert(ARRAYSIZE(vertices) == ARRAYSIZE(texcoords)); - GLCALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, ARRAYSIZE(vertices) / 2)); - } - - _all_dirty = false; - _dirty_rect = Common::Rect(); -} - -GLESPaletteTexture::GLESPaletteTexture() : - GLESTexture(), - _texture(0) -{ -} - -GLESPaletteTexture::~GLESPaletteTexture() { - delete[] _texture; -} - -void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) { - int bpp = bytesPerPixel(); - _surface.w = w; - _surface.h = h; - _surface.bytesPerPixel = bpp; - - // Already allocated a sufficiently large buffer? - if (w <= _texture_width && h <= _texture_height) - return; - - if (npot_supported) { - _texture_width = _surface.w; - _texture_height = _surface.h; - } else { - _texture_width = nextHigher2(_surface.w); - _texture_height = nextHigher2(_surface.h); - } - _surface.pitch = _texture_width * bpp; - - // Texture gets uploaded later (from drawTexture()) - - byte *new_buffer = new byte[paletteSize() + - _texture_width * _texture_height * bytesPerPixel()]; - if (_texture) { - // preserve palette - memcpy(new_buffer, _texture, paletteSize()); - delete[] _texture; - } - - _texture = new_buffer; - _surface.pixels = _texture + paletteSize(); -} - -void GLESPaletteTexture::fillBuffer(byte x) { - assert(_surface.pixels); - memset(_surface.pixels, x, _surface.pitch * _surface.h); - setDirty(); -} - -void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y, - GLuint w, GLuint h, - const void *buf, int pitch) { - _all_dirty = true; - - const byte * src = static_cast<const byte *>(buf); - byte *dst = static_cast<byte *>(_surface.getBasePtr(x, y)); - - do { - memcpy(dst, src, w * bytesPerPixel()); - dst += _surface.pitch; - src += pitch; - } while (--h); -} - -void GLESPaletteTexture::uploadTexture() const { - const size_t texture_size = - paletteSize() + _texture_width * _texture_height * bytesPerPixel(); - - GLCALL(glCompressedTexImage2D(GL_TEXTURE_2D, 0, glType(), - _texture_width, _texture_height, - 0, texture_size, _texture)); -} - -void GLESPaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { - if (_all_dirty) { - GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); - GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, - GL_NEAREST)); - GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - GL_NEAREST)); - GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE)); - GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE)); - uploadTexture(); - _all_dirty = false; - } - - GLESTexture::drawTexture(x, y, w, h); -} - -#endif - diff --git a/backends/platform/android/video.h b/backends/platform/android/video.h deleted file mode 100644 index da42ea876d..0000000000 --- a/backends/platform/android/video.h +++ /dev/null @@ -1,209 +0,0 @@ -/* 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$ - * - */ - -#if defined(__ANDROID__) - -#include <GLES/gl.h> - -#include "graphics/surface.h" - -#include "common/rect.h" -#include "common/array.h" - -class GLESTexture { -public: - static void initGLExtensions(); - - GLESTexture(); - virtual ~GLESTexture(); - - virtual void reinitGL(); - virtual void allocBuffer(GLuint width, GLuint height); - - virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, - const void *buf, int pitch); - virtual void fillBuffer(byte x); - - virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); - - inline GLuint width() const { - return _surface.w; - } - - inline GLuint height() const { - return _surface.h; - } - - inline GLuint texture_name() const { - return _texture_name; - } - - inline const Graphics::Surface *surface_const() const { - return &_surface; - } - - inline Graphics::Surface *surface() { - setDirty(); - return &_surface; - } - - inline bool dirty() const { - return _all_dirty || !_dirty_rect.isEmpty(); - } - - inline void drawTexture() { - drawTexture(0, 0, _surface.w, _surface.h); - } - -protected: - virtual byte bytesPerPixel() const = 0; - virtual GLenum glFormat() const = 0; - virtual GLenum glType() const = 0; - - virtual size_t paletteSize() const { - return 0; - } - - inline void setDirty() { - _all_dirty = true; - _dirty_rect = Common::Rect(); - } - - inline void setDirtyRect(const Common::Rect& r) { - if (!_all_dirty) { - if (_dirty_rect.isEmpty()) - _dirty_rect = r; - else - _dirty_rect.extend(r); - } - } - - GLuint _texture_name; - Graphics::Surface _surface; - GLuint _texture_width; - GLuint _texture_height; - bool _all_dirty; - - // Covers dirty area - Common::Rect _dirty_rect; -}; - -// RGBA4444 texture -class GLES4444Texture : public GLESTexture { -protected: - virtual byte bytesPerPixel() const { - return 2; - } - - virtual GLenum glFormat() const { - return GL_RGBA; - } - - virtual GLenum glType() const { - return GL_UNSIGNED_SHORT_4_4_4_4; - } -}; - -// RGB565 texture -class GLES565Texture : public GLESTexture { -protected: - virtual byte bytesPerPixel() const { - return 2; - } - - virtual GLenum glFormat() const { - return GL_RGB; - } - - virtual GLenum glType() const { - return GL_UNSIGNED_SHORT_5_6_5; - } -}; - -// RGB888 256-entry paletted texture -class GLESPaletteTexture : public GLESTexture { -public: - GLESPaletteTexture(); - virtual ~GLESPaletteTexture(); - - virtual void allocBuffer(GLuint width, GLuint height); - virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height, - const void *buf, int pitch); - virtual void fillBuffer(byte x); - - virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); - - inline void drawTexture() { - drawTexture(0, 0, _surface.w, _surface.h); - } - - inline const byte *palette_const() const { - return _texture; - }; - - inline byte *palette() { - setDirty(); - return _texture; - }; - -protected: - virtual byte bytesPerPixel() const { - return 1; - } - - virtual GLenum glFormat() const { - return GL_RGB; - } - - virtual GLenum glType() const { - return GL_PALETTE8_RGB8_OES; - } - - virtual size_t paletteSize() const { - return 256 * 3; - } - - void uploadTexture() const; - - byte *_texture; -}; - -// RGBA8888 256-entry paletted texture -class GLESPaletteATexture : public GLESPaletteTexture { -protected: - virtual GLenum glFormat() const { - return GL_RGBA; - } - - virtual GLenum glType() const { - return GL_PALETTE8_RGBA8_OES; - } - - virtual size_t paletteSize() const { - return 256 * 4; - } -}; - -#endif diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index dc91bd9fe7..bddb48ca95 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -125,10 +125,10 @@ void OSystem_SDL::init() { if (_timerManager == 0) _timerManager = new SdlTimerManager(); - #ifdef USE_OPENGL - // Setup a list with both SDL and OpenGL graphics modes - setupGraphicsModes(); - #endif +#ifdef USE_OPENGL + // Setup a list with both SDL and OpenGL graphics modes + setupGraphicsModes(); +#endif } void OSystem_SDL::initBackend() { @@ -148,11 +148,15 @@ void OSystem_SDL::initBackend() { Common::String gfxMode(ConfMan.get("gfx_mode")); bool use_opengl = false; const OSystem::GraphicsMode *mode = OpenGLSdlGraphicsManager::supportedGraphicsModes(); + int i = 0; while (mode->name) { - if (scumm_stricmp(mode->name, gfxMode.c_str()) == 0) + if (scumm_stricmp(mode->name, gfxMode.c_str()) == 0) { + _graphicsMode = i + _sdlModesCount; use_opengl = true; + } mode++; + ++i; } // If the gfx_mode is from OpenGL, create the OpenGL graphics manager @@ -464,6 +468,7 @@ int OSystem_SDL::getDefaultGraphicsMode() const { bool OSystem_SDL::setGraphicsMode(int mode) { const OSystem::GraphicsMode *srcMode; int i; + // Check if mode is from SDL or OpenGL if (mode < _sdlModesCount) { srcMode = SdlGraphicsManager::supportedGraphicsModes(); @@ -472,28 +477,34 @@ bool OSystem_SDL::setGraphicsMode(int mode) { srcMode = OpenGLSdlGraphicsManager::supportedGraphicsModes(); i = _sdlModesCount; } + // Loop through modes while (srcMode->name) { if (i == mode) { // If the new mode and the current mode are not from the same graphics // manager, delete and create the new mode graphics manager if (_graphicsMode >= _sdlModesCount && mode < _sdlModesCount) { + debug(1, "switching to plain SDL graphics"); delete _graphicsManager; _graphicsManager = new SdlGraphicsManager(_eventSource); ((SdlGraphicsManager *)_graphicsManager)->initEventObserver(); _graphicsManager->beginGFXTransaction(); } else if (_graphicsMode < _sdlModesCount && mode >= _sdlModesCount) { + debug(1, "switching to OpenGL graphics"); delete _graphicsManager; _graphicsManager = new OpenGLSdlGraphicsManager(); ((OpenGLSdlGraphicsManager *)_graphicsManager)->initEventObserver(); _graphicsManager->beginGFXTransaction(); } + _graphicsMode = mode; return _graphicsManager->setGraphicsMode(srcMode->id); } + i++; srcMode++; } + return false; } diff --git a/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in b/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in index c7623d09a8..12b4cb3610 100644 --- a/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in +++ b/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in @@ -91,7 +91,7 @@ STATICLIBRARY esdl.lib // *** Include paths USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\engines -USERINCLUDE ..\..\..\..\backends\fs ..\src ..\..\..\..\backends\platform\sdl ..\..\..\..\sound +USERINCLUDE ..\..\..\..\backends\fs ..\src ..\..\..\..\backends\platform\sdl ..\..\..\..\audio SYSTEMINCLUDE \epoc32\include\ESDL SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version diff --git a/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in b/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in index 6f14e858b0..9af6535b22 100644 --- a/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in +++ b/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in @@ -91,7 +91,7 @@ STATICLIBRARY esdl.lib // *** Include paths USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\engines -USERINCLUDE ..\..\..\..\backends\fs ..\src ..\..\..\..\backends\platform\sdl ..\..\..\..\sound +USERINCLUDE ..\..\..\..\backends\fs ..\src ..\..\..\..\backends\platform\sdl ..\..\..\..\audio SYSTEMINCLUDE \epoc32\include\ESDL SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version diff --git a/backends/platform/symbian/mmp/scummvm_agi.mmp.in b/backends/platform/symbian/mmp/scummvm_agi.mmp.in index 044326405d..e2d98b9ae4 100644 --- a/backends/platform/symbian/mmp/scummvm_agi.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_agi.mmp.in @@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\agi // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_agos.mmp.in b/backends/platform/symbian/mmp/scummvm_agos.mmp.in index e2d1e5eff4..077111d783 100644 --- a/backends/platform/symbian/mmp/scummvm_agos.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_agos.mmp.in @@ -65,6 +65,6 @@ SOURCEPATH ..\..\..\..\engines\agos // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_base.mmp.in b/backends/platform/symbian/mmp/scummvm_base.mmp.in index d25cef4ffe..b3bfbab530 100644 --- a/backends/platform/symbian/mmp/scummvm_base.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_base.mmp.in @@ -51,7 +51,7 @@ ALWAYS_BUILD_AS_ARM // *** Include paths -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio USERINCLUDE ..\..\..\..\backends\fs ..\src ..\..\..\..\backends\platform\sdl SYSTEMINCLUDE \epoc32\include\ESDL @@ -95,7 +95,7 @@ SOURCEPATH ..\..\..\..\gui //SOURCE KeysDialog.cpp //SOURCE Actions.cpp -SOURCEPATH ..\..\..\..\sound +SOURCEPATH ..\..\..\..\audio //START_AUTO_OBJECTS_SOUND_// // empty base file, will be updated by Perl build scripts @@ -110,6 +110,12 @@ SOURCE rate_arm.cpp // ARM version: add ASM .cpp wrapper SOURCE rate_arm_asm.s // ARM version: add ASM routines #endif +SOURCEPATH ..\..\..\..\video +//START_AUTO_OBJECTS_VIDEO_// + + // empty base file, will be updated by Perl build scripts + +//STOP_AUTO_OBJECTS_VIDEO_// // add a few files manually, since they are not parsed from modules.mk files SOURCEPATH ..\..\..\.. diff --git a/backends/platform/symbian/mmp/scummvm_cine.mmp.in b/backends/platform/symbian/mmp/scummvm_cine.mmp.in index d114ec554b..2c8118ef13 100644 --- a/backends/platform/symbian/mmp/scummvm_cine.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_cine.mmp.in @@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\cine // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_cruise.mmp.in b/backends/platform/symbian/mmp/scummvm_cruise.mmp.in index e4c836a68b..b43a867da3 100644 --- a/backends/platform/symbian/mmp/scummvm_cruise.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_cruise.mmp.in @@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\cruise // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_draci.mmp.in b/backends/platform/symbian/mmp/scummvm_draci.mmp.in index b10eb0b5a8..9f24927f27 100644 --- a/backends/platform/symbian/mmp/scummvm_draci.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_draci.mmp.in @@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\draci // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_drascula.mmp.in b/backends/platform/symbian/mmp/scummvm_drascula.mmp.in index 529eeb9e0b..d8cc6da6ae 100644 --- a/backends/platform/symbian/mmp/scummvm_drascula.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_drascula.mmp.in @@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\drascula // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_gob.mmp.in b/backends/platform/symbian/mmp/scummvm_gob.mmp.in index fa2ce0dedf..ce94f85283 100644 --- a/backends/platform/symbian/mmp/scummvm_gob.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_gob.mmp.in @@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\gob // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_groovie.mmp.in b/backends/platform/symbian/mmp/scummvm_groovie.mmp.in index 7a03cc1745..7229edf4aa 100644 --- a/backends/platform/symbian/mmp/scummvm_groovie.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_groovie.mmp.in @@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\groovie // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_hugo.mmp.in b/backends/platform/symbian/mmp/scummvm_hugo.mmp.in index 301d23cab4..b3f9edd1e6 100644 --- a/backends/platform/symbian/mmp/scummvm_hugo.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_hugo.mmp.in @@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\hugo // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_kyra.mmp.in b/backends/platform/symbian/mmp/scummvm_kyra.mmp.in index 5fa5fdac6a..654632c229 100644 --- a/backends/platform/symbian/mmp/scummvm_kyra.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_kyra.mmp.in @@ -65,5 +65,5 @@ SOURCEPATH ..\..\..\..\engines\kyra // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_lastexpress.mmp.in b/backends/platform/symbian/mmp/scummvm_lastexpress.mmp.in index a297137f02..418730c064 100644 --- a/backends/platform/symbian/mmp/scummvm_lastexpress.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_lastexpress.mmp.in @@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\lastexpress // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_lure.mmp.in b/backends/platform/symbian/mmp/scummvm_lure.mmp.in index c4a3900a05..e1a63b602b 100644 --- a/backends/platform/symbian/mmp/scummvm_lure.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_lure.mmp.in @@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\lure // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_m4.mmp.in b/backends/platform/symbian/mmp/scummvm_m4.mmp.in index f4430f2e58..c2e1ce4e8b 100644 --- a/backends/platform/symbian/mmp/scummvm_m4.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_m4.mmp.in @@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\m4 // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_made.mmp.in b/backends/platform/symbian/mmp/scummvm_made.mmp.in index bf50157224..91b9ca756d 100644 --- a/backends/platform/symbian/mmp/scummvm_made.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_made.mmp.in @@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\made // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_mohawk.mmp.in b/backends/platform/symbian/mmp/scummvm_mohawk.mmp.in index 78e931b06f..0edba5eb4d 100644 --- a/backends/platform/symbian/mmp/scummvm_mohawk.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_mohawk.mmp.in @@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\mohawk // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_parallaction.mmp.in b/backends/platform/symbian/mmp/scummvm_parallaction.mmp.in index e96ab907cd..744a756f4e 100644 --- a/backends/platform/symbian/mmp/scummvm_parallaction.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_parallaction.mmp.in @@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\parallaction // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_queen.mmp.in b/backends/platform/symbian/mmp/scummvm_queen.mmp.in index 4f9d9319e0..bf88744701 100644 --- a/backends/platform/symbian/mmp/scummvm_queen.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_queen.mmp.in @@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\queen // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_saga.mmp.in b/backends/platform/symbian/mmp/scummvm_saga.mmp.in index e5beefc0c5..a95ee1e7fd 100644 --- a/backends/platform/symbian/mmp/scummvm_saga.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_saga.mmp.in @@ -71,5 +71,5 @@ SOURCEPATH ..\..\..\..\engines\saga // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_sci.mmp.in b/backends/platform/symbian/mmp/scummvm_sci.mmp.in index eb0d1b020f..ca9e712f3f 100644 --- a/backends/platform/symbian/mmp/scummvm_sci.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_sci.mmp.in @@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\sci // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_scumm.mmp.in b/backends/platform/symbian/mmp/scummvm_scumm.mmp.in index 6b5d249422..0a3cd9bb7d 100644 --- a/backends/platform/symbian/mmp/scummvm_scumm.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_scumm.mmp.in @@ -82,7 +82,7 @@ SOURCE smush/codec47ARM.s // ARM version: add ASM routines // *** Include paths USERINCLUDE ..\..\..\..\engines ..\..\..\..\engines\scumm\smush ..\..\..\..\engines\scumm\insane -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version SYSTEMINCLUDE \epoc32\include\libc diff --git a/backends/platform/symbian/mmp/scummvm_sky.mmp.in b/backends/platform/symbian/mmp/scummvm_sky.mmp.in index d1d222b1fa..1bc2301745 100644 --- a/backends/platform/symbian/mmp/scummvm_sky.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_sky.mmp.in @@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\sky // *** Include paths USERINCLUDE ..\..\..\..\engines ..\..\..\..\engines\sky\music -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_sword1.mmp.in b/backends/platform/symbian/mmp/scummvm_sword1.mmp.in index 0aaf9d504b..6bf543070b 100644 --- a/backends/platform/symbian/mmp/scummvm_sword1.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_sword1.mmp.in @@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\sword1 // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_sword2.mmp.in b/backends/platform/symbian/mmp/scummvm_sword2.mmp.in index 4a7181709f..cee4143f94 100644 --- a/backends/platform/symbian/mmp/scummvm_sword2.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_sword2.mmp.in @@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\sword2 // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_teenagent.mmp.in b/backends/platform/symbian/mmp/scummvm_teenagent.mmp.in index 7832fc4880..fa4ef79692 100644 --- a/backends/platform/symbian/mmp/scummvm_teenagent.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_teenagent.mmp.in @@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\teenagent // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_tinsel.mmp.in b/backends/platform/symbian/mmp/scummvm_tinsel.mmp.in index 6190ec8152..569b79ba3c 100644 --- a/backends/platform/symbian/mmp/scummvm_tinsel.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_tinsel.mmp.in @@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\tinsel // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_toon.mmp.in b/backends/platform/symbian/mmp/scummvm_toon.mmp.in index f2301c4ae2..f309e6d0fa 100644 --- a/backends/platform/symbian/mmp/scummvm_toon.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_toon.mmp.in @@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\toon // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_touche.mmp.in b/backends/platform/symbian/mmp/scummvm_touche.mmp.in index 9e4c3d0496..ab42afe304 100644 --- a/backends/platform/symbian/mmp/scummvm_touche.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_touche.mmp.in @@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\touche // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/symbian/mmp/scummvm_tucker.mmp.in b/backends/platform/symbian/mmp/scummvm_tucker.mmp.in index d193ac49a9..434072bc96 100644 --- a/backends/platform/symbian/mmp/scummvm_tucker.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_tucker.mmp.in @@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\tucker // *** Include paths USERINCLUDE ..\..\..\..\engines -USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src diff --git a/backends/platform/wince/CEActionsPocket.cpp b/backends/platform/wince/CEActionsPocket.cpp index 99d0be2bdc..3895c7d6fa 100644 --- a/backends/platform/wince/CEActionsPocket.cpp +++ b/backends/platform/wince/CEActionsPocket.cpp @@ -38,7 +38,7 @@ #ifdef _WIN32_WCE -#define KEY_ALL_SKIP 3457 +#define KEY_ALL_SKIP 3457 #endif const Common::String pocketActionNames[] = { @@ -85,14 +85,14 @@ int CEActionsPocket::version() { } CEActionsPocket::CEActionsPocket(const Common::String &gameid) : -GUI::Actions() { + GUI::Actions() { int i; _right_click_needed = false; _hide_toolbar_needed = false; _zoom_needed = false; - for (i=0; i<POCKET_ACTION_LAST; i++) { + for (i = 0; i < POCKET_ACTION_LAST; i++) { _action_mapping[i] = 0; _action_enabled[i] = false; } @@ -112,7 +112,7 @@ GUI::Actions() { void CEActionsPocket::initInstanceMain(OSystem *mainSystem) { // Nothing generic to do for Pocket PC - _CESystem = static_cast<OSystem_WINCE3*>(mainSystem); + _CESystem = static_cast<OSystem_WINCE3 *>(mainSystem); GUI_Actions::initInstanceMain(mainSystem); } @@ -126,7 +126,7 @@ void CEActionsPocket::initInstanceGame() { bool is_comi = (strncmp(gameid.c_str(), "comi", 4) == 0); bool is_gob = (strncmp(gameid.c_str(), "gob", 3) == 0); bool is_saga = (gameid == "saga"); - bool is_kyra = (strncmp(gameid.c_str(), "kyra",4) == 0); + bool is_kyra = (strncmp(gameid.c_str(), "kyra", 4) == 0); bool is_samnmax = (gameid == "samnmax"); bool is_cine = (gameid == "cine"); bool is_touche = (gameid == "touche"); @@ -134,7 +134,7 @@ void CEActionsPocket::initInstanceGame() { bool is_parallaction = (gameid == "parallaction"); bool is_lure = (gameid == "lure"); bool is_feeble = (gameid == "feeble"); - bool is_drascula = (strncmp(gameid.c_str(), "drascula",8) == 0); + bool is_drascula = (strncmp(gameid.c_str(), "drascula", 8) == 0); bool is_tucker = (gameid == "tucker"); bool is_groovie = (gameid == "groovie"); bool is_tinsel = (gameid == "tinsel"); @@ -145,7 +145,7 @@ void CEActionsPocket::initInstanceGame() { // See if a right click mapping could be needed if (is_sword1 || is_sword2 || is_sky || is_queen || is_comi || is_gob || is_tinsel || - is_samnmax || is_cine || is_touche || is_parallaction || is_drascula || is_cruise) + is_samnmax || is_cine || is_touche || is_parallaction || is_drascula || is_cruise) _right_click_needed = true; // See if a "hide toolbar" mapping could be needed @@ -187,7 +187,7 @@ void CEActionsPocket::initInstanceGame() { if (!is_cine && !is_parallaction && !is_groovie && !is_cruise && !is_made) _action_enabled[POCKET_ACTION_SKIP] = true; if (is_simon || is_sky || is_sword2 || is_queen || is_sword1 || is_gob || is_tinsel || - is_saga || is_kyra || is_touche || is_lure || is_feeble || is_drascula || is_tucker) + is_saga || is_kyra || is_touche || is_lure || is_feeble || is_drascula || is_tucker) _key_action[POCKET_ACTION_SKIP].setKey(VK_ESCAPE); else _key_action[POCKET_ACTION_SKIP].setKey(KEY_ALL_SKIP); @@ -239,10 +239,12 @@ bool CEActionsPocket::perform(GUI::ActionType action, bool pushed) { if (!pushed) { switch (action) { case POCKET_ACTION_RIGHTCLICK: - _CESystem->add_right_click(false); + //_CESystem->add_right_click(false); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->add_right_click(false); return true; case POCKET_ACTION_LEFTCLICK: - _CESystem->add_left_click(false); + //_CESystem->add_left_click(false); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->add_left_click(false); return true; case POCKET_ACTION_PAUSE: case POCKET_ACTION_SAVE: @@ -272,43 +274,55 @@ bool CEActionsPocket::perform(GUI::ActionType action, bool pushed) { EventsBuffer::simulateKey(&_key_action[action], true); return true; case POCKET_ACTION_KEYBOARD: - _CESystem->swap_panel(); + //_CESystem->swap_panel(); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->swap_panel(); return true; case POCKET_ACTION_HIDE: - _CESystem->swap_panel_visibility(); + //_CESystem->swap_panel_visibility(); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->swap_panel_visibility(); return true; case POCKET_ACTION_SOUND: _CESystem->swap_sound_master(); return true; case POCKET_ACTION_RIGHTCLICK: - _CESystem->add_right_click(true); + //_CESystem->add_right_click(true); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->add_right_click(true); return true; case POCKET_ACTION_CURSOR: - _CESystem->swap_mouse_visibility(); + //_CESystem->swap_mouse_visibility(); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->swap_mouse_visibility(); return true; case POCKET_ACTION_FREELOOK: - _CESystem->swap_freeLook(); + //_CESystem->swap_freeLook(); + ((WINCESdlEventSource *)((OSystem_SDL *)g_system)->getEventManager())->swap_freeLook(); return true; case POCKET_ACTION_ZOOM_UP: - _CESystem->swap_zoom_up(); + //_CESystem->swap_zoom_up(); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->swap_zoom_up(); return true; case POCKET_ACTION_ZOOM_DOWN: - _CESystem->swap_zoom_down(); + //_CESystem->swap_zoom_down(); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->swap_zoom_down(); return true; case POCKET_ACTION_LEFTCLICK: - _CESystem->add_left_click(true); + //_CESystem->add_left_click(true); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->add_left_click(true); return true; case POCKET_ACTION_UP: - _CESystem->move_cursor_up(); + //_CESystem->move_cursor_up(); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->move_cursor_up(); return true; case POCKET_ACTION_DOWN: - _CESystem->move_cursor_down(); + //_CESystem->move_cursor_down(); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->move_cursor_down(); return true; case POCKET_ACTION_LEFT: - _CESystem->move_cursor_left(); + //_CESystem->move_cursor_left(); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->move_cursor_left(); return true; case POCKET_ACTION_RIGHT: - _CESystem->move_cursor_right(); + //_CESystem->move_cursor_right(); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->move_cursor_right(); return true; case POCKET_ACTION_QUIT: if (!quitdialog) { diff --git a/backends/platform/wince/CEActionsSmartphone.cpp b/backends/platform/wince/CEActionsSmartphone.cpp index 5c7feb4950..413c52af2b 100644 --- a/backends/platform/wince/CEActionsSmartphone.cpp +++ b/backends/platform/wince/CEActionsSmartphone.cpp @@ -36,7 +36,7 @@ #include "common/translation.h" -#define KEY_ALL_SKIP 3457 +#define KEY_ALL_SKIP 3457 const String smartphoneActionNames[] = { _s("Up"), @@ -79,10 +79,10 @@ int CEActionsSmartphone::version() { } CEActionsSmartphone::CEActionsSmartphone() -: GUI::Actions() { + : GUI::Actions() { int i; - for (i=0; i<SMARTPHONE_ACTION_LAST; i++) { + for (i = 0; i < SMARTPHONE_ACTION_LAST; i++) { _action_mapping[i] = ACTIONS_SMARTPHONE_DEFAULT[i]; _action_enabled[i] = false; } @@ -90,7 +90,7 @@ CEActionsSmartphone::CEActionsSmartphone() } void CEActionsSmartphone::initInstanceMain(OSystem *mainSystem) { - _CESystem = static_cast<OSystem_WINCE3*>(mainSystem); + _CESystem = static_cast<OSystem_WINCE3 *>(mainSystem); GUI_Actions::initInstanceMain(mainSystem); @@ -117,7 +117,7 @@ void CEActionsSmartphone::initInstanceGame() { bool is_comi = (strncmp(gameid.c_str(), "comi", 4) == 0); bool is_gob = (strncmp(gameid.c_str(), "gob", 3) == 0); bool is_saga = (gameid == "saga"); - bool is_kyra = (strncmp(gameid.c_str(), "kyra",4) == 0); + bool is_kyra = (strncmp(gameid.c_str(), "kyra", 4) == 0); bool is_samnmax = (gameid == "samnmax"); bool is_cine = (gameid == "cine"); bool is_touche = (gameid == "touche"); @@ -125,7 +125,7 @@ void CEActionsSmartphone::initInstanceGame() { bool is_parallaction = (gameid == "parallaction"); bool is_lure = (gameid == "lure"); bool is_feeble = (gameid == "feeble"); - bool is_drascula = (strncmp(gameid.c_str(), "drascula",8) == 0); + bool is_drascula = (strncmp(gameid.c_str(), "drascula", 8) == 0); bool is_tucker = (gameid == "tucker"); bool is_groovie = (gameid == "groovie"); bool is_tinsel = (gameid == "tinsel"); @@ -136,7 +136,7 @@ void CEActionsSmartphone::initInstanceGame() { // See if a right click mapping could be needed if (is_sword1 || is_sword2 || is_sky || is_queen || is_comi || is_gob || is_tinsel || - is_samnmax || is_cine || is_touche || is_parallaction || is_drascula || is_cruise) + is_samnmax || is_cine || is_touche || is_parallaction || is_drascula || is_cruise) _right_click_needed = true; // Initialize keys for different actions @@ -168,8 +168,8 @@ void CEActionsSmartphone::initInstanceGame() { // Skip _action_enabled[SMARTPHONE_ACTION_SKIP] = true; if (is_simon || is_sky || is_sword2 || is_queen || is_sword1 || is_gob || is_tinsel || - is_saga || is_kyra || is_touche || is_lure || is_feeble || is_drascula || is_tucker || - is_groovie || is_cruise || is_made) + is_saga || is_kyra || is_touche || is_lure || is_feeble || is_drascula || is_tucker || + is_groovie || is_cruise || is_made) _key_action[SMARTPHONE_ACTION_SKIP].setKey(VK_ESCAPE); else _key_action[SMARTPHONE_ACTION_SKIP].setKey(KEY_ALL_SKIP); @@ -204,81 +204,92 @@ bool CEActionsSmartphone::perform(GUI::ActionType action, bool pushed) { if (!pushed) { switch (action) { - case SMARTPHONE_ACTION_RIGHTCLICK: - _CESystem->add_right_click(false); - return true; - case SMARTPHONE_ACTION_LEFTCLICK: - _CESystem->add_left_click(false); - return true; - case SMARTPHONE_ACTION_SAVE: - case SMARTPHONE_ACTION_SKIP: - case SMARTPHONE_ACTION_MULTI: - EventsBuffer::simulateKey(&_key_action[action], false); - return true; - } - return false; - } - - switch (action) { - case SMARTPHONE_ACTION_SAVE: - case SMARTPHONE_ACTION_SKIP: - case SMARTPHONE_ACTION_MULTI: - if (action == SMARTPHONE_ACTION_SAVE && ConfMan.get("gameid") == "parallaction") { - // FIXME: This is a temporary solution. The engine should handle its own menus. - // Note that the user can accomplish this via the virtual keyboard as well, this is just for convenience - GUI::MessageDialog alert(_("Do you want to load or save the game?"), _("Load"), _("Save")); - if (alert.runModal() == GUI::kMessageOK) - _key_action[action].setKey(SDLK_l); - else - _key_action[action].setKey(SDLK_s); - } - EventsBuffer::simulateKey(&_key_action[action], true); - return true; case SMARTPHONE_ACTION_RIGHTCLICK: - _CESystem->add_right_click(true); + //_CESystem->add_right_click(false); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->add_right_click(false); return true; case SMARTPHONE_ACTION_LEFTCLICK: - _CESystem->add_left_click(true); - return true; - case SMARTPHONE_ACTION_UP: - _CESystem->move_cursor_up(); - return true; - case SMARTPHONE_ACTION_DOWN: - _CESystem->move_cursor_down(); - return true; - case SMARTPHONE_ACTION_LEFT: - _CESystem->move_cursor_left(); - return true; - case SMARTPHONE_ACTION_RIGHT: - _CESystem->move_cursor_right(); - return true; - case SMARTPHONE_ACTION_ZONE: - _CESystem->switch_zone(); + //_CESystem->add_left_click(false); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->add_left_click(false); return true; - case SMARTPHONE_ACTION_BINDKEYS: - if (!keydialogrunning) { - keydialogrunning = true; - GUI::KeysDialog *keysDialog = new GUI::KeysDialog(); - keysDialog->runModal(); - delete keysDialog; - keydialogrunning = false; - } - return true; - case SMARTPHONE_ACTION_KEYBOARD: - _CESystem->swap_smartphone_keyboard(); - return true; - case SMARTPHONE_ACTION_ROTATE: - _CESystem->smartphone_rotate_display(); - return true; - case SMARTPHONE_ACTION_QUIT: - if (!quitdialog) { - quitdialog = true; - GUI::MessageDialog alert(_(" Are you sure you want to quit ? "), _("Yes"), _("No")); - if (alert.runModal() == GUI::kMessageOK) - _mainSystem->quit(); - quitdialog = false; - } + case SMARTPHONE_ACTION_SAVE: + case SMARTPHONE_ACTION_SKIP: + case SMARTPHONE_ACTION_MULTI: + EventsBuffer::simulateKey(&_key_action[action], false); return true; + } + return false; + } + + switch (action) { + case SMARTPHONE_ACTION_SAVE: + case SMARTPHONE_ACTION_SKIP: + case SMARTPHONE_ACTION_MULTI: + if (action == SMARTPHONE_ACTION_SAVE && ConfMan.get("gameid") == "parallaction") { + // FIXME: This is a temporary solution. The engine should handle its own menus. + // Note that the user can accomplish this via the virtual keyboard as well, this is just for convenience + GUI::MessageDialog alert(_("Do you want to load or save the game?"), _("Load"), _("Save")); + if (alert.runModal() == GUI::kMessageOK) + _key_action[action].setKey(SDLK_l); + else + _key_action[action].setKey(SDLK_s); + } + EventsBuffer::simulateKey(&_key_action[action], true); + return true; + case SMARTPHONE_ACTION_RIGHTCLICK: + //_CESystem->add_right_click(true); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->add_right_click(true); + return true; + case SMARTPHONE_ACTION_LEFTCLICK: + //_CESystem->add_left_click(true); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->add_left_click(true); + return true; + case SMARTPHONE_ACTION_UP: + //_CESystem->move_cursor_up(); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->move_cursor_up(); + return true; + case SMARTPHONE_ACTION_DOWN: + //_CESystem->move_cursor_down(); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->move_cursor_down(); + return true; + case SMARTPHONE_ACTION_LEFT: + //_CESystem->move_cursor_left(); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->move_cursor_left(); + return true; + case SMARTPHONE_ACTION_RIGHT: + //_CESystem->move_cursor_right(); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->move_cursor_right(); + return true; + case SMARTPHONE_ACTION_ZONE: + //_CESystem->switch_zone(); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->switch_zone(); + return true; + case SMARTPHONE_ACTION_BINDKEYS: + if (!keydialogrunning) { + keydialogrunning = true; + GUI::KeysDialog *keysDialog = new GUI::KeysDialog(); + keysDialog->runModal(); + delete keysDialog; + keydialogrunning = false; + } + return true; + case SMARTPHONE_ACTION_KEYBOARD: + //_CESystem->swap_smartphone_keyboard(); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->swap_smartphone_keyboard(); + return true; + case SMARTPHONE_ACTION_ROTATE: + //_CESystem->smartphone_rotate_display(); + ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->smartphone_rotate_display(); + return true; + case SMARTPHONE_ACTION_QUIT: + if (!quitdialog) { + quitdialog = true; + GUI::MessageDialog alert(_(" Are you sure you want to quit ? "), _("Yes"), _("No")); + if (alert.runModal() == GUI::kMessageOK) + _mainSystem->quit(); + quitdialog = false; + } + return true; } return false; diff --git a/backends/platform/wince/CEDevice.cpp b/backends/platform/wince/CEDevice.cpp index d94ce6cde7..ffe2523b47 100644 --- a/backends/platform/wince/CEDevice.cpp +++ b/backends/platform/wince/CEDevice.cpp @@ -29,22 +29,22 @@ #include "backends/platform/wince/wince-sdl.h" -static void (WINAPI* _SHIdleTimerReset)(void) = NULL; -static HANDLE (WINAPI* _SetPowerRequirement)(PVOID,int,ULONG,PVOID,ULONG) = NULL; -static DWORD (WINAPI* _ReleasePowerRequirement)(HANDLE) = NULL; +static void (WINAPI *_SHIdleTimerReset)(void) = NULL; +static HANDLE(WINAPI *_SetPowerRequirement)(PVOID, int, ULONG, PVOID, ULONG) = NULL; +static DWORD (WINAPI *_ReleasePowerRequirement)(HANDLE) = NULL; static HANDLE _hPowerManagement = NULL; static DWORD _lastTime = 0; static DWORD REG_bat = 0, REG_ac = 0, REG_disp = 0, bat_timeout = 0; static bool REG_tampered = false; #ifdef __GNUC__ extern "C" void WINAPI SystemIdleTimerReset(void); -#define SPI_SETBATTERYIDLETIMEOUT 251 -#define SPI_GETBATTERYIDLETIMEOUT 252 +#define SPI_SETBATTERYIDLETIMEOUT 251 +#define SPI_GETBATTERYIDLETIMEOUT 252 #endif #define TIMER_TRIGGER 9000 -DWORD CEDevice::reg_access(TCHAR *key, TCHAR *val, DWORD data) { +DWORD CEDevice::reg_access(const TCHAR *key, const TCHAR *val, DWORD data) { HKEY regkey; DWORD tmpval, cbdata; @@ -70,7 +70,7 @@ DWORD CEDevice::reg_access(TCHAR *key, TCHAR *val, DWORD data) { void CEDevice::backlight_xchg() { HANDLE h; - REG_bat = reg_access(TEXT("ControlPanel\\BackLight"), TEXT("BatteryTimeout"), REG_bat); + REG_bat = reg_access(TEXT("ControlPanel\\BackLight"), (const TCHAR *)TEXT("BatteryTimeout"), REG_bat); REG_ac = reg_access(TEXT("ControlPanel\\BackLight"), TEXT("ACTimeout"), REG_ac); REG_disp = reg_access(TEXT("ControlPanel\\Power"), TEXT("Display"), REG_disp); @@ -85,20 +85,19 @@ void CEDevice::init() { // 2003+ power management code borrowed from MoDaCo & Betaplayer. Thanks ! HINSTANCE dll = LoadLibrary(TEXT("aygshell.dll")); if (dll) { - *(FARPROC*)&_SHIdleTimerReset = GetProcAddress(dll, MAKEINTRESOURCE(2006)); + _SHIdleTimerReset = (void (*)())GetProcAddress(dll, MAKEINTRESOURCE(2006)); } dll = LoadLibrary(TEXT("coredll.dll")); if (dll) { - *(FARPROC*)&_SetPowerRequirement = GetProcAddress(dll, TEXT("SetPowerRequirement")); - *(FARPROC*)&_ReleasePowerRequirement = GetProcAddress(dll, TEXT("ReleasePowerRequirement")); - + _SetPowerRequirement = (HANDLE (*)(PVOID, int, ULONG, PVOID, ULONG))GetProcAddress(dll, TEXT("SetPowerRequirement")); + _ReleasePowerRequirement = (DWORD (*)(HANDLE))GetProcAddress(dll, TEXT("ReleasePowerRequirement")); } if (_SetPowerRequirement) _hPowerManagement = _SetPowerRequirement((PVOID) TEXT("BKL1:"), 0, 1, (PVOID) NULL, 0); _lastTime = GetTickCount(); // older devices - REG_bat = REG_ac = REG_disp = 2 * 60 * 60 * 1000; // 2hrs should do it + REG_bat = REG_ac = REG_disp = 2 * 60 * 60 * 1000; // 2hrs should do it backlight_xchg(); REG_tampered = true; SystemParametersInfo(SPI_GETBATTERYIDLETIMEOUT, 0, (void *) &bat_timeout, 0); @@ -127,6 +126,10 @@ bool CEDevice::hasSquareQVGAResolution() { return (OSystem_WINCE3::getScreenWidth() == 240 && OSystem_WINCE3::getScreenHeight() == 240); } +bool CEDevice::hasWideResolution() { + return (OSystem_WINCE3::getScreenWidth() >= 640 || OSystem_WINCE3::getScreenHeight() >= 640); +} + bool CEDevice::hasPocketPCResolution() { if (OSystem_WINCE3::isOzone() && hasWideResolution()) return true; @@ -139,10 +142,6 @@ bool CEDevice::hasDesktopResolution() { return (OSystem_WINCE3::getScreenWidth() > 320); } -bool CEDevice::hasWideResolution() { - return (OSystem_WINCE3::getScreenWidth() >= 640 || OSystem_WINCE3::getScreenHeight() >= 640); -} - bool CEDevice::hasSmartphoneResolution() { return (OSystem_WINCE3::getScreenWidth() < 240); } diff --git a/backends/platform/wince/CEDevice.h b/backends/platform/wince/CEDevice.h index b2b20d05ce..24dffca0b3 100644 --- a/backends/platform/wince/CEDevice.h +++ b/backends/platform/wince/CEDevice.h @@ -43,7 +43,7 @@ public: static bool isSmartphone(); private: - static DWORD reg_access(TCHAR *key, TCHAR *val, DWORD data); + static DWORD reg_access(const TCHAR *key, const TCHAR *val, DWORD data); static void backlight_xchg(); }; diff --git a/backends/platform/wince/CEException.cpp b/backends/platform/wince/CEException.cpp index 421db4960c..08a327136f 100644 --- a/backends/platform/wince/CEException.cpp +++ b/backends/platform/wince/CEException.cpp @@ -36,7 +36,7 @@ void CEException::writeBreak(HANDLE file) { int i; memset(tempo, 0, sizeof(tempo)); - for (i=0; i<40; i++) + for (i = 0; i < 40; i++) tempo[i] = '-'; writeString(file, tempo); } @@ -51,23 +51,23 @@ void CEException::dumpContext(HANDLE file, HANDLE hProcess, CONTEXT *context) { writeBreak(file); writeString(file, "Context dump"); sprintf(tempo, "R0=%.8x R1=%.8x R2=%.8x R3=%.8x R4=%.8x", context->R0, context->R1, - context->R2, context->R3, context->R4); + context->R2, context->R3, context->R4); writeString(file, tempo); sprintf(tempo, "R5=%.8x R6=%.8x R7=%.8x R8=%.8x R9=%.8x", context->R5, context->R6, - context->R7, context->R8, context->R9); + context->R7, context->R8, context->R9); writeString(file, tempo); sprintf(tempo, "R10=%.8x R11=%.8x R12=%.8x", context->R10, context->R11, - context->R12); + context->R12); writeString(file, tempo); sprintf(tempo, "Sp=%.8x Lr=%.8x Pc=%.8x Psr=%.8x", context->Sp, context->Lr, - context->Pc, context->Psr); + context->Pc, context->Psr); writeString(file, tempo); writeBreak(file); sprintf(tempo, "Memory dump at %.8x", context->Pc - (sizeof(memoryDump) / 2)); writeString(file, tempo); if (ReadProcessMemory(hProcess, (LPCVOID)(context->Pc - (sizeof(memoryDump) / 2)), memoryDump, sizeof(memoryDump), &size)) { - for (i=0; i<size; i+=8) { + for (i = 0; i < size; i += 8) { int j; char digit[4]; int max; @@ -75,7 +75,7 @@ void CEException::dumpContext(HANDLE file, HANDLE hProcess, CONTEXT *context) { if (max > 8) max = 8; tempo[0] = '\0'; - for (j=0; j<max; j++) { + for (j = 0; j < max; j++) { sprintf(digit, "%.2x ", memoryDump[i + j]); strcat(tempo, digit); } @@ -121,10 +121,10 @@ void CEException::dumpException(HANDLE file, EXCEPTION_RECORD *exceptionRecord) break; } sprintf(tempo, "Exception %s Flags %.8x Address %.8x", exceptionName, exceptionRecord->ExceptionFlags, - exceptionRecord->ExceptionAddress); + exceptionRecord->ExceptionAddress); writeString(file, tempo); if (exceptionRecord->NumberParameters) { - for (i=0; i<exceptionRecord->NumberParameters; i++) { + for (i = 0; i < exceptionRecord->NumberParameters; i++) { sprintf(tempo, "Parameter %d %.8x", i, exceptionRecord->ExceptionInformation[i]); writeString(file, tempo); } @@ -144,8 +144,8 @@ bool CEException::writeException(TCHAR *path, EXCEPTION_POINTERS *exceptionPoint GetSystemTime(&systemTime); wsprintf(dumpFileName, TEXT("%s_%.2d_%.2d_%.4d_%.2d_%.2d_%.2d.txt"), - path, systemTime.wDay, systemTime.wMonth, systemTime.wYear, - systemTime.wHour, systemTime.wMinute, systemTime.wSecond); + path, systemTime.wDay, systemTime.wMonth, systemTime.wYear, + systemTime.wHour, systemTime.wMinute, systemTime.wSecond); dumpFile = CreateFile(dumpFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (dumpFile == INVALID_HANDLE_VALUE) return false; diff --git a/backends/platform/wince/CELauncherDialog.cpp b/backends/platform/wince/CELauncherDialog.cpp index de1bb2f1f6..8824af732f 100644 --- a/backends/platform/wince/CELauncherDialog.cpp +++ b/backends/platform/wince/CELauncherDialog.cpp @@ -48,14 +48,14 @@ using namespace Common; class CEAboutDialog : public Dialog { public: CEAboutDialog() - : Dialog(10, 60, 300, 77) { + : Dialog(10, 60, 300, 77) { char tempo[100]; // FIXME: Fingolfin asks: why is there a FIXME here? Please either clarify what // needs fixing, or remove it! const int buttonWidth = g_gui.xmlEval()->getVar("Globals.Button.Width", 0); const int buttonHeight = g_gui.xmlEval()->getVar("Globals.Button.Height", 0); - new ButtonWidget(this, (_w - buttonWidth) / 2, 45, buttonWidth, buttonHeight, _("OK"), 0, kCloseCmd, '\r'); // Close dialog - FIXME + new ButtonWidget(this, (_w - buttonWidth) / 2, 45, buttonWidth, buttonHeight, _("OK"), 0, kCloseCmd, '\r'); // Close dialog - FIXME Common::String videoDriver(_("Using SDL driver ")); SDL_VideoDriverName(tempo, sizeof(tempo)); @@ -106,14 +106,13 @@ void CELauncherDialog::addGame() { MessageDialog alert(_("Do you want to perform an automatic scan ?"), _("Yes"), _("No")); if (alert.runModal() == kMessageOK && _browser->runModal() > 0) { // Clear existing domains - ConfigManager::DomainMap &domains = (ConfigManager::DomainMap&)ConfMan.getGameDomains(); + ConfigManager::DomainMap &domains = (ConfigManager::DomainMap &)ConfMan.getGameDomains(); domains.clear(); ConfMan.flushToDisk(); automaticScanDirectory(_browser->getResult()); ConfMan.flushToDisk(); updateListing(); draw(); - } - else + } else GUILauncherDialog::addGame(); } diff --git a/backends/platform/wince/CEgui/GUIElement.cpp b/backends/platform/wince/CEgui/GUIElement.cpp index dd463c22a1..e7ffc8d473 100644 --- a/backends/platform/wince/CEgui/GUIElement.cpp +++ b/backends/platform/wince/CEgui/GUIElement.cpp @@ -32,7 +32,7 @@ namespace CEGUI { GUIElement::GUIElement(int x, int y, int width, int height) : -_background(0), _drawn(false), _visible(true), _x(x), _y(y), _width(width), _height(height) { + _background(0), _drawn(false), _visible(true), _x(x), _y(y), _width(width), _height(height) { } bool GUIElement::setBackground(WORD backgroundReference) { @@ -45,9 +45,7 @@ bool GUIElement::setBackground(WORD backgroundReference) { if (!_height && !_width) { _height = _background->height(); _width = _background->width(); - } - else - if (_background->height() != _height || _background->width() != _width) { + } else if (_background->height() != _height || _background->width() != _width) { delete _background; _background = NULL; return false; @@ -74,8 +72,7 @@ bool GUIElement::draw(SDL_Surface *surface) { _drawn = true; return true; - } - else + } else return false; } diff --git a/backends/platform/wince/CEgui/ItemAction.cpp b/backends/platform/wince/CEgui/ItemAction.cpp index 55805744e6..efbc43ce00 100644 --- a/backends/platform/wince/CEgui/ItemAction.cpp +++ b/backends/platform/wince/CEgui/ItemAction.cpp @@ -28,7 +28,7 @@ namespace CEGUI { ItemAction::ItemAction(WORD reference, GUI::ActionType action) : -PanelItem(reference) { + PanelItem(reference) { _action = action; if (!GUI::Actions::Instance()->isEnabled(_action)) _visible = false; diff --git a/backends/platform/wince/CEgui/ItemSwitch.cpp b/backends/platform/wince/CEgui/ItemSwitch.cpp index d4648f7556..8eb62bf365 100644 --- a/backends/platform/wince/CEgui/ItemSwitch.cpp +++ b/backends/platform/wince/CEgui/ItemSwitch.cpp @@ -40,7 +40,7 @@ void ItemSwitch::init(WORD referenceTrue, WORD referenceFalse) { } ItemSwitch::ItemSwitch(WORD referenceTrue, WORD referenceFalse, bool *item) : -PanelItem(referenceTrue) { + PanelItem(referenceTrue) { init(referenceTrue, referenceFalse); _item = item; _itemmax = -1; @@ -49,8 +49,8 @@ PanelItem(referenceTrue) { } ItemSwitch::ItemSwitch(WORD referenceTrue, WORD referenceFalse, int *item, int max) : -PanelItem(referenceTrue) { - init(referenceTrue, referenceFalse); + PanelItem(referenceTrue) { + init(referenceTrue, referenceFalse); _itemmultiple = item; _itemmax = max; if (!*item) diff --git a/backends/platform/wince/CEgui/Panel.cpp b/backends/platform/wince/CEgui/Panel.cpp index dfdd6526be..576da23029 100644 --- a/backends/platform/wince/CEgui/Panel.cpp +++ b/backends/platform/wince/CEgui/Panel.cpp @@ -34,7 +34,7 @@ Panel::Panel(int interleave_first, int interleave) : Toolbar() { bool Panel::add(const String &name, const PanelItem *item) { - _itemsMap[name] = (PanelItem*)item; + _itemsMap[name] = (PanelItem *)item; _itemsMap[name]->move(_currentItem, _y + 10); _itemsMap[name]->setPanel(this); _currentItem += _interleave; @@ -47,11 +47,10 @@ bool Panel::draw(SDL_Surface *surface) { if (!_drawn && _visible) { GUIElement::draw(surface); for (iterator = _itemsMap.begin(); iterator != _itemsMap.end(); ++iterator) { - ((GUIElement*)(iterator->_value))->draw(surface); + ((GUIElement *)(iterator->_value))->draw(surface); } return true; - } - else + } else return false; } @@ -59,7 +58,7 @@ void Panel::forceRedraw() { ItemMap::const_iterator iterator; GUIElement::forceRedraw(); for (iterator = _itemsMap.begin(); iterator != _itemsMap.end(); ++iterator) - ((GUIElement*)(iterator->_value))->forceRedraw(); + ((GUIElement *)(iterator->_value))->forceRedraw(); } bool Panel::action(int x, int y, bool pushed) { @@ -69,7 +68,7 @@ bool Panel::action(int x, int y, bool pushed) { return false; for (iterator = _itemsMap.begin(); !result && iterator != _itemsMap.end(); ++iterator) - result = ((GUIElement*)(iterator->_value))->action(x, y, pushed); + result = ((GUIElement *)(iterator->_value))->action(x, y, pushed); return result; } diff --git a/backends/platform/wince/CEgui/Panel.h b/backends/platform/wince/CEgui/Panel.h index e6b693360d..1a8a580dba 100644 --- a/backends/platform/wince/CEgui/Panel.h +++ b/backends/platform/wince/CEgui/Panel.h @@ -51,7 +51,7 @@ public: virtual bool action(int x, int y, bool pushed); private: - typedef HashMap<String, PanelItem*, Common::IgnoreCase_Hash , Common::IgnoreCase_EqualTo> ItemMap; + typedef HashMap<String, PanelItem *, Common::IgnoreCase_Hash , Common::IgnoreCase_EqualTo> ItemMap; ItemMap _itemsMap; int _interleave; diff --git a/backends/platform/wince/CEgui/PanelItem.h b/backends/platform/wince/CEgui/PanelItem.h index 14b62f0f20..9968aa8d5e 100644 --- a/backends/platform/wince/CEgui/PanelItem.h +++ b/backends/platform/wince/CEgui/PanelItem.h @@ -36,7 +36,7 @@ namespace CEGUI { class Panel; class PanelItem : public GUIElement { -friend class Panel; + friend class Panel; public: PanelItem(WORD reference); virtual ~PanelItem(); diff --git a/backends/platform/wince/CEgui/PanelKeyboard.cpp b/backends/platform/wince/CEgui/PanelKeyboard.cpp index 5ca125898d..3512b34da3 100644 --- a/backends/platform/wince/CEgui/PanelKeyboard.cpp +++ b/backends/platform/wince/CEgui/PanelKeyboard.cpp @@ -30,8 +30,9 @@ namespace CEGUI { const char KEYBOARD_MAPPING_ALPHA[][14] = { {"abcdefghijklm"}, {"nopqrstuvwxyz"} }; const char KEYBOARD_MAPPING_NUMERIC[][6] = { {"12345"}, {"67890"} }; -const int KEYBOARD_MAPPING_SPECIAL[][3][2] = { { {1,SDLK_ESCAPE}, {224,SDLK_UP}, {32,SDLK_SPACE} }, - { {224,SDLK_LEFT}, {224,SDLK_DOWN}, {224,SDLK_RIGHT} } }; +const int KEYBOARD_MAPPING_SPECIAL[][3][2] = { { {1, SDLK_ESCAPE}, {224, SDLK_UP}, {32, SDLK_SPACE} }, + { {224, SDLK_LEFT}, {224, SDLK_DOWN}, {224, SDLK_RIGHT} } +}; PanelKeyboard::PanelKeyboard(WORD reference) : Toolbar() { setBackground(reference); @@ -51,21 +52,23 @@ bool PanelKeyboard::action(int x, int y, bool pushed) { int keyCode = 0; if (x < 185) { // Alpha selection - keyCode = keyAscii = KEYBOARD_MAPPING_ALPHA[y >= _y+20][((x + 10) / 14) - 1]; + keyCode = keyAscii = KEYBOARD_MAPPING_ALPHA[y >= _y + 20][((x + 10) / 14) - 1]; } else if (x >= 186 && x <= 255) { // Numeric selection - keyCode = keyAscii = KEYBOARD_MAPPING_NUMERIC[y >= _y+20][((x - 187 + 10) / 14) - 1]; + keyCode = keyAscii = KEYBOARD_MAPPING_NUMERIC[y >= _y + 20][((x - 187 + 10) / 14) - 1]; } else if (x >= 258 && x <= 300) { // Special keys - keyAscii = KEYBOARD_MAPPING_SPECIAL[y >= _y+20][((x - 259 + 10) / 14) - 1][0]; - keyCode = KEYBOARD_MAPPING_SPECIAL[y >= _y+20][((x - 259 + 10) / 14) - 1][1]; + keyAscii = KEYBOARD_MAPPING_SPECIAL[y >= _y + 20][((x - 259 + 10) / 14) - 1][0]; + keyCode = KEYBOARD_MAPPING_SPECIAL[y >= _y + 20][((x - 259 + 10) / 14) - 1][1]; } else if (x >= 302 && x <= 316) { - if (y < _y +20) { + if (y < _y + 20) { // Backspace - keyAscii = VK_BACK; keyCode = keyAscii; + keyAscii = VK_BACK; + keyCode = keyAscii; } else { // Enter - keyAscii = 13; keyCode = 13; + keyAscii = 13; + keyCode = 13; } } diff --git a/backends/platform/wince/CEgui/SDL_ImageResource.cpp b/backends/platform/wince/CEgui/SDL_ImageResource.cpp index 8dad5f0a0c..872b94a442 100644 --- a/backends/platform/wince/CEgui/SDL_ImageResource.cpp +++ b/backends/platform/wince/CEgui/SDL_ImageResource.cpp @@ -32,7 +32,7 @@ SDL_ImageResource::SDL_ImageResource() : _surface(0) { } -SDL_Surface* SDL_ImageResource::load(WORD resourceID) { +SDL_Surface *SDL_ImageResource::load(WORD resourceID) { HRSRC resource; HGLOBAL resourceGlobal; LPVOID resourcePointer; @@ -62,7 +62,7 @@ SDL_Surface* SDL_ImageResource::load(WORD resourceID) { return _surface; } -SDL_Surface* SDL_ImageResource::get() { +SDL_Surface *SDL_ImageResource::get() { return _surface; } diff --git a/backends/platform/wince/CEgui/SDL_ImageResource.h b/backends/platform/wince/CEgui/SDL_ImageResource.h index 5affd5c33c..397ced1434 100644 --- a/backends/platform/wince/CEgui/SDL_ImageResource.h +++ b/backends/platform/wince/CEgui/SDL_ImageResource.h @@ -36,8 +36,8 @@ namespace CEGUI { class SDL_ImageResource { public: SDL_ImageResource(); - SDL_Surface* load(WORD resourceID); - SDL_Surface* get(); + SDL_Surface *load(WORD resourceID); + SDL_Surface *get(); int height(); int width(); virtual ~SDL_ImageResource(); diff --git a/backends/platform/wince/CEgui/ToolbarHandler.cpp b/backends/platform/wince/CEgui/ToolbarHandler.cpp index 78f69119c3..ed2a72245a 100644 --- a/backends/platform/wince/CEgui/ToolbarHandler.cpp +++ b/backends/platform/wince/CEgui/ToolbarHandler.cpp @@ -29,15 +29,15 @@ namespace CEGUI { ToolbarHandler::ToolbarHandler(): -_current(""), _active(NULL) { + _current(""), _active(NULL) { } bool ToolbarHandler::add(const String &name, const Toolbar &toolbar) { - _toolbarMap[name] = (Toolbar*)&toolbar; + _toolbarMap[name] = (Toolbar *)&toolbar; if (!_active) { - _active = &((Toolbar&)toolbar); + _active = &((Toolbar &)toolbar); _current = name; } @@ -53,7 +53,7 @@ bool ToolbarHandler::setActive(const String &name) { return false; if (_current == name) return true; - _active->action(0, 0, false); // make sure any items are unpushed when changing toolbars (e.g. forced VK->main panel) + _active->action(0, 0, false); // make sure any items are unpushed when changing toolbars (e.g. forced VK->main panel) _current = name; _active = _toolbarMap[name]; _active->forceRedraw(); @@ -67,8 +67,7 @@ bool ToolbarHandler::action(int x, int y, bool pushed) { return _active->action(x / 2, (y - _offset) / 2, pushed); else return _active->action(x, y - _offset, pushed); - } - else + } else return false; } @@ -118,7 +117,7 @@ int ToolbarHandler::getOffset() { return _offset; } -Toolbar* ToolbarHandler::active() { +Toolbar *ToolbarHandler::active() { return _active; } diff --git a/backends/platform/wince/CEgui/ToolbarHandler.h b/backends/platform/wince/CEgui/ToolbarHandler.h index e3bf590768..0f794d7d61 100644 --- a/backends/platform/wince/CEgui/ToolbarHandler.h +++ b/backends/platform/wince/CEgui/ToolbarHandler.h @@ -57,7 +57,7 @@ public: virtual ~ToolbarHandler(); private: - HashMap<String, Toolbar*, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _toolbarMap; + HashMap<String, Toolbar *, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _toolbarMap; String _current; Toolbar *_active; int _offset; diff --git a/backends/platform/wince/CEkeys/EventsBuffer.cpp b/backends/platform/wince/CEkeys/EventsBuffer.cpp index c9f4af2304..beea272d2b 100644 --- a/backends/platform/wince/CEkeys/EventsBuffer.cpp +++ b/backends/platform/wince/CEkeys/EventsBuffer.cpp @@ -29,55 +29,55 @@ namespace CEKEYS { - bool EventsBuffer::simulateKey(GUI::Key *key, bool pushed) { - SDL_Event ev = {0}; - - if (!key->keycode()) - key->setKey(key->ascii(), key->ascii()); - else if (!key->ascii()) - key->setKey(key->keycode()); - - ev.type = (pushed ? SDL_KEYDOWN : SDL_KEYUP); - ev.key.keysym.unicode = (SDLMod)key->flags(); // HACK: put the flags into the unused unicode field - ev.key.keysym.sym = (SDLKey)key->keycode(); - ev.key.keysym.mod = KMOD_RESERVED; - return (SDL_PushEvent(&ev) == 0); - } - - bool EventsBuffer::simulateMouseMove(int x, int y) { - SDL_Event ev = {0}; - - ev.type = SDL_MOUSEMOTION; - ev.motion.x = x; - ev.motion.y = y; - return (SDL_PushEvent(&ev) == 0); - } - - bool EventsBuffer::simulateMouseLeftClick(int x, int y, bool pushed) { - SDL_Event ev = {0}; - static bool state = false; - - if (pushed == state) return 0; - state = pushed; - ev.type = (pushed ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP); - ev.button.button = SDL_BUTTON_LEFT; - ev.button.x = x; - ev.button.y = y; - return (SDL_PushEvent(&ev) == 0); - } - - bool EventsBuffer::simulateMouseRightClick(int x, int y, bool pushed) { - SDL_Event ev = {0}; - static bool state = false; - - if (pushed == state) return 0; - state = pushed; - ev.type = (pushed ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP); - ev.button.button = SDL_BUTTON_RIGHT; - ev.button.x = x; - ev.button.y = y; - return (SDL_PushEvent(&ev) == 0); - } +bool EventsBuffer::simulateKey(GUI::Key *key, bool pushed) { + SDL_Event ev = {0}; + + if (!key->keycode()) + key->setKey(key->ascii(), key->ascii()); + else if (!key->ascii()) + key->setKey(key->keycode()); + + ev.type = (pushed ? SDL_KEYDOWN : SDL_KEYUP); + ev.key.keysym.unicode = (SDLMod)key->flags(); // HACK: put the flags into the unused unicode field + ev.key.keysym.sym = (SDLKey)key->keycode(); + ev.key.keysym.mod = KMOD_RESERVED; + return (SDL_PushEvent(&ev) == 0); +} + +bool EventsBuffer::simulateMouseMove(int x, int y) { + SDL_Event ev = {0}; + + ev.type = SDL_MOUSEMOTION; + ev.motion.x = x; + ev.motion.y = y; + return (SDL_PushEvent(&ev) == 0); +} + +bool EventsBuffer::simulateMouseLeftClick(int x, int y, bool pushed) { + SDL_Event ev = {0}; + static bool state = false; + + if (pushed == state) return 0; + state = pushed; + ev.type = (pushed ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP); + ev.button.button = SDL_BUTTON_LEFT; + ev.button.x = x; + ev.button.y = y; + return (SDL_PushEvent(&ev) == 0); +} + +bool EventsBuffer::simulateMouseRightClick(int x, int y, bool pushed) { + SDL_Event ev = {0}; + static bool state = false; + + if (pushed == state) return 0; + state = pushed; + ev.type = (pushed ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP); + ev.button.button = SDL_BUTTON_RIGHT; + ev.button.x = x; + ev.button.y = y; + return (SDL_PushEvent(&ev) == 0); +} } diff --git a/backends/platform/wince/CEkeys/EventsBuffer.h b/backends/platform/wince/CEkeys/EventsBuffer.h index 22590db03c..9b766c6ca9 100644 --- a/backends/platform/wince/CEkeys/EventsBuffer.h +++ b/backends/platform/wince/CEkeys/EventsBuffer.h @@ -34,14 +34,14 @@ namespace CEKEYS { - class EventsBuffer { - public: - static bool simulateKey(GUI::Key *key, bool pushed); - static bool simulateMouseMove(int x, int y); - static bool simulateMouseLeftClick(int x, int y, bool pushed); - static bool simulateMouseRightClick(int x, int y, bool pushed); - - }; +class EventsBuffer { +public: + static bool simulateKey(GUI::Key *key, bool pushed); + static bool simulateMouseMove(int x, int y); + static bool simulateMouseLeftClick(int x, int y, bool pushed); + static bool simulateMouseRightClick(int x, int y, bool pushed); + +}; } #endif diff --git a/backends/platform/wince/Makefile b/backends/platform/wince/Makefile index 8ad134648b..21bff06f95 100644 --- a/backends/platform/wince/Makefile +++ b/backends/platform/wince/Makefile @@ -113,7 +113,7 @@ INCLUDES := -I$(srcdir) -I. -I$(srcdir)/engines -Imissing/gcc -Ilibs/include -Il CFLAGS := ifndef UNOPTIMIZED_BUILD -CFLAGS += -O3 -march=armv4 -mtune=xscale +CFLAGS += -O3 -fno-inline-functions -march=armv4 -mtune=xscale endif LDFLAGS := -Wl,-Map,scummvm.exe.map -Wl,--stack,65536 diff --git a/backends/platform/wince/missing/io.h b/backends/platform/wince/missing/io.h index 8c66e9405b..96bc6a9ea1 100644 --- a/backends/platform/wince/missing/io.h +++ b/backends/platform/wince/missing/io.h @@ -5,9 +5,9 @@ #define strdup _strdup #ifndef _FILE_DEFINED - typedef void FILE; - #define _FILE_DEFINED +typedef void FILE; +#define _FILE_DEFINED #endif -FILE* wce_fopen(const char* fname, const char* fmode); +FILE *wce_fopen(const char *fname, const char *fmode); #define fopen wce_fopen diff --git a/backends/platform/wince/missing/missing.cpp b/backends/platform/wince/missing/missing.cpp index 92af3e6961..c855247ae1 100644 --- a/backends/platform/wince/missing/missing.cpp +++ b/backends/platform/wince/missing/missing.cpp @@ -50,7 +50,7 @@ char *strdup(const char *strSource); // common missing functions required by both gcc and evc void *bsearch(const void *key, const void *base, size_t nmemb, - size_t size, int (*compar)(const void *, const void *)) { + size_t size, int (*compar)(const void *, const void *)) { // Perform binary search size_t lo = 0; size_t hi = nmemb; @@ -63,17 +63,17 @@ void *bsearch(const void *key, const void *base, size_t nmemb, else if (tmp > 0) lo = mid + 1; else - return (void *)p; + return const_cast<void *>(p); } return NULL; } -static char cwd[MAX_PATH+1] = ""; +static char cwd[MAX_PATH + 1] = ""; EXT_C char *getcwd(char *buffer, int maxlen) { - TCHAR fileUnc[MAX_PATH+1]; - char* plast; + TCHAR fileUnc[MAX_PATH + 1]; + char *plast; if (cwd[0] == 0) { GetModuleFileName(NULL, fileUnc, MAX_PATH); @@ -94,7 +94,7 @@ EXT_C char *getcwd(char *buffer, int maxlen) { #undef GetCurrentDirectory #endif EXT_C void GetCurrentDirectory(int len, char *buf) { - getcwd(buf,len); + getcwd(buf, len); } /* @@ -103,8 +103,8 @@ fully qualified paths refer to root folder rather than current folder (concept not implemented in CE). */ #undef fopen -EXT_C FILE *wce_fopen(const char* fname, const char* fmode) { - char fullname[MAX_PATH+1]; +EXT_C FILE *wce_fopen(const char *fname, const char *fmode) { + char fullname[MAX_PATH + 1]; if (!fname || fname[0] == '\0') return NULL; @@ -118,8 +118,8 @@ EXT_C FILE *wce_fopen(const char* fname, const char* fmode) { } /* Remove file by name */ -int remove(const char* path) { - TCHAR pathUnc[MAX_PATH+1]; +int remove(const char *path) { + TCHAR pathUnc[MAX_PATH + 1]; MultiByteToWideChar(CP_ACP, 0, path, -1, pathUnc, MAX_PATH); return !DeleteFile(pathUnc); } @@ -128,15 +128,15 @@ int remove(const char* path) { /* check out file access permissions */ int _access(const char *path, int mode) { TCHAR fname[MAX_PATH]; - char fullname[MAX_PATH+1]; + char fullname[MAX_PATH + 1]; if (path[0] != '\\' && path[0] != '/') { getcwd(fullname, MAX_PATH); strcat(fullname, "\\"); strcat(fullname, path); - MultiByteToWideChar(CP_ACP, 0, fullname, -1, fname, sizeof(fname)/sizeof(TCHAR)); + MultiByteToWideChar(CP_ACP, 0, fullname, -1, fname, sizeof(fname) / sizeof(TCHAR)); } else - MultiByteToWideChar(CP_ACP, 0, path, -1, fname, sizeof(fname)/sizeof(TCHAR)); + MultiByteToWideChar(CP_ACP, 0, path, -1, fname, sizeof(fname) / sizeof(TCHAR)); WIN32_FIND_DATA ffd; HANDLE h = FindFirstFile(fname, &ffd); @@ -144,10 +144,10 @@ int _access(const char *path, int mode) { if (h == INVALID_HANDLE_VALUE) { // WORKAROUND: WinCE 3.0 doesn't find paths ending in '\' - if (path[strlen(path)-1] == '\\') { + if (path[strlen(path) - 1] == '\\') { char p2[MAX_PATH]; - strncpy(p2, path, strlen(path)-1); - p2[strlen(path) - 1]= '\0'; + strncpy(p2, path, strlen(path) - 1); + p2[strlen(path) - 1] = '\0'; return _access(p2, mode); } else return -1; //Can't find file @@ -158,7 +158,7 @@ int _access(const char *path, int mode) { // hits for files that don't exist. TRIPLE checking for the same fname // seems to weed out those false positives. // Exhibited in kyra engine. - HANDLE h = FindFirstFile(fname, &ffd); + h = FindFirstFile(fname, &ffd); FindClose(h); if (h == INVALID_HANDLE_VALUE) return -1; //Can't find file @@ -170,13 +170,13 @@ int _access(const char *path, int mode) { return 0; //Always return success if target is directory and exists } switch (mode) { - case 00: //Check existence - return 0; - case 06: //Check Read & Write permission - case 02: //Check Write permission - return ffd.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? -1 : 0; - case 04: //Check Read permission - return 0; //Assume always have read permission + case 00: //Check existence + return 0; + case 06: //Check Read & Write permission + case 02: //Check Write permission + return ffd.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? -1 : 0; + case 04: //Check Read permission + return 0; //Assume always have read permission } //Bad mode value supplied, return failure return -1; @@ -188,7 +188,7 @@ int _access(const char *path, int mode) { char *strdup(const char *strSource) { char *buffer; size_z len = strlen(strSource) + 1; - buffer = (char*)malloc(len); + buffer = (char *)malloc(len); if (buffer) memcpy(buffer, strSource, len); return buffer; @@ -199,25 +199,25 @@ char *strdup(const char *strSource) { #ifndef __MINGW32CE__ int islower(int c) { - return (c>='a' && c<='z'); + return (c >= 'a' && c <= 'z'); } int isspace(int c) { - return (c==' ' || c=='\f' || c=='\n' || c=='\r' || c=='\t' || c=='\v'); + return (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v'); } int isalpha(int c) { - return ((c>='a' && c<='z') || (c>='A' && c<='Z')); + return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); } int isalnum(int c) { - return ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9')); + return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')); } int isprint(int c) { //static const char punct[] = "!\"#%&'();<=>?[\\]*+,-./:^_{|}~"; //return (isalnum(c) || strchr(punct, c)); - return (32 <= c && c <= 126); // based on BSD manpage + return (32 <= c && c <= 126); // based on BSD manpage } #endif diff --git a/backends/platform/wince/missing/time.h b/backends/platform/wince/missing/time.h index f2bc5e4f89..a0ba6c246e 100644 --- a/backends/platform/wince/missing/time.h +++ b/backends/platform/wince/missing/time.h @@ -6,8 +6,7 @@ #include <stdlib.h> #ifndef __MINGW32CE__ -struct tm -{ +struct tm { short tm_year; short tm_mon; short tm_mday; @@ -23,8 +22,8 @@ struct tm #define EXT_C #endif -EXT_C time_t time(time_t* dummy); -EXT_C struct tm* localtime(time_t* dummy); +EXT_C time_t time(time_t *dummy); +EXT_C struct tm *localtime(time_t *dummy); unsigned int clock(); diff --git a/backends/platform/wince/portdefs.h b/backends/platform/wince/portdefs.h index cbf2006be2..8ad643946f 100644 --- a/backends/platform/wince/portdefs.h +++ b/backends/platform/wince/portdefs.h @@ -34,10 +34,10 @@ int isprint(int c); int isspace(int c); char *strrchr(const char *s, int c); char *strdup(const char *s); -int _stricmp( const char *string1, const char *string2 ); -int stricmp( const char *string1, const char *string2 ); -void assert( void* expression ); -void assert( int expression ); +int _stricmp(const char *string1, const char *string2); +int stricmp(const char *string1, const char *string2); +void assert(void *expression); +void assert(int expression); long int strtol(const char *nptr, char **endptr, int base); char *_strdup(const char *s); char *strpbrk(const char *s, const char *accept); @@ -47,20 +47,20 @@ char *strpbrk(const char *s, const char *accept); #ifdef _WIN32_WCE #ifndef __GNUC__ - void *bsearch(const void *, const void *, size_t, size_t, int (*x) (const void *, const void *)); - char *getcwd(char *buf, int size); - typedef int ptrdiff_t; - void GetCurrentDirectory(int len, char *buf); - #define INVALID_FILE_ATTRIBUTES 0xffffffff +void *bsearch(const void *, const void *, size_t, size_t, int (*x)(const void *, const void *)); +char *getcwd(char *buf, int size); +typedef int ptrdiff_t; +void GetCurrentDirectory(int len, char *buf); +#define INVALID_FILE_ATTRIBUTES 0xffffffff #else - #include <math.h> - #undef GetCurrentDirectory - extern "C" void GetCurrentDirectory(int len, char *buf); - #define stricmp _stricmp - #define strnicmp _strnicmp - #define snprintf _snprintf - #define strdup _strdup - #define fopen wce_fopen +#include <math.h> +#undef GetCurrentDirectory +extern "C" void GetCurrentDirectory(int len, char *buf); +#define stricmp _stricmp +#define strnicmp _strnicmp +#define snprintf _snprintf +#define strdup _strdup +#define fopen wce_fopen #endif #include <windows.h> @@ -75,12 +75,12 @@ char *strpbrk(const char *s, const char *accept); //#include <direct.h> #ifdef __MINGW32CE__ - void *bsearch(const void *, const void *, size_t, size_t, int (*x) (const void *, const void *)); +void *bsearch(const void *, const void *, size_t, size_t, int (*x)(const void *, const void *)); #endif int remove(const char *path); int _access(const char *path, int mode); -void drawError(char*); +void drawError(char *); #define vsnprintf _vsnprintf diff --git a/backends/platform/wince/wince-sdl.cpp b/backends/platform/wince/wince-sdl.cpp index ade90b2dfb..b829686cb0 100644 --- a/backends/platform/wince/wince-sdl.cpp +++ b/backends/platform/wince/wince-sdl.cpp @@ -23,6 +23,7 @@ * */ + // Disable symbol overrides so that we can use system headers. #define FORBIDDEN_SYMBOL_ALLOW_ALL @@ -43,13 +44,12 @@ #include "audio/mixer_intern.h" #include "audio/fmopl.h" -#include "backends/timer/default/default-timer.h" +#include "backends/timer/sdl/sdl-timer.h" #include "gui/Actions.h" #include "gui/KeysDialog.h" #include "gui/message.h" -#include "backends/platform/wince/resource.h" #include "backends/platform/wince/CEActionsPocket.h" #include "backends/platform/wince/CEActionsSmartphone.h" #include "backends/platform/wince/CEgui/ItemAction.h" @@ -60,39 +60,22 @@ #include "backends/platform/wince/CEException.h" #include "backends/platform/wince/CEScaler.h" -#ifdef USE_VORBIS -#ifndef USE_TREMOR -#include <vorbis/vorbisfile.h> -#else -#include <tremor/ivorbisfile.h> -#endif -#endif +#include "backends/graphics/wincesdl/wincesdl-graphics.h" +#include "backends/events/wincesdl/wincesdl-events.h" +#include "backends/mixer/wincesdl/wincesdl-mixer.h" #ifdef DYNAMIC_MODULES #include "backends/plugins/win32/win32-provider.h" #endif #ifdef __GNUC__ -extern "C" _CRTIMP FILE* __cdecl _wfreopen (const wchar_t*, const wchar_t*, FILE*); +extern "C" _CRTIMP FILE *__cdecl _wfreopen(const wchar_t *, const wchar_t *, FILE *); #endif -#define SAMPLES_PER_SEC_OLD 11025 -#define SAMPLES_PER_SEC_NEW 22050 - using namespace CEGUI; // ******************************************************************************************** -// 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" - // stdin/err redirection #define STDOUT_FNAME "\\scummvm_stdout.txt" #define STDERR_FNAME "\\scummvm_stderr.txt" @@ -106,34 +89,6 @@ bool OSystem_WINCE3::_soundMaster = true; bool _isSmartphone = false; bool _hasSmartphoneResolution = false; -// 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} -}; - #define DEFAULT_CONFIG_FILE "scummvm.ini" // ******************************************************************************************** @@ -144,7 +99,7 @@ bool isSmartphone() { } const TCHAR *ASCIItoUnicode(const char *str) { - static TCHAR ustr[MAX_PATH]; // size good enough + static TCHAR ustr[MAX_PATH]; // size good enough MultiByteToWideChar(CP_ACP, 0, str, strlen(str) + 1, ustr, sizeof(ustr) / sizeof(TCHAR)); return ustr; @@ -173,7 +128,7 @@ int SDL_main(int argc, char **argv) { // thanks to joostp and DJWillis extern void (*__CTOR_LIST__)(); void (**constructor)() = &__CTOR_LIST__; - constructor++; // First item in list of constructors has special meaning (platform dependent), ignore it. + constructor++; // First item in list of constructors has special meaning (platform dependent), ignore it. while (*constructor) { (*constructor)(); constructor++; @@ -238,10 +193,10 @@ int SDL_main(int argc, char **argv) { res = scummvm_main(argc, argv); // Free OSystem - delete (OSystem_WINCE3 *)g_system; + delete(OSystem_WINCE3 *)g_system; #if !defined(DEBUG) && !defined(__GNUC__) } - __except (handleException(GetExceptionInformation())) { + __except(handleException(GetExceptionInformation())) { } #endif @@ -264,22 +219,22 @@ int console_main(int argc, char *argv[]) { char *bufp, *appname; appname = argv[0]; - if ( (bufp=strrchr(argv[0], '\\')) != NULL ) + if ((bufp = strrchr(argv[0], '\\')) != NULL) appname = bufp + 1; - else if ( (bufp=strrchr(argv[0], '/')) != NULL ) + else if ((bufp = strrchr(argv[0], '/')) != NULL) appname = bufp + 1; - if ( (bufp=strrchr(appname, '.')) == NULL ) + if ((bufp = strrchr(appname, '.')) == NULL) n = strlen(appname); else - n = (bufp-appname); + n = (bufp - appname); bufp = (char *) alloca(n + 1); strncpy(bufp, appname, n); bufp[n] = '\0'; appname = bufp; - if ( SDL_Init(SDL_INIT_NOPARACHUTE) < 0 ) { + if (SDL_Init(SDL_INIT_NOPARACHUTE) < 0) { error("WinMain() error: %d", SDL_GetError()); return(FALSE); } @@ -344,31 +299,31 @@ int dynamic_modules_main(HINSTANCE hInst, HINSTANCE hPrev, LPWSTR szCmdLine, int int nLen; if (wcsncmp(szCmdLine, TEXT("\\"), 1)) { - nLen = wcslen(szCmdLine)+128+1; - bufp = (wchar_t *) alloca(nLen*2); - wcscpy (bufp, TEXT("\"")); - GetModuleFileName(NULL, bufp+1, 128-3); - wcscpy (bufp+wcslen(bufp), TEXT("\" ")); - wcsncpy(bufp+wcslen(bufp), szCmdLine,nLen-wcslen(bufp)); + nLen = wcslen(szCmdLine) + 128 + 1; + bufp = (wchar_t *) alloca(nLen * 2); + wcscpy(bufp, TEXT("\"")); + GetModuleFileName(NULL, bufp + 1, 128 - 3); + wcscpy(bufp + wcslen(bufp), TEXT("\" ")); + wcsncpy(bufp + wcslen(bufp), szCmdLine, nLen - wcslen(bufp)); } else bufp = szCmdLine; - nLen = wcslen(bufp)+1; + nLen = wcslen(bufp) + 1; cmdline = (char *) alloca(nLen); WideCharToMultiByte(CP_ACP, 0, bufp, -1, cmdline, nLen, NULL, NULL); // Parse command line into argv and argc argc = ParseCommandLine(cmdline, NULL); - argv = (char **) alloca((argc+1)*(sizeof *argv)); + argv = (char **) alloca((argc + 1) * (sizeof * argv)); ParseCommandLine(cmdline, argv); // fix gdb-emulator combo while (argc > 1 && !strstr(argv[0], ".exe")) { OutputDebugString(TEXT("SDL: gdb argv[0] fixup\n")); - *(argv[1]-1) = ' '; + *(argv[1] - 1) = ' '; int i; - for (i=1; i<argc; i++) - argv[i] = argv[i+1]; + for (i = 1; i < argc; i++) + argv[i] = argv[i + 1]; argc--; } @@ -380,7 +335,6 @@ int dynamic_modules_main(HINSTANCE hInst, HINSTANCE hPrev, LPWSTR szCmdLine, int // ******************************************************************************************** - // ******************************************************************************************** void pumpMessages() { @@ -407,47 +361,53 @@ static Uint32 timer_handler_wrapper(Uint32 interval) { } void OSystem_WINCE3::initBackend() { - // Instantiate our own sound mixer - // mixer init is rerun when a game engine is selected. - setupMixer(); + + assert(!_inited); + + // Create the backend custom managers + if (_eventSource == 0) + _eventSource = new WINCESdlEventSource(); + + if (_mixerManager == 0) { + _mixerManager = new WINCESdlMixerManager(); + + // Setup and start mixer + _mixerManager->init(); + } + + if (_graphicsManager == 0) + _graphicsManager = new WINCESdlGraphicsManager(_eventSource); + + ((WINCESdlEventSource *)_eventSource)->init((WINCESdlGraphicsManager *)_graphicsManager); // Create the timer. CE SDL does not support multiple timers (SDL_AddTimer). // We work around this by using the SetTimer function, since we only use // one timer in scummvm (for the time being) _timer = _int_timer = new DefaultTimerManager(); - _timerID = NULL; // OSystem_SDL will call removetimer with this, it's ok + //_timerID = NULL; // OSystem_SDL will call removetimer with this, it's ok SDL_SetTimer(10, &timer_handler_wrapper); // Chain init OSystem_SDL::initBackend(); - // Query SDL for screen size and init screen dependent stuff - OSystem_WINCE3::initScreenInfos(); - _isSmartphone = CEDevice::isSmartphone(); - create_toolbar(); - _hasSmartphoneResolution = CEDevice::hasSmartphoneResolution() || CEDevice::isSmartphone(); - if (_hasSmartphoneResolution) - _panelVisible = false; // init correctly in smartphones - // Initialize global key mapping GUI::Actions::init(); GUI_Actions::Instance()->initInstanceMain(this); - if (!GUI_Actions::Instance()->loadMapping()) { // error during loading means not present/wrong version + if (!GUI_Actions::Instance()->loadMapping()) { // error during loading means not present/wrong version warning("Setting default action mappings"); - GUI_Actions::Instance()->saveMapping(); // write defaults + GUI_Actions::Instance()->saveMapping(); // write defaults } - loadDeviceConfiguration(); + // Call parent implementation of this method + //OSystem_SDL::initBackend(); + + _inited = true; } int OSystem_WINCE3::getScreenWidth() { return _platformScreenWidth; } -int OSystem_WINCE3::getScreenHeight() { - return _platformScreenHeight; -} - void OSystem_WINCE3::initScreenInfos() { // sdl port ensures that we use correctly full screen _isOzone = 0; @@ -457,6 +417,10 @@ void OSystem_WINCE3::initScreenInfos() { _platformScreenHeight = r[0]->h; } +int OSystem_WINCE3::getScreenHeight() { + return _platformScreenHeight; +} + bool OSystem_WINCE3::isOzone() { return _isOzone; } @@ -473,496 +437,37 @@ Common::String OSystem_WINCE3::getDefaultConfigFileName() { OSystem_WINCE3::OSystem_WINCE3() : OSystem_SDL(), - _orientationLandscape(0), _newOrientation(0), _panelInitialized(false), _canBeAspectScaled(false), - _panelVisible(true), _panelStateForced(false), _forceHideMouse(false), _unfilteredkeys(false), - _freeLook(false), _forcePanelInvisible(false), _toolbarHighDrawn(false), _zoomUp(false), _zoomDown(false), - _scalersChanged(false), _lastKeyPressed(0), _tapTime(0), _closeClick(false), _noDoubleTapRMB(false), - _saveToolbarState(false), _saveActiveToolbar(NAME_MAIN_PANEL), _rbutton(false), _hasfocus(true), - _usesEmulatedMouse(false), _mouseBackupOld(NULL), _mouseBackupToolbar(NULL), _mouseBackupDim(0) -{ - memset(&_mouseCurState, 0, sizeof(_mouseCurState)); - if (_isSmartphone) { - _mouseCurState.x = 20; - _mouseCurState.y = 20; - } - + _forcePanelInvisible(false) { + // Initialze File System Factory + _fsFactory = new WindowsFilesystemFactory(); _mixer = 0; - _screen = NULL; } -void OSystem_WINCE3::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(); - } - //} +OSystem_WINCE3::~OSystem_WINCE3() { + delete _fsFactory; + delete _mixer; } -void OSystem_WINCE3::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 OSystem_WINCE3::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 OSystem_WINCE3::smartphone_rotate_display() { - _orientationLandscape = _newOrientation = _orientationLandscape == 1 ? 2 : 1; - ConfMan.setInt("landscape", _orientationLandscape); - ConfMan.flushToDisk(); - hotswapGFXMode(); +FilesystemFactory *OSystem_WINCE3::getFilesystemFactory() { + return _fsFactory; } void OSystem_WINCE3::swap_sound_master() { _soundMaster = !_soundMaster; - if (_toolbarHandler.activeName() == NAME_MAIN_PANEL) - _toolbarHandler.forceRedraw(); // redraw sound icon -} - -void OSystem_WINCE3::add_right_click(bool pushed) { - int x, y; - retrieve_mouse_location(x, y); - EventsBuffer::simulateMouseRightClick(x, y, pushed); -} - -void OSystem_WINCE3::swap_mouse_visibility() { - _forceHideMouse = !_forceHideMouse; - if (_forceHideMouse) - undrawMouse(); -} - -void OSystem_WINCE3::swap_freeLook() { - _freeLook = !_freeLook; -} -void OSystem_WINCE3::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; - } + //WINCESdlGraphicsManager _graphicsManager - _zoomDown = false; - _zoomUp = true; - } - // redraw whole screen - addDirtyRect(0, 0, 640, 480); - internUpdateScreen(); + if (((WINCESdlGraphicsManager *)_graphicsManager)->_toolbarHandler.activeName() == NAME_MAIN_PANEL) + ((WINCESdlGraphicsManager *)_graphicsManager)->_toolbarHandler.forceRedraw(); // redraw sound icon } -void OSystem_WINCE3::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(); -} - -// Smartphone actions -void OSystem_WINCE3::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 OSystem_WINCE3::loadDeviceConfigurationElement(String element, int &value, int defaultValue) { - value = ConfMan.getInt(element, ConfMan.kApplicationDomain); - if (!value) { - value = defaultValue; - ConfMan.setInt(element, value, ConfMan.kApplicationDomain); - } -} - -void OSystem_WINCE3::loadDeviceConfiguration() { - 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(); -} - -void OSystem_WINCE3::add_left_click(bool pushed) { - int x, y; - retrieve_mouse_location(x, y); - EventsBuffer::simulateMouseLeftClick(x, y, pushed); -} - -void OSystem_WINCE3::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 OSystem_WINCE3::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 OSystem_WINCE3::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 OSystem_WINCE3::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 OSystem_WINCE3::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 OSystem_WINCE3::create_toolbar() { - PanelKeyboard *keyboard; - - // Add the keyboard - keyboard = new PanelKeyboard(PANEL_KEYBOARD); - _toolbarHandler.add(NAME_PANEL_KEYBOARD, *keyboard); - _toolbarHandler.setVisible(false); -} - -void OSystem_WINCE3::setupMixer() { - SDL_AudioSpec desired; - int thread_priority; - - uint32 sampleRate = compute_sample_rate(); - if (sampleRate == 0) - warning("OSystem_WINCE3::setupMixer called with sample rate 0 - audio will not work"); - else if (_mixer && _mixer->getOutputRate() == sampleRate) { - debug(1, "Skipping sound mixer re-init: samplerate is good"); - return; - } - - memset(&desired, 0, sizeof(desired)); - desired.freq = sampleRate; - desired.format = AUDIO_S16SYS; - desired.channels = 2; - desired.samples = 128; - desired.callback = private_sound_proc; - desired.userdata = this; - - // Create the mixer instance - if (_mixer == 0) - _mixer = new Audio::MixerImpl(this, sampleRate); - - // Add sound thread priority - if (!ConfMan.hasKey("sound_thread_priority")) - thread_priority = THREAD_PRIORITY_NORMAL; - else - thread_priority = ConfMan.getInt("sound_thread_priority"); - - desired.thread_priority = thread_priority; - - SDL_CloseAudio(); - if (SDL_OpenAudio(&desired, NULL) != 0) { - warning("Could not open audio device: %s", SDL_GetError()); - _mixer->setReady(false); - - } else { - debug(1, "Sound opened OK, mixing at %d Hz", sampleRate); - - // Re-create mixer to match the output rate - int vol1 = _mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType); - int vol2 = _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType); - int vol3 = _mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType); - int vol4 = _mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType); - delete _mixer; - _mixer = new Audio::MixerImpl(this, sampleRate); - _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, vol1); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, vol2); - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, vol3); - _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, vol4); - _mixer->setReady(true); - SDL_PauseAudio(0); - } -} - -void OSystem_WINCE3::private_sound_proc(void *param, byte *buf, int len) { - OSystem_WINCE3 *this_ = (OSystem_WINCE3 *)param; - assert(this_); - - if (this_->_mixer) - this_->_mixer->mixCallback(buf, len); - if (!_soundMaster) - memset(buf, 0, len); -} - -#ifdef USE_VORBIS -bool OSystem_WINCE3::checkOggHighSampleRate() { - char trackFile[255]; - FILE *testFile; - OggVorbis_File *test_ov_file = new OggVorbis_File; - - // FIXME: The following sprintf assumes that "path" is always - // terminated by a path separator. This is *not* true in general. - // This code really should check for the path separator, or even - // better, use the FSNode API. - sprintf(trackFile, "%sTrack1.ogg", ConfMan.get("path").c_str()); - // Check if we have an OGG audio track - testFile = fopen(trackFile, "rb"); - if (testFile) { - if (!ov_open(testFile, test_ov_file, NULL, 0)) { - bool highSampleRate = (ov_info(test_ov_file, -1)->rate == 22050); - ov_clear(test_ov_file); - delete test_ov_file; - return highSampleRate; - } - } - - // Do not test for OGG samples - too big and too slow anyway :) - - delete test_ov_file; - return false; -} -#endif - -uint32 OSystem_WINCE3::compute_sample_rate() { - uint32 sampleRate; - - // Force at least medium quality FM synthesis for FOTAQ - Common::String gameid(ConfMan.get("gameid")); - if (gameid == "queen") { - if (!((ConfMan.hasKey("FM_high_quality") && ConfMan.getBool("FM_high_quality")) || - (ConfMan.hasKey("FM_medium_quality") && ConfMan.getBool("FM_medium_quality")))) { - ConfMan.setBool("FM_medium_quality", true); - ConfMan.flushToDisk(); - } - } - // See if the output frequency is forced by the game - if (gameid == "ft" || gameid == "dig" || gameid == "comi" || gameid == "queen" || gameid == "sword" || gameid == "agi") - sampleRate = SAMPLES_PER_SEC_NEW; - else { - if (ConfMan.hasKey("high_sample_rate") && ConfMan.getBool("high_sample_rate")) - sampleRate = SAMPLES_PER_SEC_NEW; - else - sampleRate = SAMPLES_PER_SEC_OLD; - } - -#ifdef USE_VORBIS - // Modify the sample rate on the fly if OGG is involved - if (sampleRate == SAMPLES_PER_SEC_OLD) - if (checkOggHighSampleRate()) - sampleRate = SAMPLES_PER_SEC_NEW; -#endif - - return sampleRate; -} void OSystem_WINCE3::engineInit() { check_mappings(); // called here to initialize virtual keys handling //update_game_settings(); // finalize mixer init - setupMixer(); -} - -const OSystem::GraphicsMode *OSystem_WINCE3::getSupportedGraphicsModes() const { - if (CEDevice::hasWideResolution()) - return s_supportedGraphicsModesHigh; - else - return s_supportedGraphicsModesLow; -} - -bool OSystem_WINCE3::hasFeature(Feature f) { - return (f == kFeatureVirtualKeyboard); -} - -void OSystem_WINCE3::setFeatureState(Feature f, bool enable) { - switch (f) { - case kFeatureFullscreenMode: - return; - - case 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 kFeatureDisableKeyFiltering: - if (_hasSmartphoneResolution) - _unfilteredkeys = enable; - return; - - default: - OSystem_SDL::setFeatureState(f, enable); - } -} - -bool OSystem_WINCE3::getFeatureState(Feature f) { - switch (f) { - case kFeatureFullscreenMode: - return false; - case kFeatureVirtualKeyboard: - return (_panelStateForced); - default: - return OSystem_SDL::getFeatureState(f); - } + _mixerManager->init(); } void OSystem_WINCE3::check_mappings() { @@ -974,7 +479,7 @@ void OSystem_WINCE3::check_mappings() { return; GUI_Actions::Instance()->initInstanceGame(); - instance = (CEActionsPocket*)GUI_Actions::Instance(); + instance = (CEActionsPocket *)GUI_Actions::Instance(); // Some games need to map the right click button, signal it here if it wasn't done if (instance->needsRightClickMapping()) { @@ -1014,1472 +519,39 @@ void OSystem_WINCE3::check_mappings() { // Extra warning for Zak Mc Kracken if (strncmp(gameid.c_str(), "zak", 3) == 0 && - !GUI_Actions::Instance()->getMapping(POCKET_ACTION_HIDE)) { + !GUI_Actions::Instance()->getMapping(POCKET_ACTION_HIDE)) { GUI::MessageDialog alert(_("Don't forget to map a key to 'Hide Toolbar' action to see the whole inventory")); alert.runModal(); } } -void OSystem_WINCE3::update_game_settings() { - Common::String gameid(ConfMan.get("gameid")); - - // Finish panel initialization - if (!_panelInitialized && !gameid.empty()) { - Panel *panel; - _panelInitialized = true; - // Add the main panel - panel = new Panel(0, 32); - panel->setBackground(IMAGE_PANEL); - // Save - panel->add(NAME_ITEM_OPTIONS, new ItemAction(ITEM_OPTIONS, POCKET_ACTION_SAVE)); - // Skip - panel->add(NAME_ITEM_SKIP, new ItemAction(ITEM_SKIP, POCKET_ACTION_SKIP)); - // sound - panel->add(NAME_ITEM_SOUND, new ItemSwitch(ITEM_SOUND_OFF, ITEM_SOUND_ON, &_soundMaster)); - // bind keys - panel->add(NAME_ITEM_BINDKEYS, new 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 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 OSystem_WINCE3::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; - - OSystem_SDL::initSize(w, h, format); - - if (_scalersChanged) { - unloadGFXMode(); - loadGFXMode(); - _scalersChanged = false; - } - - update_game_settings(); -} - - -int OSystem_WINCE3::getDefaultGraphicsMode() const { - return GFX_NORMAL; -} - void OSystem_WINCE3::setGraphicsModeIntern() { // Scalers have been pre-selected for the desired mode. // No further tuning required. } -bool OSystem_WINCE3::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 (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 && !(isOzone() && (getScreenWidth() >= 640 || getScreenHeight() >= 640))) { - _scaleFactorXm = 1; - _scaleFactorXd = 2; - _scaleFactorYm = 1; - _scaleFactorYd = 2; - _scalerProc = DownscaleAllByHalf; - } else if (_videoMode.screenWidth == 640 && (isOzone() && (getScreenWidth() >= 640 || 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; -} - -bool OSystem_WINCE3::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 (isOzone() && (getScreenWidth() >= 640 || 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 > getScreenWidth() && _videoMode.scaleFactor * _videoMode.screenWidth > getScreenHeight()) - || (_videoMode.scaleFactor * _videoMode.screenHeight > getScreenWidth() && _videoMode.scaleFactor * _videoMode.screenHeight > 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 OSystem_WINCE3::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()); - 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 = (uint16 *)calloc(640 * 80, sizeof(uint16)); - _toolbarHigh = SDL_CreateRGBSurfaceFrom(toolbar_screen, 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? - _km.x_max = _videoMode.screenWidth * _scaleFactorXm / _scaleFactorXd - 1; - _km.y_max = _videoMode.screenHeight * _scaleFactorXm / _scaleFactorXd - 1; - _km.delay_time = 25; - _km.last_time = 0; - - return true; -} - -void OSystem_WINCE3::unloadGFXMode() { - if (_screen) { - SDL_FreeSurface(_screen); - _screen = NULL; - } - - if (_hwscreen) { - SDL_FreeSurface(_hwscreen); - _hwscreen = NULL; - } - - if (_tmpscreen) { - SDL_FreeSurface(_tmpscreen); - _tmpscreen = NULL; - } -} - -bool OSystem_WINCE3::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; -} - -void OSystem_WINCE3::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; - } +void OSystem_WINCE3::initSDL() { + // Check if SDL has not been initialized + if (!_initedSDL) { + uint32 sdlFlags = SDL_INIT_EVENTTHREAD; + if (ConfMan.hasKey("disable_sdl_parachute")) + sdlFlags |= SDL_INIT_NOPARACHUTE; - 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()); + if (ConfMan.hasKey("use_GDI") && ConfMan.getBool("use_GDI")) { + SDL_VideoInit("windib", 0); + sdlFlags ^= SDL_INIT_VIDEO; } - 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 > _platformScreenWidth) continue; - if (routy + routh > _platformScreenWidth) { - routh = _platformScreenWidth - routy; - r->h = routh * _scaleFactorYd / _scaleFactorYm; - } - } else { - if (routy > _platformScreenHeight) continue; - if (routy + routh > _platformScreenHeight) { - routh = _platformScreenHeight - routy; - r->h = routh * _scaleFactorYd / _scaleFactorYm; - } - } - - // check if the toolbar is overwritten - if (toolbarVisible && r->y + r->h >= toolbarOffset) - _toolbarHandler.forceRedraw(); + // Initialize SDL (SDL Subsystems are initiliazed in the corresponding sdl managers) + if (SDL_Init(sdlFlags) == -1) + error("Could not initialize SDL: %s", SDL_GetError()); - // 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); + // Enable unicode support if possible + SDL_EnableUNICODE(1); - // 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; -} - -Graphics::Surface *OSystem_WINCE3::lockScreen() { - // Make sure mouse pointer is not painted over the playfield at the time of locking - undrawMouse(); - return OSystem_SDL::lockScreen(); -} - -void OSystem_WINCE3::unlockScreen() { - OSystem_SDL::unlockScreen(); -} - -bool OSystem_WINCE3::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 OSystem_WINCE3::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; + _initedSDL = true; } - - 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 OSystem_WINCE3::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 OSystem_WINCE3::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 OSystem_WINCE3::setMousePos(int x, int y) { - if (x != _mouseCurState.x || y != _mouseCurState.y) { - undrawMouse(); - _mouseCurState.x = x; - _mouseCurState.y = y; - updateScreen(); - } -} - - -void OSystem_WINCE3::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 OSystem_WINCE3::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; -} - -bool OSystem_WINCE3::showMouse(bool visible) { - if (_mouseVisible == visible) - return visible; - - if (visible == false) - undrawMouse(); - - bool last = _mouseVisible; - _mouseVisible = visible; - _mouseNeedsRedraw = true; - - return last; -} - -void OSystem_WINCE3::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 OSystem_WINCE3::blitCursor() { -} - -void OSystem_WINCE3::showOverlay() { - assert (_transactionMode == kTransactionNone); - - if (_overlayVisible) - return; - - undrawMouse(); - _overlayVisible = true; - update_scalers(); - clearOverlay(); -} - -void OSystem_WINCE3::hideOverlay() { - assert (_transactionMode == kTransactionNone); - - if (!_overlayVisible) - return; - - undrawMouse(); - _overlayVisible = false; - clearOverlay(); - _forceFull = true; -} - -void OSystem_WINCE3::drawMouse() { - if (!(_toolbarHandler.visible() && _mouseCurState.y >= _toolbarHandler.getOffset() && !_usesEmulatedMouse) && !_forceHideMouse) - internDrawMouse(); -} - -void OSystem_WINCE3::fillMouseEvent(Common::Event &event, int x, int y) { - event.mouse.x = x; - event.mouse.y = y; - - // Update the "keyboard mouse" coords - _km.x = event.mouse.x; - _km.y = event.mouse.y; - - // Adjust for the screen scaling - if (_zoomDown) - event.mouse.y += 240; - - event.mouse.x = event.mouse.x * _scaleFactorXd / _scaleFactorXm; - event.mouse.y = event.mouse.y * _scaleFactorYd / _scaleFactorYm; -} - -void OSystem_WINCE3::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 OSystem_WINCE3::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 OSystem_WINCE3::addDirtyRect(int x, int y, int w, int h, bool mouseRect) { - - if (_forceFull || _paletteDirtyEnd) - return; - - OSystem_SDL::addDirtyRect(x, y, w, h, false); -} - -static int mapKeyCE(SDLKey key, SDLMod mod, Uint16 unicode, bool unfilter) { - if (GUI::Actions::Instance()->mappingActive()) - return key; - - if (unfilter) { - switch (key) { - case SDLK_ESCAPE: - return SDLK_BACKSPACE; - case SDLK_F8: - return SDLK_ASTERISK; - case SDLK_F9: - return SDLK_HASH; - default: - return key; - } - } - - if (key >= SDLK_KP0 && key <= SDLK_KP9) { - return key - SDLK_KP0 + '0'; - } else if (key >= SDLK_UP && key <= SDLK_PAGEDOWN) { - return key; - } else if (key >= SDLK_NUMLOCK && key <= SDLK_EURO) { - return 0; - } - return key; -} - -bool OSystem_WINCE3::pollEvent(Common::Event &event) { - SDL_Event ev; - ev.type = SDL_NOEVENT; - DWORD currentTime; - bool keyEvent = false; - int deltaX, deltaY; - - memset(&event, 0, sizeof(Common::Event)); - - handleKbdMouse(); - - // If the screen mode changed, send an Common::EVENT_SCREEN_CHANGED - if (_modeChanged) { - _modeChanged = false; - event.type = Common::EVENT_SCREEN_CHANGED; - _screenChangeCount++; - return true; - } - - CEDevice::wakeUp(); - - currentTime = GetTickCount(); - - while (SDL_PollEvent(&ev)) { - switch (ev.type) { - case SDL_KEYDOWN: - debug(1, "Key down %X %s", ev.key.keysym.sym, SDL_GetKeyName((SDLKey)ev.key.keysym.sym)); - // KMOD_RESERVED is used if the key has been injected by an external buffer - if (ev.key.keysym.mod != KMOD_RESERVED && !_unfilteredkeys) { - keyEvent = true; - _lastKeyPressed = ev.key.keysym.sym; - _keyRepeatTime = currentTime; - _keyRepeat = 0; - - if (!GUI_Actions::Instance()->mappingActive() && GUI_Actions::Instance()->performMapped(ev.key.keysym.sym, true)) - return true; - } - - if (GUI_Actions::Instance()->mappingActive()) - event.kbd.flags = 0xFF; - else if (ev.key.keysym.sym == SDLK_PAUSE) { - _lastKeyPressed = 0; - event.type = Common::EVENT_PREDICTIVE_DIALOG; - return true; - } event.type = Common::EVENT_KEYDOWN; - if (!_unfilteredkeys) - event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym; - else - event.kbd.keycode = (Common::KeyCode)mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, _unfilteredkeys); - event.kbd.ascii = mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, _unfilteredkeys); - - if (ev.key.keysym.mod == KMOD_RESERVED && ev.key.keysym.unicode == KMOD_SHIFT) { - event.kbd.ascii ^= 0x20; - event.kbd.flags = Common::KBD_SHIFT; - } - - return true; - - case SDL_KEYUP: - debug(1, "Key up %X %s", ev.key.keysym.sym, SDL_GetKeyName((SDLKey)ev.key.keysym.sym)); - // KMOD_RESERVED is used if the key has been injected by an external buffer - if (ev.key.keysym.mod != KMOD_RESERVED && !_unfilteredkeys) { - keyEvent = true; - _lastKeyPressed = 0; - - if (!GUI_Actions::Instance()->mappingActive() && GUI_Actions::Instance()->performMapped(ev.key.keysym.sym, false)) - return true; - } - - if (GUI_Actions::Instance()->mappingActive()) - event.kbd.flags = 0xFF; - else if (ev.key.keysym.sym == SDLK_PAUSE) { - _lastKeyPressed = 0; - return false; // chew up the show agi dialog key up event - } - - event.type = Common::EVENT_KEYUP; - if (!_unfilteredkeys) - event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym; - else - event.kbd.keycode = (Common::KeyCode)mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, _unfilteredkeys); - event.kbd.ascii = mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, _unfilteredkeys); - - if (ev.key.keysym.mod == KMOD_RESERVED && ev.key.keysym.unicode == KMOD_SHIFT) { - event.kbd.ascii ^= 0x20; - event.kbd.flags = Common::KBD_SHIFT; - } - - return true; - - case SDL_MOUSEMOTION: - event.type = Common::EVENT_MOUSEMOVE; - fillMouseEvent(event, ev.motion.x, ev.motion.y); - setMousePos(event.mouse.x, event.mouse.y); - return true; - - case SDL_MOUSEBUTTONDOWN: - if (ev.button.button == SDL_BUTTON_LEFT) - event.type = Common::EVENT_LBUTTONDOWN; - else if (ev.button.button == SDL_BUTTON_RIGHT) - event.type = Common::EVENT_RBUTTONDOWN; - else - break; - fillMouseEvent(event, ev.button.x, ev.button.y); - - - if (event.mouse.x > _tapX) - deltaX = event.mouse.x - _tapX; - else - deltaX = _tapX - event.mouse.x; - if (event.mouse.y > _tapY) - deltaY = event.mouse.y - _tapY; - else - deltaY = _tapY - event.mouse.y; - _closeClick = (deltaX <= 5 && deltaY <= 5); - - if (!_isSmartphone) { - // handle double-taps - if (_tapTime) { // second tap - if (_closeClick && (GetTickCount() - _tapTime < 1000)) { - if (event.mouse.y <= 20 && _panelInitialized) { // top of screen (show panel) - swap_panel_visibility(); - } else if (!_noDoubleTapRMB) { // right click - event.type = Common::EVENT_RBUTTONDOWN; - _rbutton = true; - } - } - _tapTime = 0; - } else { - _tapTime = GetTickCount(); - _tapX = event.mouse.x; - _tapY = event.mouse.y; - } - } - - if (_freeLook && !_closeClick) { - _rbutton = false; - _tapTime = 0; - _tapX = event.mouse.x; - _tapY = event.mouse.y; - event.type = Common::EVENT_MOUSEMOVE; - setMousePos(event.mouse.x, event.mouse.y); - } - - - if (_toolbarHandler.action(event.mouse.x, event.mouse.y, true)) { - if (!_toolbarHandler.drawn()) { - _toolbarHighDrawn = false; - internUpdateScreen(); - } - if (_newOrientation != _orientationLandscape){ - _orientationLandscape = _newOrientation; - _toolbarHighDrawn = false; - ConfMan.setInt("landscape", _orientationLandscape); - ConfMan.flushToDisk(); - hotswapGFXMode(); - } - return false; - } - - return true; - - case SDL_MOUSEBUTTONUP: - if (ev.button.button == SDL_BUTTON_LEFT) - event.type = Common::EVENT_LBUTTONUP; - else if (ev.button.button == SDL_BUTTON_RIGHT) - event.type = Common::EVENT_RBUTTONUP; - else - break; - - if (_rbutton) { - event.type = Common::EVENT_RBUTTONUP; - _rbutton = false; - } - - fillMouseEvent(event, ev.button.x, ev.button.y); - - if (_freeLook && !_closeClick) { - _tapX = event.mouse.x; - _tapY = event.mouse.y; - event.type = Common::EVENT_MOUSEMOVE; - setMousePos(event.mouse.x, event.mouse.y); - } - - if (_toolbarHandler.action(event.mouse.x, event.mouse.y, false)) { - if (!_toolbarHandler.drawn()) { - _toolbarHighDrawn = false; - internUpdateScreen(); - } - return false; - - } - return true; - - case SDL_VIDEOEXPOSE: - _forceFull = true; - break; - - case SDL_QUIT: - event.type = Common::EVENT_QUIT; - return true; - - case SDL_ACTIVEEVENT: - if (ev.active.state & SDL_APPMOUSEFOCUS) - debug(2, "%s mouse focus.", ev.active.gain ? "Got" : "Lost"); - if (ev.active.state & SDL_APPINPUTFOCUS) - debug(2, "%s input focus.", ev.active.gain ? "Got" : "Lost"); - if (ev.active.state & SDL_APPACTIVE) - debug(2, "%s total focus.", ev.active.gain ? "Got" : "Lost"); - if (ev.active.state & SDL_APPINPUTFOCUS) { - _hasfocus = ev.active.gain; - SDL_PauseAudio(!_hasfocus); - _forceFull |= _hasfocus; - } - break; - } - } - - // Simulate repeated key for backend - if (!keyEvent && _lastKeyPressed && currentTime > _keyRepeatTime + _keyRepeatTrigger) { - _keyRepeatTime = currentTime; - _keyRepeat++; - GUI_Actions::Instance()->performMapped(_lastKeyPressed, true); - } - - return false; } void OSystem_WINCE3::quit() { @@ -2497,19 +569,14 @@ void OSystem_WINCE3::getTimeAndDate(TimeDate &t) const { SYSTEMTIME systime; GetLocalTime(&systime); - t.tm_year = systime.wYear - 1900; - t.tm_mon = systime.wMonth - 1; - t.tm_mday = systime.wDay; - t.tm_hour = systime.wHour; - t.tm_min = systime.wMinute; - t.tm_sec = systime.wSecond; + t.tm_year = systime.wYear - 1900; + t.tm_mon = systime.wMonth - 1; + t.tm_mday = systime.wDay; + t.tm_hour = systime.wHour; + t.tm_min = systime.wMinute; + t.tm_sec = systime.wSecond; } int OSystem_WINCE3::_platformScreenWidth; int OSystem_WINCE3::_platformScreenHeight; bool OSystem_WINCE3::_isOzone; -OSystem_WINCE3::zoneDesc OSystem_WINCE3::_zones[TOTAL_ZONES] = { - { 0, 0, 320, 145 }, - { 0, 145, 150, 55 }, - { 150, 145, 170, 55 } -}; diff --git a/backends/platform/wince/wince-sdl.h b/backends/platform/wince/wince-sdl.h index 6cc6e538e1..d7ede8ca81 100644 --- a/backends/platform/wince/wince-sdl.h +++ b/backends/platform/wince/wince-sdl.h @@ -35,7 +35,10 @@ #include "backends/platform/wince/CEkeys/CEKeys.h" #include "backends/platform/wince/CEDevice.h" -#define TOTAL_ZONES 3 +#include "backends/graphics/wincesdl/wincesdl-graphics.h" +#include "backends/events/wincesdl/wincesdl-events.h" +#include "backends/timer/default/default-timer.h" +#include "backends/fs/windows/windows-fs-factory.h" // defines used for implementing the raw frame buffer access method (2003+) #define GETRAWFRAMEBUFFER 0x00020001 @@ -46,202 +49,45 @@ class OSystem_WINCE3 : public OSystem_SDL { public: OSystem_WINCE3(); - - // Update the dirty areas of the screen - void internUpdateScreen(); + virtual ~OSystem_WINCE3(); void setGraphicsModeIntern(); - void initSize(uint w, uint h, const Graphics::PixelFormat *format); void initBackend(); - // Overloaded from SDL backend (toolbar handling) - bool pollEvent(Common::Event &event); - // Overloaded from SDL backend (toolbar handling) - void drawMouse(); - // Overloaded from SDL backend (mouse and new scaler handling) - void fillMouseEvent(Common::Event &event, int x, int y); - // 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); // Overloaded from SDL backend void quit(); - // Overloaded from SDL backend (master volume and sample rate subtleties) - void setupMixer(); // Overloaded from OSystem void engineInit(); void getTimeAndDate(TimeDate &t) const; virtual Common::String getDefaultConfigFileName(); + virtual FilesystemFactory *getFilesystemFactory(); - - // Overloaded from SDL_Common (FIXME) - 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 undrawMouse(); - void blitCursor(); - bool showMouse(bool visible); - void setMousePos(int x, int y); - void copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h); // overloaded by CE backend (FIXME) - void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h); - void showOverlay(); - void hideOverlay(); - Graphics::Surface *lockScreen(); - void unlockScreen(); - - // GUI and action stuff - void swap_panel_visibility(); - void swap_panel(); void swap_sound_master(); - void add_right_click(bool pushed); - void swap_mouse_visibility(); - void swap_freeLook(); - void swap_zoom_up(); - void swap_zoom_down(); - void swap_smartphone_keyboard(); - -//#ifdef WIN32_PLATFORM_WFSP - // Smartphone actions - - void initZones(); - void loadDeviceConfigurationElement(String element, int &value, int defaultValue); - void loadDeviceConfiguration(); - void add_left_click(bool pushed); - void move_cursor_up(); - void move_cursor_down(); - void move_cursor_left(); - void move_cursor_right(); - void switch_zone(); - void smartphone_rotate_display(); -//#endif static int getScreenWidth(); static int getScreenHeight(); static void initScreenInfos(); static bool isOzone(); -protected: - bool loadGFXMode(); - void unloadGFXMode(); - bool hotswapGFXMode(); - bool saveScreenshot(const char *filename); - + static bool _soundMaster; // turn off sound after all calculations + // static since needed by the SDL callback - const GraphicsMode *getSupportedGraphicsModes() const; - bool setGraphicsMode(int mode); - //int getGraphicsMode() const; - int getDefaultGraphicsMode() const; - - bool hasFeature(Feature f); - void setFeatureState(Feature f, bool enable); - bool getFeatureState(Feature f); - - void internDrawMouse(); - void drawToolbarMouse(SDL_Surface *surf, bool draw); +protected: + void initSDL(); + Audio::MixerImpl *_mixer; + DefaultTimerManager *_timer; + FilesystemFactory *_fsFactory; private: - -#ifdef USE_VORBIS - bool checkOggHighSampleRate(); -#endif - - static void private_sound_proc(void *param, byte *buf, int len); - - bool update_scalers(); - void create_toolbar(); - void update_game_settings(); void check_mappings(); - uint32 compute_sample_rate(); - - void retrieve_mouse_location(int &x, int &y); - - CEGUI::ToolbarHandler _toolbarHandler; - SDL_Surface *_toolbarLow; // toolbar 320x40 - SDL_Surface *_toolbarHigh; // toolbar 640x80 - bool _toolbarHighDrawn; // cache toolbar 640x80 - - bool _freeLook; // freeLook mode (do not send mouse button events) - - bool _forceHideMouse; // force invisible mouse cursor - - bool _forcePanelInvisible; // force panel visibility for some cases - bool _panelVisible; // panel visibility - bool _panelStateForced; // panel visibility forced by external call - - bool _panelInitialized; // only initialize the toolbar once - - bool _unfilteredkeys; // discard key mapping temporarily (agi pred. dialog) - static bool _soundMaster; // turn off sound after all calculations - // static since needed by the SDL callback - int _orientationLandscape; // current orientation - int _newOrientation; // new orientation - - bool _saveToolbarState; // save visibility when forced - String _saveActiveToolbar; // save active toolbar when forced - - bool _saveToolbarZoom; // save visibility when zooming - bool _zoomUp; // zooming up mode - bool _zoomDown; // zooming down mode - - bool _noDoubleTapRMB; // disable double tap -> rmb click - bool _rbutton; // double tap -> right button simulation - bool _closeClick; // flag when taps are spatially close together - - bool _usesEmulatedMouse; // emulated mousemove ever been used in this session - - bool _canBeAspectScaled; // game screen size allows for aspect scaling - - int _scaleFactorXm; // scaler X * - int _scaleFactorXd; // scaler X / - int _scaleFactorYm; // scaler Y * - int _scaleFactorYd; // scaler Y / - SDL_Rect _dirtyRectOut[NUM_DIRTY_RECT]; - bool _scalersChanged; - bool _hasfocus; // scummvm has the top window + bool _forcePanelInvisible; // force panel visibility for some cases static int _platformScreenWidth; static int _platformScreenHeight; - static bool _isOzone; // true if running on Windows 2003 SE - - // Keyboard tap - int _tapX; - int _tapY; - long _tapTime; - - // Mouse - int _mouseHotspotX, _mouseHotspotY; - byte *_mouseBackupOld; - uint16 *_mouseBackupToolbar; - uint16 _mouseBackupDim; - - // 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 - - 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) - - int _mouseXZone[TOTAL_ZONES]; - int _mouseYZone[TOTAL_ZONES]; - int _currentZone; - - struct zoneDesc { - int x; - int y; - int width; - int height; - }; - - static zoneDesc _zones[TOTAL_ZONES]; + static bool _isOzone; // true if running on Windows 2003 SE + }; #endif |