diff options
Diffstat (limited to 'backends/platform')
164 files changed, 11219 insertions, 4401 deletions
diff --git a/backends/platform/android/README.build b/backends/platform/android/README.build index 1c407bd469..f3fb77cbcf 100644 --- a/backends/platform/android/README.build +++ b/backends/platform/android/README.build @@ -82,7 +82,8 @@ Then build ScummVM: export ANDROID_TOP=<root of built Android source> - ./configure --backend=android --host=android --enable-zlib #and any other flags + ./configure --backend=android --host=android --enable-zlib --disable-timidity + # ... and any other configure flags you want make scummvm.apk This will build a "monolithic" ScummVM package, with the engines diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index dcc4e37458..38f387b201 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -109,7 +109,7 @@ static void JNU_ThrowByName(JNIEnv* env, const char* name, const char* msg) { env->DeleteLocalRef(cls); } -// floating point. use sparingly. +// floating point. use sparingly. template <class T> static inline T scalef(T in, float numerator, float denominator) { return static_cast<float>(in) * numerator / denominator; @@ -177,7 +177,6 @@ private: GLESPaletteTexture* _game_texture; int _shake_offset; Common::Rect _focus_rect; - bool _full_screen_dirty; // Overlay layer GLES4444Texture* _overlay_texture; @@ -320,7 +319,6 @@ OSystem_Android::OSystem_Android(jobject am) _fsFactory(new POSIXFilesystemFactory()), _asset_archive(new AndroidAssetArchive(am)), _shake_offset(0), - _full_screen_dirty(false), _event_queue_lock(createMutex()) { } @@ -862,6 +860,9 @@ void OSystem_Android::hideOverlay() { void OSystem_Android::clearOverlay() { ENTER("clearOverlay()"); _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) { @@ -887,6 +888,9 @@ void OSystem_Android::copyRectToOverlay(const OverlayColor *buf, int pitch, // 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() { diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java index d39aa363ef..6986f3988d 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java @@ -23,6 +23,8 @@ import javax.microedition.khronos.egl.EGLSurface; import java.io.File; import java.util.concurrent.Semaphore; +import java.util.Map; +import java.util.LinkedHashMap; // At least in Android 2.1, eglCreateWindowSurface() requires an @@ -109,6 +111,51 @@ public class ScummVM implements SurfaceHolder.Callback { } } + // 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); + } + 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])); + } + } + // Called by ScummVM thread (from initBackend) private void createScummVMGLContext() { egl = (EGL10)EGLContext.getEGL(); @@ -125,10 +172,75 @@ public class ScummVM implements SurfaceHolder.Callback { EGLConfig[] configs = new EGLConfig[numConfigs]; egl.eglChooseConfig(eglDisplay, configSpec, configs, numConfigs, num_config); - eglConfig = configs[0]; + + if (false) { + Log.d(LOG_TAG, + String.format("Found %d EGL configurations.", numConfigs)); + for (EGLConfig config : configs) + dumpEglConfig(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); + } eglContext = egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, null); + if (eglContext == EGL10.EGL_NO_CONTEXT) + throw new RuntimeException("Failed to create context"); + } + + private EGLConfig chooseEglConfig(EGLConfig[] configs) { + int best = 0; + int bestScore = -1; + int[] value = new int[1]; + 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; + + // 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 + } + + egl.eglGetConfigAttrib(eglDisplay, config, + EGL10.EGL_DEPTH_SIZE, value); + score -= value[0]; // penalize for wasted bits + + if (score > bestScore) { + best = i; + bestScore = score; + } + } + + if (bestScore < 0) { + Log.e(LOG_TAG, "Unable to find an acceptable EGL config, expect badness."); + return configs[0]; + } + + return configs[best]; } // Called by ScummVM thread @@ -137,12 +249,13 @@ public class ScummVM implements SurfaceHolder.Callback { try { surfaceLock.acquire(); } catch (InterruptedException e) { - Log.e(this.toString(), - "Interrupted while waiting for surface lock", 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(); @@ -302,8 +415,8 @@ public class ScummVM implements SurfaceHolder.Callback { 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)); + "Unable to get min audio buffer size (error %d). Guessing %dB.", + buf_size, guess)); buf_size = guess; } Log.d(LOG_TAG, String.format("Using %dB buffer for %dHZ audio", diff --git a/backends/platform/android/video.cpp b/backends/platform/android/video.cpp index d4c002fbd0..81a8f7fbc7 100644 --- a/backends/platform/android/video.cpp +++ b/backends/platform/android/video.cpp @@ -38,6 +38,9 @@ #include "backends/platform/android/video.h" +// Unfortunately, Android devices are too varied to make broad assumptions :/ +#define TEXSUBIMAGE_IS_EXPENSIVE 0 + #undef LOG_TAG #define LOG_TAG "ScummVM-video" @@ -158,13 +161,11 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) { // later (perhaps with multiple TexSubImage2D operations). CHECK_GL_ERROR(); glBindTexture(GL_TEXTURE_2D, _texture_name); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); CHECK_GL_ERROR(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - CHECK_GL_ERROR(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - CHECK_GL_ERROR(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - CHECK_GL_ERROR(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); CHECK_GL_ERROR(); glTexImage2D(GL_TEXTURE_2D, 0, glFormat(), @@ -177,6 +178,7 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, const void* buf, int pitch) { ENTER("updateBuffer(%u, %u, %u, %u, %p, %d)", x, y, w, h, buf, pitch); glBindTexture(GL_TEXTURE_2D, _texture_name); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); setDirtyRect(Common::Rect(x, y, x+w, y+h)); @@ -185,7 +187,25 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, glFormat(), glType(), buf); } else { // GLES removed the ability to specify pitch, so we - // have to do this row by row. + // 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); + 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 { glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, @@ -193,16 +213,15 @@ void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, ++y; src += pitch; } while (--h); +#endif } } void GLESTexture::fillBuffer(byte x) { - byte tmpbuf[_surface.h * _surface.w * bytesPerPixel()]; - memset(tmpbuf, 0, _surface.h * _surface.w * bytesPerPixel()); - glBindTexture(GL_TEXTURE_2D, _texture_name); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _surface.w, _surface.h, - glFormat(), glType(), tmpbuf); - setDirty(); + 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) { @@ -215,6 +234,7 @@ void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { //glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); const GLint crop[4] = {0, _surface.h, _surface.w, -_surface.h}; glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); + glColor4ub(0xff, 0xff, 0xff, 0xff); // Android GLES bug? glDrawTexiOES(x, y, 0, w, h); } else #endif diff --git a/backends/platform/dingux/dingux-events.cpp b/backends/platform/dingux/dingux-events.cpp new file mode 100644 index 0000000000..f9b519623d --- /dev/null +++ b/backends/platform/dingux/dingux-events.cpp @@ -0,0 +1,215 @@ +/* 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 "backends/platform/dingux/dingux.h" + +#include "graphics/scaler/aspect.h" // for aspect2Real + +#if defined (DINGUX) + +#define PAD_UP SDLK_UP +#define PAD_DOWN SDLK_DOWN +#define PAD_LEFT SDLK_LEFT +#define PAD_RIGHT SDLK_RIGHT +#define BUT_A SDLK_LCTRL +#define BUT_B SDLK_LALT +#define BUT_X SDLK_SPACE +#define BUT_Y SDLK_LSHIFT +#define BUT_SELECT SDLK_ESCAPE +#define BUT_START SDLK_RETURN +#define TRIG_L SDLK_TAB +#define TRIG_R SDLK_BACKSPACE + +static int mapKey(SDLKey key, SDLMod mod, Uint16 unicode) { + if (key >= SDLK_F1 && key <= SDLK_F9) { + return key - SDLK_F1 + Common::ASCII_F1; + } else if (key >= SDLK_KP0 && key <= SDLK_KP9) { + return key - SDLK_KP0 + '0'; + } else if (key >= SDLK_UP && key <= SDLK_PAGEDOWN) { + return key; + } else if (unicode) { + return unicode; + } else if (key >= 'a' && key <= 'z' && (mod & KMOD_SHIFT)) { + return key & ~0x20; + } else if (key >= SDLK_NUMLOCK && key <= SDLK_EURO) { + return 0; + } + return key; +} + +bool OSystem_SDL_Dingux::remapKey(SDL_Event &ev, Common::Event &event) { + if (ev.key.keysym.sym == PAD_UP) { + if (ev.type == SDL_KEYDOWN) { + _km.y_vel = -1; + _km.y_down_count = 1; + } else { + _km.y_vel = 0; + _km.y_down_count = 0; + } + + event.type = Common::EVENT_MOUSEMOVE; + fillMouseEvent(event, _km.x, _km.y); + + return true; + } else if (ev.key.keysym.sym == PAD_DOWN) { + if (ev.type == SDL_KEYDOWN) { + _km.y_vel = 1; + _km.y_down_count = 1; + } else { + _km.y_vel = 0; + _km.y_down_count = 0; + } + + event.type = Common::EVENT_MOUSEMOVE; + fillMouseEvent(event, _km.x, _km.y); + + return true; + } else if (ev.key.keysym.sym == PAD_LEFT) { + if (ev.type == SDL_KEYDOWN) { + _km.x_vel = -1; + _km.x_down_count = 1; + } else { + _km.x_vel = 0; + _km.x_down_count = 0; + } + + event.type = Common::EVENT_MOUSEMOVE; + fillMouseEvent(event, _km.x, _km.y); + + return true; + } else if (ev.key.keysym.sym == PAD_RIGHT) { + if (ev.type == SDL_KEYDOWN) { + _km.x_vel = 1; + _km.x_down_count = 1; + } else { + _km.x_vel = 0; + _km.x_down_count = 0; + } + + event.type = Common::EVENT_MOUSEMOVE; + fillMouseEvent(event, _km.x, _km.y); + + return true; + } else if (ev.key.keysym.sym == BUT_Y) { // left mouse button + if (ev.type == SDL_KEYDOWN) { + event.type = Common::EVENT_LBUTTONDOWN; + } else { + event.type = Common::EVENT_LBUTTONUP; + } + + fillMouseEvent(event, _km.x, _km.y); + + return true; + } else if (ev.key.keysym.sym == BUT_B) { // right mouse button + if (ev.type == SDL_KEYDOWN) { + event.type = Common::EVENT_RBUTTONDOWN; + } else { + event.type = Common::EVENT_RBUTTONUP; + } + + fillMouseEvent(event, _km.x, _km.y); + + return true; + } else if (ev.key.keysym.sym == BUT_X) { // '.' skip dialogue + ev.key.keysym.sym = SDLK_PERIOD; + ev.key.keysym.mod = (SDLMod)0; + ev.key.keysym.unicode = '.'; + } else if (ev.key.keysym.sym == TRIG_L) { // global menu + ev.key.keysym.sym = SDLK_F5; + event.kbd.keycode = Common::KEYCODE_F5; + event.kbd.ascii = Common::ASCII_F5; + event.kbd.flags = Common::KBD_CTRL; + + if (ev.type == SDL_KEYDOWN) { + event.type = Common::EVENT_KEYDOWN; + } else { + event.type = Common::EVENT_KEYUP; + } + + return true; + } else if (ev.key.keysym.sym == BUT_A) { // key '0' + ev.key.keysym.sym = SDLK_0; + + event.kbd.keycode = Common::KEYCODE_0; + event.kbd.ascii = '0'; + event.kbd.flags = 0; + + if (ev.type == SDL_KEYDOWN) { + event.type = Common::EVENT_KEYDOWN; + } else { + event.type = Common::EVENT_KEYUP; + } + + return true; + } else if (ev.key.keysym.sym == BUT_SELECT) { // virtual keyboard + ev.key.keysym.sym = SDLK_F7; + + } else if (ev.key.keysym.sym == BUT_START) { // F5, menu in some games + ev.key.keysym.sym = SDLK_F5; + + } else if (ev.key.keysym.sym == TRIG_R) { // ESC + ev.key.keysym.sym = SDLK_ESCAPE; + } else { + event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym; + event.kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode); + } + + return false; +} + +void OSystem_SDL_Dingux::fillMouseEvent(Common::Event &event, int x, int y) { + if (_videoMode.mode == GFX_HALF && !_overlayVisible) { + event.mouse.x = x * 2; + event.mouse.y = y * 2; + } else { + event.mouse.x = x; + event.mouse.y = y; + } + + // Update the "keyboard mouse" coords + _km.x = x; + _km.y = y; + + // Adjust for the screen scaling + if (!_overlayVisible) { + event.mouse.x /= _videoMode.scaleFactor; + event.mouse.y /= _videoMode.scaleFactor; + if (_videoMode.aspectRatioCorrection) + event.mouse.y = aspect2Real(event.mouse.y); + } +} + +void OSystem_SDL_Dingux::warpMouse(int x, int y) { + if (_mouseCurState.x != x || _mouseCurState.y != y) { + if (_videoMode.mode == GFX_HALF && !_overlayVisible) { + x = x / 2; + y = y / 2; + } + } + OSystem_SDL::warpMouse(x, y); +} + +#endif + diff --git a/backends/platform/dingux/dingux-graphics.cpp b/backends/platform/dingux/dingux-graphics.cpp new file mode 100644 index 0000000000..bbd4a58636 --- /dev/null +++ b/backends/platform/dingux/dingux-graphics.cpp @@ -0,0 +1,468 @@ +/* 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 "backends/platform/dingux/dingux.h" + +#include "common/mutex.h" +#include "graphics/scaler.h" +#include "graphics/scaler/aspect.h" +#include "graphics/scaler/downscaler.h" +#include "graphics/surface.h" + +#if defined (DINGUX) + +static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { + {"1x", "Standard", GFX_NORMAL}, + {0, 0, 0} +}; + +int OSystem_SDL_Dingux::getDefaultGraphicsMode() const { + return GFX_NORMAL; +} + +const OSystem::GraphicsMode *OSystem_SDL_Dingux::getSupportedGraphicsModes() const { + return s_supportedGraphicsModes; +} + +bool OSystem_SDL_Dingux::setGraphicsMode(int mode) { + Common::StackLock lock(_graphicsMutex); + + assert(_transactionMode == kTransactionActive); + + if (_oldVideoMode.setup && _oldVideoMode.mode == mode) + return true; + + int newScaleFactor = 1; + + switch (mode) { + case GFX_NORMAL: + newScaleFactor = 1; + break; + case GFX_HALF: + newScaleFactor = 1; + break; + default: + warning("unknown gfx mode %d", mode); + return false; + } + + _transactionDetails.normal1xScaler = (mode == GFX_NORMAL); + if (_oldVideoMode.setup && _oldVideoMode.scaleFactor != newScaleFactor) + _transactionDetails.needHotswap = true; + + _transactionDetails.needUpdatescreen = true; + + _videoMode.mode = mode; + _videoMode.scaleFactor = newScaleFactor; + + return true; +} + +void OSystem_SDL_Dingux::setGraphicsModeIntern() { + Common::StackLock lock(_graphicsMutex); + ScalerProc *newScalerProc = 0; + + switch (_videoMode.mode) { + case GFX_NORMAL: + newScalerProc = Normal1x; + break; + case GFX_HALF: + newScalerProc = DownscaleAllByHalf; + break; + + default: + error("Unknown gfx mode %d", _videoMode.mode); + } + + _scalerProc = newScalerProc; + + if (!_screen || !_hwscreen) + return; + + // Blit everything to the screen + _forceFull = true; + + // Even if the old and new scale factors are the same, we may have a + // different scaler for the cursor now. + blitCursor(); +} + +void OSystem_SDL_Dingux::initSize(uint w, uint h) { + assert(_transactionMode == kTransactionActive); + + // Avoid redundant res changes + if ((int)w == _videoMode.screenWidth && (int)h == _videoMode.screenHeight) + return; + + _videoMode.screenWidth = w; + _videoMode.screenHeight = h; + if (w > 320 || h > 240) { + setGraphicsMode(GFX_HALF); + setGraphicsModeIntern(); + toggleMouseGrab(); + } + + _transactionDetails.sizeChanged = true; +} + +void OSystem_SDL_Dingux::drawMouse() { + if (!_mouseVisible || !_mouseSurface) { + _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0; + return; + } + + SDL_Rect dst; + int scale; + int hotX, hotY; + + if (_videoMode.mode == GFX_HALF && !_overlayVisible) { + dst.x = _mouseCurState.x / 2; + dst.y = _mouseCurState.y / 2; + } else { + dst.x = _mouseCurState.x; + dst.y = _mouseCurState.y; + } + + if (!_overlayVisible) { + scale = _videoMode.scaleFactor; + dst.w = _mouseCurState.vW; + dst.h = _mouseCurState.vH; + hotX = _mouseCurState.vHotX; + hotY = _mouseCurState.vHotY; + } else { + scale = 1; + dst.w = _mouseCurState.rW; + dst.h = _mouseCurState.rH; + hotX = _mouseCurState.rHotX; + hotY = _mouseCurState.rHotY; + } + + // The mouse is undrawn using virtual coordinates, i.e. they may be + // scaled and aspect-ratio corrected. + + _mouseBackup.x = dst.x - hotX; + _mouseBackup.y = dst.y - hotY; + _mouseBackup.w = dst.w; + _mouseBackup.h = dst.h; + + // We draw the pre-scaled cursor image, so now we need to adjust for + // scaling, shake position and aspect ratio correction manually. + + if (!_overlayVisible) { + dst.y += _currentShakePos; + } + + if (_videoMode.aspectRatioCorrection && !_overlayVisible) + dst.y = real2Aspect(dst.y); + + dst.x = scale * dst.x - _mouseCurState.rHotX; + dst.y = scale * dst.y - _mouseCurState.rHotY; + dst.w = _mouseCurState.rW; + dst.h = _mouseCurState.rH; + + // Note that SDL_BlitSurface() and addDirtyRect() will both perform any + // clipping necessary + + if (SDL_BlitSurface(_mouseSurface, NULL, _hwscreen, &dst) != 0) + error("SDL_BlitSurface failed: %s", SDL_GetError()); + + // The screen will be updated using real surface coordinates, i.e. + // they will not be scaled or aspect-ratio corrected. + addDirtyRect(dst.x, dst.y, dst.w, dst.h, true); +} + +void OSystem_SDL_Dingux::undrawMouse() { + const int x = _mouseBackup.x; + const int y = _mouseBackup.y; + + // When we switch bigger overlay off mouse jumps. Argh! + // This is intended to prevent undrawing offscreen mouse + if (!_overlayVisible && (x >= _videoMode.screenWidth || y >= _videoMode.screenHeight)) + return; + + if (_mouseBackup.w != 0 && _mouseBackup.h != 0) { + if (_videoMode.mode == GFX_HALF && !_overlayVisible) { + addDirtyRect(x*2, y*2, _mouseBackup.w*2, _mouseBackup.h*2); + } else { + addDirtyRect(x, y, _mouseBackup.w, _mouseBackup.h); + } + } +} + +void OSystem_SDL_Dingux::internUpdateScreen() { + SDL_Surface *srcSurf, *origSurf; + int height, width; + ScalerProc *scalerProc; + int scale1; + +#if defined (DEBUG) && ! defined(_WIN32_WCE) // definitions not available for non-DEBUG here. (needed this to compile in SYMBIAN32 & linux?) + assert(_hwscreen != NULL); + assert(_hwscreen->map->sw_data != NULL); +#endif + + // If the shake position changed, fill the dirty area with blackness + if (_currentShakePos != _newShakePos) { + SDL_Rect blackrect = {0, 0, _videoMode.screenWidth * _videoMode.scaleFactor, _newShakePos * _videoMode.scaleFactor}; + + if (_videoMode.aspectRatioCorrection && !_overlayVisible) + blackrect.h = real2Aspect(blackrect.h - 1) + 1; + + SDL_FillRect(_hwscreen, &blackrect, 0); + + _currentShakePos = _newShakePos; + + _forceFull = true; + } + + // Check whether the palette was changed in the meantime and update the + // screen surface accordingly. + if (_screen && _paletteDirtyEnd != 0) { + SDL_SetColors(_screen, _currentPalette + _paletteDirtyStart, + _paletteDirtyStart, + _paletteDirtyEnd - _paletteDirtyStart); + + _paletteDirtyEnd = 0; + + _forceFull = true; + } + +#ifdef USE_OSD + // OSD visible (i.e. non-transparent)? + if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + // Updated alpha value + const int diff = SDL_GetTicks() - _osdFadeStartTime; + if (diff > 0) { + if (diff >= kOSDFadeOutDuration) { + // Back to full transparency + _osdAlpha = SDL_ALPHA_TRANSPARENT; + } else { + // Do a linear fade out... + const int startAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100; + _osdAlpha = startAlpha + diff * (SDL_ALPHA_TRANSPARENT - startAlpha) / kOSDFadeOutDuration; + } + SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha); + _forceFull = true; + } + } +#endif + + if (!_overlayVisible) { + origSurf = _screen; + srcSurf = _tmpscreen; + width = _videoMode.screenWidth; + height = _videoMode.screenHeight; + scalerProc = _scalerProc; + scale1 = _videoMode.scaleFactor; + } else { + origSurf = _overlayscreen; + srcSurf = _tmpscreen2; + width = _videoMode.overlayWidth; + height = _videoMode.overlayHeight; + scalerProc = Normal1x; + scale1 = 1; + } + + // Add the area covered by the mouse cursor to the list of dirty rects if + // we have to redraw the mouse. + if (_mouseNeedsRedraw) + undrawMouse(); + + // Force a full redraw if requested + if (_forceFull) { + _numDirtyRects = 1; + _dirtyRectList[0].x = 0; + _dirtyRectList[0].y = 0; + _dirtyRectList[0].w = width; + _dirtyRectList[0].h = height; + } + + // Only draw anything if necessary + if (_numDirtyRects > 0 || _mouseNeedsRedraw) { + SDL_Rect *r; + SDL_Rect dst; + uint32 srcPitch, dstPitch; + SDL_Rect *lastRect = _dirtyRectList + _numDirtyRects; + + for (r = _dirtyRectList; r != lastRect; ++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. + + 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; r != lastRect; ++r) { + register int dst_y = r->y + _currentShakePos; + register int dst_h = 0; + register int dst_w = r->w; + register int orig_dst_y = 0; + register int dst_x = r->x; + register int src_y; + register int src_x; + + if (dst_y < height) { + dst_h = r->h; + if (dst_h > height - dst_y) + dst_h = height - dst_y; + + orig_dst_y = dst_y; + src_x = dst_x; + src_y = dst_y; + + if (_videoMode.aspectRatioCorrection && !_overlayVisible) + dst_y = real2Aspect(dst_y); + + assert(scalerProc != NULL); + + if ((_videoMode.mode == GFX_HALF) && (scalerProc == DownscaleAllByHalf)) { + if (dst_x % 2 == 1) { + dst_x--; + dst_w++; + } + if (dst_y % 2 == 1) { + dst_y--; + dst_h++; + } + src_x = dst_x; + src_y = dst_y; + dst_x = dst_x / 2; + dst_y = dst_y / 2; + + scalerProc((byte *)srcSurf->pixels + (src_x * 2 + 2) + (src_y + 1) * srcPitch, srcPitch, + (byte *)_hwscreen->pixels + dst_x * 2 + dst_y * dstPitch, dstPitch, dst_w, dst_h); + + } else { + scalerProc((byte *)srcSurf->pixels + (r->x * 2 + 2) + (r->y + 1) * srcPitch, srcPitch, + (byte *)_hwscreen->pixels + r->x * 2 + dst_y * dstPitch, dstPitch, r->w, dst_h); + } + } + + if (_videoMode.mode == GFX_HALF && scalerProc == DownscaleAllByHalf) { + r->w = r->w / 2; + r->h = dst_h / 2; + } else { + r->w = r->w; + r->h = dst_h; + } + + r->x = dst_x; + r->y = dst_y; + + +#ifdef USE_SCALERS + if (_videoMode.aspectRatioCorrection && orig_dst_y < height && !_overlayVisible) + r->h = stretch200To240((uint8 *) _hwscreen->pixels, dstPitch, r->w, r->h, r->x, r->y, orig_dst_y * scale1); +#endif + } + SDL_UnlockSurface(srcSurf); + SDL_UnlockSurface(_hwscreen); + + // Readjust the dirty rect list in case we are doing a full update. + // This is necessary if shaking is active. + if (_forceFull) { + _dirtyRectList[0].y = 0; + _dirtyRectList[0].h = (_videoMode.mode == GFX_HALF) ? effectiveScreenHeight() / 2 : effectiveScreenHeight(); + } + + drawMouse(); + +#ifdef USE_OSD + if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + SDL_BlitSurface(_osdSurface, 0, _hwscreen, 0); + } +#endif + // Finally, blit all our changes to the screen + SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList); + } + + _numDirtyRects = 0; + _forceFull = false; + _mouseNeedsRedraw = false; +} + +void OSystem_SDL_Dingux::showOverlay() { + if (_videoMode.mode == GFX_HALF) { + _mouseCurState.x = _mouseCurState.x / 2; + _mouseCurState.y = _mouseCurState.y / 2; + } + OSystem_SDL::showOverlay(); +} + +void OSystem_SDL_Dingux::hideOverlay() { + if (_videoMode.mode == GFX_HALF) { + _mouseCurState.x = _mouseCurState.x * 2; + _mouseCurState.y = _mouseCurState.y * 2; + } + OSystem_SDL::hideOverlay(); +} + +bool OSystem_SDL_Dingux::loadGFXMode() { + + // Forcefully disable aspect ratio correction for games + // which starts with a native 240px height resolution. + // This fixes games with weird resolutions, like MM Nes (256x240) + if(_videoMode.screenHeight == 240) { + _videoMode.aspectRatioCorrection = false; + } + + fprintf(stdout, "Game ScreenMode = %d*%d\n", _videoMode.screenWidth, _videoMode.screenHeight); + if (_videoMode.screenWidth > 320 || _videoMode.screenHeight > 240) { + _videoMode.aspectRatioCorrection = false; + setGraphicsMode(GFX_HALF); + fprintf(stdout, "GraphicsMode set to HALF\n"); + } else { + setGraphicsMode(GFX_NORMAL); + fprintf(stdout, "GraphicsMode set to NORMAL\n"); + } + + if ((_videoMode.mode == GFX_HALF) && !_overlayVisible) { + _videoMode.overlayWidth = _videoMode.screenWidth / 2; + _videoMode.overlayHeight = _videoMode.screenHeight / 2; + _videoMode.fullscreen = true; + } else { + + _videoMode.overlayWidth = _videoMode.screenWidth * _videoMode.scaleFactor; + _videoMode.overlayHeight = _videoMode.screenHeight * _videoMode.scaleFactor; + + if (_videoMode.aspectRatioCorrection) + _videoMode.overlayHeight = real2Aspect(_videoMode.overlayHeight); + + _videoMode.hardwareWidth = _videoMode.screenWidth * _videoMode.scaleFactor; + _videoMode.hardwareHeight = effectiveScreenHeight(); + } + + + return OSystem_SDL::loadGFXMode(); +} + +#endif + diff --git a/backends/platform/dingux/dingux.cpp b/backends/platform/dingux/dingux.cpp index 98bf51f49c..cdf10600ce 100644 --- a/backends/platform/dingux/dingux.cpp +++ b/backends/platform/dingux/dingux.cpp @@ -23,25 +23,35 @@ * */ +#include "backends/platform/dingux/dingux.h" + #if defined(DINGUX) -#include "backends/platform/dingux/dingux.h" -#include "backends/events/dinguxsdl/dinguxsdl-events.h" -#include "backends/graphics/dinguxsdl/dinguxsdl-graphics.h" - -void OSystem_SDL_Dingux::initBackend() { - // Create the events manager - if (_eventSource == 0) - _eventSource = new DINGUXSdlEventSource(); - - // Create the graphics manager - if (_graphicsManager == 0) { - _graphicsManager = new DINGUXSdlGraphicsManager(_eventSource); - ((DINGUXSdlEventSource*)_eventSource)->setCurrentGraphMan((DINGUXSdlGraphicsManager*)_graphicsManager); +bool OSystem_SDL_Dingux::hasFeature(Feature f) { + return + (f == kFeatureAspectRatioCorrection) || + (f == kFeatureCursorHasPalette); +} + +void OSystem_SDL_Dingux::setFeatureState(Feature f, bool enable) { + switch (f) { + case kFeatureAspectRatioCorrection: + setAspectRatioCorrection(enable); + break; + default: + break; } +} - // Call parent implementation of this method - OSystem_POSIX::initBackend(); +bool OSystem_SDL_Dingux::getFeatureState(Feature f) { + assert(_transactionMode == kTransactionNone); + + switch (f) { + case kFeatureAspectRatioCorrection: + return _videoMode.aspectRatioCorrection; + default: + return false; + } } #endif diff --git a/backends/platform/dingux/dingux.h b/backends/platform/dingux/dingux.h index 80b2ecae5f..846ad3faf9 100644 --- a/backends/platform/dingux/dingux.h +++ b/backends/platform/dingux/dingux.h @@ -26,21 +26,44 @@ #ifndef SDL_DINGUX_COMMON_H #define SDL_DINGUX_COMMON_H -#if defined(DINGUX) - #include <SDL.h> + #include "backends/base-backend.h" #include "backends/platform/sdl/sdl.h" -#include "backends/platform/sdl/posix/posix.h" -#include "backends/graphics/dinguxsdl/dinguxsdl-graphics.h" -#include "backends/events/dinguxsdl/dinguxsdl-events.h" -class OSystem_SDL_Dingux : public OSystem_POSIX { +#if defined(DINGUX) + +enum { + GFX_HALF = 12 +}; + +class OSystem_SDL_Dingux : public OSystem_SDL { public: - void initBackend(); + virtual bool hasFeature(Feature f); + virtual void setFeatureState(Feature f, bool enable); + virtual bool getFeatureState(Feature f); + virtual int getDefaultGraphicsMode() const; + + void initSize(uint w, uint h); + const OSystem::GraphicsMode *getSupportedGraphicsModes() const; + bool setGraphicsMode(const char *name); + bool setGraphicsMode(int mode); + void setGraphicsModeIntern(); + void internUpdateScreen(); + void showOverlay(); + void hideOverlay(); + bool loadGFXMode(); + void drawMouse(); + void undrawMouse(); + void warpMouse(int, int); + void fillMouseEvent(Common::Event&, int, int); + +protected: + virtual bool remapKey(SDL_Event &ev, Common::Event &event); }; -#endif /* DINGUX */ -#endif /* SDL_DINGUX_COMMON_H */ +#endif + +#endif diff --git a/backends/platform/dingux/main.cpp b/backends/platform/dingux/main.cpp index 587c65334e..7b02151c1a 100644 --- a/backends/platform/dingux/main.cpp +++ b/backends/platform/dingux/main.cpp @@ -24,7 +24,8 @@ */ #include "backends/platform/dingux/dingux.h" -#include "backends/plugins/posix/posix-provider.h" +#include "backends/plugins/sdl/sdl-provider.h" +//#include "backends/plugins/posix/posix-provider.h" #include "base/main.h" #if defined(DINGUX) @@ -36,17 +37,16 @@ int main(int argc, char* argv[]) { g_system = new OSystem_SDL_Dingux(); assert(g_system); - ((OSystem_SDL_Dingux *)g_system)->init(); - #ifdef DYNAMIC_MODULES - PluginManager::instance().addPluginProvider(new POSIXPluginProvider()); + PluginManager::instance().addPluginProvider(new SDLPluginProvider()); +// PluginManager::instance().addPluginProvider(new POSIXPluginProvider()); #endif // Invoke the actual ScummVM main entry point: int res = scummvm_main(argc, argv); - ((OSystem_SDL_Dingux *)g_system)->deinit(); - + ((OSystem_SDL *)g_system)->deinit(); return res; + } #endif diff --git a/backends/platform/dingux/module.mk b/backends/platform/dingux/module.mk index 2247625a04..309fb94442 100644 --- a/backends/platform/dingux/module.mk +++ b/backends/platform/dingux/module.mk @@ -2,7 +2,9 @@ MODULE := backends/platform/dingux MODULE_OBJS := \ main.o \ - dingux.o + dingux.o \ + dingux-events.o \ + dingux-graphics.o \ MODULE_DIRS += \ backends/platform/dingux/ diff --git a/backends/platform/ds/arm9/source/dsmain.cpp b/backends/platform/ds/arm9/source/dsmain.cpp index 1525647c2e..a9dc05b89c 100644 --- a/backends/platform/ds/arm9/source/dsmain.cpp +++ b/backends/platform/ds/arm9/source/dsmain.cpp @@ -105,6 +105,7 @@ #endif #include "engine.h" +#include "backends/plugins/ds/ds-provider.h" #include "backends/fs/ds/ds-fs.h" #include "base/version.h" #include "common/util.h" @@ -3213,6 +3214,9 @@ int main(void) { const char *argv[] = {"/scummvmds"}; #endif +#ifdef DYNAMIC_MODULES + PluginManager::instance().addPluginProvider(new DSPluginProvider()); +#endif while (1) { scummvm_main(ARRAYSIZE(argv), (char **) &argv); diff --git a/backends/platform/ds/build-ds.sh b/backends/platform/ds/build-ds.sh new file mode 100755 index 0000000000..d56af5a092 --- /dev/null +++ b/backends/platform/ds/build-ds.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# +# build-ds.sh -- script for building a ds build with every usable dynamic engine plugin + +make clean + +#Set up a static build with only engines usable by DS enabled +./configure --host=ds --disable-debug --disable-all-engines --enable-scumm --enable-sky --enable-queen --enable-agos --enable-gob --enable-cine --enable-agi --enable-kyra --enable-lure --enable-parallaction --enable-made --enable-cruise + +make clean + +make + +#Dump all symbols used in this garbage-collected static build into a file +rm -f ds.syms +arm-eabi-objdump -t scummvm.elf > ds.syms + +make clean + +#Set up a dynamic build with only engines usable by the DS enabled +./configure --host=ds --enable-plugins --default-dynamic --disable-debug --disable-all-engines --enable-scumm --enable-sky --enable-queen --enable-gob --enable-cine --enable-agos --enable-agi --enable-kyra --enable-lure --enable-parallaction --enable-made --enable-cruise + +make clean + +#Make this final build, which is selectively stripped with the assistance of the ds.syms file that was generated earlier +make diff --git a/backends/platform/gp2x/build/README-GP2X b/backends/platform/gp2x/build/README-GP2X index dc93a9f1c9..3c6591d369 100644 --- a/backends/platform/gp2x/build/README-GP2X +++ b/backends/platform/gp2x/build/README-GP2X @@ -1,19 +1,10 @@ -ScummVM - GP2X SPECIFIC README - HEAD SVN +ScummVM - GP2X SPECIFIC README ------------------------------------------------------------------------ Contents: * About the backend/port <#About_the_backendport> - * Game compatability <#Game_compatibility> - * Included engines <#Included_engines> * Supported audio options <#Supported_audio_options> - * Supported cut-scene options <#Supported_cut-scene_options> - * Recent changes <#Recent_changes> - * How to save <#How_to_save> - * Controller mappings <#Controller_mappings> - * Know issues <#Know_issues> - * TODO's <#Major_TODOs> - * Additional resources/links <#Additional_resourceslinks> * Credits <#Credits> ------------------------------------------------------------------------ @@ -26,47 +17,24 @@ WiKi: <http://wiki.scummvm.org/index.php/GP2X> for the most current information on the port and any updates to this documentation. +The wiki includes detailed instructions on how to use the port and +control information. + ------------------------------------------------------------------------ About the backend/port -This is the readme for the offficial GP2X ScummVM backend (also known as +This is the readme for the official GP2X ScummVM backend (also known as the GP2X port). This is an SVN test release of ScummVM for the GP2X, it would be appreciated if this SVN test distribution was not mirrored and that -people be directed to http://www.distant-earth.com/scummvm instead for +people be directed to http://scummvm.distant-earth.com/ instead for updated SVN builds. Full supported official releases of the GP2X ScummVM backend are made in line with main official releases and are avalalble from the ScummVM downloads page <http://www.scummvm.org/downloads.php>. -This build is in an active state of development and as such no -?expected? behavior can be guaranteed ;). - -SVN builds are quickly tested with firmware 2.0.0 for reference. - -Please refer to the GP2X ScummVM forum -<http://forums.scummvm.org/viewforum.php?f=14> and WiKi -<http://wiki.scummvm.org/index.php/GP2X> for the latest information on -the port. - ------------------------------------------------------------------------- -Game compatibility - -For information on the compatability of a specific game please refer to -the GP2X compatability section of the ScummVM WiKi -<http://wiki.scummvm.org/index.php/GP2X#Compatibility_List>. - -Please note the version and date of the ScummVM build you are running -when reviewing the above list. - ------------------------------------------------------------------------- -Included engines - -Just because an engine is included does not mean any/all of its games -are supported. Please check game compatability for more infomation. - ------------------------------------------------------------------------ Supported audio options @@ -79,106 +47,6 @@ FLAC audio is currently unsupported. For best results use uncompressed audio in games. ------------------------------------------------------------------------ -Supported cut-scene options - -No cut scene compression options are currently supported. - -DXA video support will be added as soon as it is stable. - ------------------------------------------------------------------------- -Recent changes - -Refined audio hacks to reduce audio delay a little more. -Enabled hardware scalar code. -Now built using SDL 1.2.9 for the parts of the port that use SDL (some -parts now hit the hardware directly). -Enabled new launcher - (Ensure defaulttheme.zip is in the same folder as -the executable). -Aspect Ratio Correction can now be disabled ?per game?. When adding a -game you can find this option on the GFX tab. -Note: This will cause the game to run with a black border at the bottom -as it will be rendered to a 320*200 frame. - ------------------------------------------------------------------------- -How to save - -NOTE: Everything is saved to the SD card, saves are stored in the saves -folder under your main ScummVM executable unless you set another save -location. - -The configiration file for ScummVM (.scummvmrc) is stored in the same -place as the ScummVM executable. - -The save process below is for Scumm engine games but the principle is -the same for all. - -In Game. - -1. Right Trigger -2. Select SAVE with B -3. Select a position with B -4. Right trigger puts ? in the name box for some text. -5. Press B to save - -Basically the emulated keys you can use are equivelent to the values -buttons are mapped to, - -I have a virtual keyboard like the GP32 one (left/right on the stick to -pick chars) to add in at some point ;-) - ------------------------------------------------------------------------- -Controller mappings - -Mouse emulation: - -Stick: Move Pointer -Stick Click: ?light? Left Click -B: Left click -X: Right click - -Keyboard emulation: - -Start: Return -Select: Escape -Y: Space Bar (Pause) -Right Trigger: Game Menu (Save, Load, Quit etc.) -Volume Buttons: Increase and Decrease volume (5% per press) - -Fancy button combos: - -NOTE: To use button combos press and hold the Left Trigger then... - -Y: Toggle "zoom" mode - Try it in larger games like Broken Sword. -Volume Buttons: Increase and Decrease subtitle speed (In SCUMM games) -Right Trigger: 0 (For skipping the copy protection in Monkey Island 2) -Select: Exit ScummVM completely (and gracefully) - ------------------------------------------------------------------------- -Know issues - -Possible random crash (well SegFault). I have had this happen twice and -have not tracked down the cause. -It happens very infrequently, both times it was in the DOTT CD intro. -Saving often is never a bad idea anyhow. - ------------------------------------------------------------------------- -TODO's - -Fix save support when using the Sky engine (Beneath a Steel Sky) - You -CAN'T save at the moment but auto save works. - ------------------------------------------------------------------------- -Additional resources/links - - * ScummVM WiKi GP2X page <http://wiki.scummvm.org/index.php/GP2X> - * ScummVM forums GP2X forum - <http://forums.scummvm.org/viewforum.php?f=14> - * My own ScummVM page <http://scummvm.distant-earth.com/> (for - SVN/test builds) - * Main ScummVM site <http://www.scummvm.org> (for official supported - release builds) - ------------------------------------------------------------------------- Credits Core ScummVM code (c) The ScummVM Team diff --git a/backends/platform/gp2x/build/config.sh b/backends/platform/gp2x/build/config.sh index 2bc49564f7..e0a1bf1209 100755 --- a/backends/platform/gp2x/build/config.sh +++ b/backends/platform/gp2x/build/config.sh @@ -18,6 +18,7 @@ export DEFINES=-DNDEBUG # Edit the configure line to suit. cd ../../../.. ./configure --backend=gp2x --disable-mt32emu --host=gp2x --disable-flac --disable-nasm --disable-hq-scalers --with-sdl-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin --with-mpeg2-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-tremor --with-tremor-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-zlib --with-zlib-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-mad --with-mad-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-vkeybd -#--enable-plugins --default-dynamic +# --disable-release --enable-debug +# --enable-plugins --default-dynamic echo Generating config for GP2X complete. Check for errors. diff --git a/backends/platform/gp2x/build/scummvm.gpe b/backends/platform/gp2x/build/scummvm.gpe index 1e69c149b9..c6b051831c 100755 --- a/backends/platform/gp2x/build/scummvm.gpe +++ b/backends/platform/gp2x/build/scummvm.gpe @@ -4,7 +4,7 @@ mount -o sync,remount /dev/mmcsd/disc0/part1 /mnt/sd/ # Run ScummVM, important this bit. -./scummvm.gp2x +./scummvm.gph # Sync the SD card to check that everything is written. sync diff --git a/backends/platform/gp2x/events.cpp b/backends/platform/gp2x/events.cpp new file mode 100644 index 0000000000..08553968d2 --- /dev/null +++ b/backends/platform/gp2x/events.cpp @@ -0,0 +1,742 @@ +/* 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$ + * + */ + +/* + * GP2X: Common::Event Handling. + * + */ + +#include "backends/platform/gp2x/gp2x-common.h" +#include "backends/platform/gp2x/gp2x-hw.h" +#include "common/util.h" +#include "common/events.h" +#include "graphics/scaler/aspect.h" // for aspect2Real + +// FIXME move joystick defines out and replace with confile file options +// we should really allow users to map any key to a joystick button using the keymapper. +#define JOY_DEADZONE 2200 + +#define JOY_XAXIS 0 +#define JOY_YAXIS 1 + +/* Quick default button states for modifiers. */ +int BUTTON_STATE_L = false; + +enum { + /* DPAD/Stick */ + BUTTON_UP = 0, + BUTTON_UPLEFT = 1, + BUTTON_LEFT = 2, + BUTTON_DOWNLEFT = 3, + BUTTON_DOWN = 4, + BUTTON_DOWNRIGHT = 5, + BUTTON_RIGHT = 6, + BUTTON_UPRIGHT = 7, + /* Joystick Buttons */ + BUTTON_MENU = 8, // Start on F100 GP2X + BUTTON_SELECT = 9, + BUTTON_L = 10, + BUTTON_R = 11, + BUTTON_A = 12, + BUTTON_B = 13, + BUTTON_X = 14, + BUTTON_Y = 15, + BUTTON_VOLUP = 16, + BUTTON_VOLDOWN = 17, + BUTTON_CLICK = 18 +}; + +enum { + /* Unused Joystick Buttons on the GP2X */ + BUTTON_HOME = 51, + BUTTON_HOLD = 52, + BUTTON_HELP = 53, + BUTTON_HELP2 = 54 +}; + +enum { + /* Touchscreen TapMode */ + TAPMODE_LEFT = 0, + TAPMODE_RIGHT = 1, + TAPMODE_HOVER = 2 +}; + +static int mapKey(SDLKey key, SDLMod mod, Uint16 unicode) { + if (key >= SDLK_F1 && key <= SDLK_F9) { + return key - SDLK_F1 + Common::ASCII_F1; + } else if (key >= SDLK_KP0 && key <= SDLK_KP9) { + return key - SDLK_KP0 + '0'; + } else if (key >= SDLK_UP && key <= SDLK_PAGEDOWN) { + return key; + } else if (unicode) { + return unicode; + } else if (key >= 'a' && key <= 'z' && (mod & KMOD_SHIFT)) { + return key & ~0x20; + } else if (key >= SDLK_NUMLOCK && key <= SDLK_EURO) { + return 0; + } + return key; +} + +void OSystem_GP2X::fillMouseEvent(Common::Event &event, int x, int y) { + event.mouse.x = x; + event.mouse.y = y; + + // Update the "keyboard mouse" coords + _km.x = x; + _km.y = y; + + // Adjust for the screen scaling + if (!_overlayVisible) { + event.mouse.x /= _videoMode.scaleFactor; + event.mouse.y /= _videoMode.scaleFactor; + if (_videoMode.aspectRatioCorrection) + event.mouse.y = aspect2Real(event.mouse.y); + } +} + +void OSystem_GP2X::handleKbdMouse() { + uint32 curTime = getMillis(); + if (curTime >= _km.last_time + _km.delay_time) { + _km.last_time = curTime; + if (_km.x_down_count == 1) { + _km.x_down_time = curTime; + _km.x_down_count = 2; + } + if (_km.y_down_count == 1) { + _km.y_down_time = curTime; + _km.y_down_count = 2; + } + + if (_km.x_vel || _km.y_vel) { + if (_km.x_down_count) { + if (curTime > _km.x_down_time + _km.delay_time * 12) { + if (_km.x_vel > 0) + _km.x_vel++; + else + _km.x_vel--; + } else if (curTime > _km.x_down_time + _km.delay_time * 8) { + if (_km.x_vel > 0) + _km.x_vel = 5; + else + _km.x_vel = -5; + } + } + if (_km.y_down_count) { + if (curTime > _km.y_down_time + _km.delay_time * 12) { + if (_km.y_vel > 0) + _km.y_vel++; + else + _km.y_vel--; + } else if (curTime > _km.y_down_time + _km.delay_time * 8) { + if (_km.y_vel > 0) + _km.y_vel = 5; + else + _km.y_vel = -5; + } + } + + _km.x += _km.x_vel; + _km.y += _km.y_vel; + + if (_km.x < 0) { + _km.x = 0; + _km.x_vel = -1; + _km.x_down_count = 1; + } else if (_km.x > _km.x_max) { + _km.x = _km.x_max; + _km.x_vel = 1; + _km.x_down_count = 1; + } + + if (_km.y < 0) { + _km.y = 0; + _km.y_vel = -1; + _km.y_down_count = 1; + } else if (_km.y > _km.y_max) { + _km.y = _km.y_max; + _km.y_vel = 1; + _km.y_down_count = 1; + } + + SDL_WarpMouse((Uint16)_km.x, (Uint16)_km.y); + } + } +} + +static void SDLModToOSystemKeyFlags(SDLMod mod, Common::Event &event) { + + event.kbd.flags = 0; + + if (mod & KMOD_SHIFT) + event.kbd.flags |= Common::KBD_SHIFT; + if (mod & KMOD_ALT) + event.kbd.flags |= Common::KBD_ALT; + if (mod & KMOD_CTRL) + event.kbd.flags |= Common::KBD_CTRL; + + // Sticky flags + if (mod & KMOD_NUM) + event.kbd.flags |= Common::KBD_NUM; + if (mod & KMOD_CAPS) + event.kbd.flags |= Common::KBD_CAPS; +} + +void OSystem_GP2X::moveStick() { + bool stickBtn[32]; + + memcpy(stickBtn, _stickBtn, sizeof(stickBtn)); + + if ((stickBtn[0])||(stickBtn[2])||(stickBtn[4])||(stickBtn[6])) + stickBtn[1] = stickBtn[3] = stickBtn[5] = stickBtn[7] = 0; + + if ((stickBtn[1])||(stickBtn[2])||(stickBtn[3])){ + if (_km.x_down_count!=2){ + _km.x_vel = -1; + _km.x_down_count = 1; + }else + _km.x_vel = -4; + } else if ((stickBtn[5])||(stickBtn[6])||(stickBtn[7])){ + if (_km.x_down_count!=2){ + _km.x_vel = 1; + _km.x_down_count = 1; + } else + _km.x_vel = 4; + } else { + _km.x_vel = 0; + _km.x_down_count = 0; + } + + if ((stickBtn[0])||(stickBtn[1])||(stickBtn[7])){ + if (_km.y_down_count!=2){ + _km.y_vel = -1; + _km.y_down_count = 1; + }else + _km.y_vel = -4; + } else if ((stickBtn[3])||(stickBtn[4])||(stickBtn[5])){ + if (_km.y_down_count!=2){ + _km.y_vel = 1; + _km.y_down_count = 1; + } else + _km.y_vel = 4; + } else { + _km.y_vel = 0; + _km.y_down_count = 0; + } +} + +bool OSystem_GP2X::pollEvent(Common::Event &event) { + SDL_Event ev; + ev.type = SDL_NOEVENT; + + handleKbdMouse(); + + // If the screen mode changed, send an Common::EVENT_SCREEN_CHANGED + if (_modeChanged) { + _modeChanged = false; + event.type = Common::EVENT_SCREEN_CHANGED; + return true; + } + + while (SDL_PollEvent(&ev)) { + preprocessEvents(&ev); + if (dispatchSDLEvent(ev, event)) + return true; + } + return false; +} + +bool OSystem_GP2X::dispatchSDLEvent(SDL_Event &ev, Common::Event &event) { + switch (ev.type) { + case SDL_KEYDOWN: + return handleKeyDown(ev, event); + case SDL_KEYUP: + return handleKeyUp(ev, event); + case SDL_MOUSEMOTION: + return handleMouseMotion(ev, event); + case SDL_MOUSEBUTTONDOWN: + return handleMouseButtonDown(ev, event); + case SDL_MOUSEBUTTONUP: + return handleMouseButtonUp(ev, event); + case SDL_JOYBUTTONDOWN: + return handleJoyButtonDown(ev, event); + case SDL_JOYBUTTONUP: + return handleJoyButtonUp(ev, event); + case SDL_JOYAXISMOTION: + return handleJoyAxisMotion(ev, event); + + case SDL_VIDEOEXPOSE: + _forceFull = true; + break; + + case SDL_QUIT: + event.type = Common::EVENT_QUIT; + return true; + + } + + return false; +} + +bool OSystem_GP2X::handleKeyDown(SDL_Event &ev, Common::Event &event) { + + SDLModToOSystemKeyFlags(SDL_GetModState(), event); + + // Handle scroll lock as a key modifier + if (ev.key.keysym.sym == SDLK_SCROLLOCK) + _scrollLock = !_scrollLock; + + if (_scrollLock) + event.kbd.flags |= Common::KBD_SCRL; + + // Alt-Return and Alt-Enter toggle full screen mode + if (event.kbd.hasFlags(Common::KBD_ALT) && (ev.key.keysym.sym == SDLK_RETURN || ev.key.keysym.sym == SDLK_KP_ENTER)) { + beginGFXTransaction(); + setFullscreenMode(!_videoMode.fullscreen); + endGFXTransaction(); +#ifdef USE_OSD + if (_videoMode.fullscreen) + displayMessageOnOSD("Fullscreen mode"); + else + displayMessageOnOSD("Windowed mode"); +#endif + + return false; + } + + // Alt-S: Create a screenshot + if (event.kbd.hasFlags(Common::KBD_ALT) && ev.key.keysym.sym == 's') { + char filename[20]; + + for (int n = 0;; n++) { + SDL_RWops *file; + + sprintf(filename, "scummvm%05d.bmp", n); + file = SDL_RWFromFile(filename, "r"); + if (!file) + break; + SDL_RWclose(file); + } + if (saveScreenshot(filename)) + printf("Saved '%s'\n", filename); + else + printf("Could not save screenshot!\n"); + return false; + } + + // Ctrl-m toggles mouse capture + if (event.kbd.hasFlags(Common::KBD_CTRL) && ev.key.keysym.sym == 'm') { + toggleMouseGrab(); + return false; + } + + if ((ev.key.keysym.mod & KMOD_CTRL) && ev.key.keysym.sym == 'q') { + event.type = Common::EVENT_QUIT; + return true; + } + + if ((ev.key.keysym.mod & KMOD_CTRL) && ev.key.keysym.sym == 'u') { + event.type = Common::EVENT_MUTE; + return true; + } + + // Ctrl-Alt-<key> will change the GFX mode + if ((event.kbd.flags & (Common::KBD_CTRL|Common::KBD_ALT)) == (Common::KBD_CTRL|Common::KBD_ALT)) { + if (handleScalerHotkeys(ev.key)) + return false; + } + + if (remapKey(ev, event)) + return true; + + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym; + event.kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode); + + return true; +} + +bool OSystem_GP2X::handleKeyUp(SDL_Event &ev, Common::Event &event) { + if (remapKey(ev, event)) + return true; + + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym; + event.kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode); + + // Ctrl-Alt-<key> will change the GFX mode + SDLModToOSystemKeyFlags(SDL_GetModState(), event); + + // Set the scroll lock sticky flag + if (_scrollLock) + event.kbd.flags |= Common::KBD_SCRL; + + if (isScalerHotkey(event)) + // Swallow these key up events + return false; + + return true; +} + +bool OSystem_GP2X::handleMouseMotion(SDL_Event &ev, Common::Event &event) { + event.type = Common::EVENT_MOUSEMOVE; + fillMouseEvent(event, ev.motion.x, ev.motion.y); + + setMousePos(event.mouse.x, event.mouse.y); + return true; +} + +/* Custom handleMouseButtonDown/handleMouseButtonUp to deal with 'Tap Mode' for the touchscreen */ + +bool OSystem_GP2X::handleMouseButtonDown(SDL_Event &ev, Common::Event &event) { + if (ev.button.button == SDL_BUTTON_LEFT){ + if (BUTTON_STATE_L == true) /* BUTTON_STATE_L = Left Trigger Held, force Right Click */ + event.type = Common::EVENT_RBUTTONDOWN; + else if (GPH::tapmodeLevel == TAPMODE_LEFT) /* TAPMODE_LEFT = Left Click Tap Mode */ + event.type = Common::EVENT_LBUTTONDOWN; + else if (GPH::tapmodeLevel == TAPMODE_RIGHT) /* TAPMODE_RIGHT = Right Click Tap Mode */ + event.type = Common::EVENT_RBUTTONDOWN; + else if (GPH::tapmodeLevel == TAPMODE_HOVER) /* TAPMODE_HOVER = Hover (No Click) Tap Mode */ + event.type = Common::EVENT_MOUSEMOVE; + else + event.type = Common::EVENT_LBUTTONDOWN; /* For normal mice etc. */ + } + else if (ev.button.button == SDL_BUTTON_RIGHT) + event.type = Common::EVENT_RBUTTONDOWN; +#if defined(SDL_BUTTON_WHEELUP) && defined(SDL_BUTTON_WHEELDOWN) + else if (ev.button.button == SDL_BUTTON_WHEELUP) + event.type = Common::EVENT_WHEELUP; + else if (ev.button.button == SDL_BUTTON_WHEELDOWN) + event.type = Common::EVENT_WHEELDOWN; +#endif +#if defined(SDL_BUTTON_MIDDLE) + else if (ev.button.button == SDL_BUTTON_MIDDLE) + event.type = Common::EVENT_MBUTTONDOWN; +#endif + else + return false; + + fillMouseEvent(event, ev.button.x, ev.button.y); + + return true; +} + +bool OSystem_GP2X::handleMouseButtonUp(SDL_Event &ev, Common::Event &event) { + if (ev.button.button == SDL_BUTTON_LEFT){ + if (BUTTON_STATE_L == true) /* BUTTON_STATE_L = Left Trigger Held, force Right Click */ + event.type = Common::EVENT_RBUTTONUP; + else if (GPH::tapmodeLevel == TAPMODE_LEFT) /* TAPMODE_LEFT = Left Click Tap Mode */ + event.type = Common::EVENT_LBUTTONUP; + else if (GPH::tapmodeLevel == TAPMODE_RIGHT) /* TAPMODE_RIGHT = Right Click Tap Mode */ + event.type = Common::EVENT_RBUTTONUP; + else if (GPH::tapmodeLevel == TAPMODE_HOVER) /* TAPMODE_HOVER = Hover (No Click) Tap Mode */ + event.type = Common::EVENT_MOUSEMOVE; + else + event.type = Common::EVENT_LBUTTONUP; /* For normal mice etc. */ + + } + else if (ev.button.button == SDL_BUTTON_RIGHT) + event.type = Common::EVENT_RBUTTONUP; +#if defined(SDL_BUTTON_MIDDLE) + else if (ev.button.button == SDL_BUTTON_MIDDLE) + event.type = Common::EVENT_MBUTTONUP; +#endif + else + return false; + + fillMouseEvent(event, ev.button.x, ev.button.y); + + return true; +} + +/* Custom handleJoyButtonDown/handleJoyButtonUp to deal with the joystick buttons on GPH devices */ + +bool OSystem_GP2X::handleJoyButtonDown(SDL_Event &ev, Common::Event &event) { + + _stickBtn[ev.jbutton.button] = 1; + event.kbd.flags = 0; + + switch (ev.jbutton.button) { + case BUTTON_UP: + case BUTTON_UPLEFT: + case BUTTON_LEFT: + case BUTTON_DOWNLEFT: + case BUTTON_DOWN: + case BUTTON_DOWNRIGHT: + case BUTTON_RIGHT: + case BUTTON_UPRIGHT: + moveStick(); + event.type = Common::EVENT_MOUSEMOVE; + fillMouseEvent(event, _km.x, _km.y); + break; + case BUTTON_B: + case BUTTON_CLICK: + if (BUTTON_STATE_L == true) { + setZoomOnMouse(); + fillMouseEvent(event, _km.x, _km.y); + } else { + event.type = Common::EVENT_LBUTTONDOWN; + fillMouseEvent(event, _km.x, _km.y); + } + break; + case BUTTON_X: + event.type = Common::EVENT_RBUTTONDOWN; + fillMouseEvent(event, _km.x, _km.y); + break; + case BUTTON_L: + BUTTON_STATE_L = true; + break; + case BUTTON_R: + event.type = Common::EVENT_KEYDOWN; + if (BUTTON_STATE_L == true) { +#ifdef ENABLE_VKEYBD + event.kbd.keycode = Common::KEYCODE_F7; + event.kbd.ascii = mapKey(SDLK_F7, ev.key.keysym.mod, 0); +#else + event.kbd.keycode = Common::KEYCODE_0; + event.kbd.ascii = mapKey(SDLK_0, ev.key.keysym.mod, 0); +#endif + } else { + event.kbd.keycode = Common::KEYCODE_RETURN; + event.kbd.ascii = mapKey(SDLK_RETURN, ev.key.keysym.mod, 0); + } + break; + case BUTTON_SELECT: + case BUTTON_HOME: + event.type = Common::EVENT_KEYDOWN; + if (BUTTON_STATE_L == true) { + event.type = Common::EVENT_QUIT; + } else { + event.kbd.keycode = Common::KEYCODE_ESCAPE; + event.kbd.ascii = mapKey(SDLK_ESCAPE, ev.key.keysym.mod, 0); + } + break; + case BUTTON_A: + event.type = Common::EVENT_KEYDOWN; + if (BUTTON_STATE_L == true) { + event.type = Common::EVENT_PREDICTIVE_DIALOG; + } else { + event.kbd.keycode = Common::KEYCODE_PERIOD; + event.kbd.ascii = mapKey(SDLK_PERIOD, ev.key.keysym.mod, 0); + } + break; + case BUTTON_Y: + event.type = Common::EVENT_KEYDOWN; + if (BUTTON_STATE_L == true) { + GPH::ToggleTapMode(); + if (GPH::tapmodeLevel == TAPMODE_LEFT) { + displayMessageOnOSD("Touchscreen 'Tap Mode' - Left Click"); + } else if (GPH::tapmodeLevel == TAPMODE_RIGHT) { + displayMessageOnOSD("Touchscreen 'Tap Mode' - Right Click"); + } else if (GPH::tapmodeLevel == TAPMODE_HOVER) { + displayMessageOnOSD("Touchscreen 'Tap Mode' - Hover (No Click)"); + } + } else { + event.kbd.keycode = Common::KEYCODE_SPACE; + event.kbd.ascii = mapKey(SDLK_SPACE, ev.key.keysym.mod, 0); + } + break; + case BUTTON_MENU: + case BUTTON_HELP: + event.type = Common::EVENT_KEYDOWN; + if (BUTTON_STATE_L == true) { + event.type = Common::EVENT_MAINMENU; + } else { + event.kbd.keycode = Common::KEYCODE_F5; + event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0); + } + break; + case BUTTON_VOLUP: + GP2X_HW::mixerMoveVolume(2); + if (GP2X_HW::volumeLevel == 100) { + displayMessageOnOSD("Maximum Volume"); + } else { + displayMessageOnOSD("Increasing Volume"); + } + break; + + case BUTTON_VOLDOWN: + GP2X_HW::mixerMoveVolume(1); + if (GP2X_HW::volumeLevel == 0) { + displayMessageOnOSD("Minimal Volume"); + } else { + displayMessageOnOSD("Decreasing Volume"); + } + break; + case BUTTON_HOLD: + event.type = Common::EVENT_QUIT; + break; + case BUTTON_HELP2: + GPH::ToggleTapMode(); + if (GPH::tapmodeLevel == TAPMODE_LEFT) { + displayMessageOnOSD("Touchscreen 'Tap Mode': Left Click"); + } else if (GPH::tapmodeLevel == TAPMODE_RIGHT) { + displayMessageOnOSD("Touchscreen 'Tap Mode': Right Click"); + } else if (GPH::tapmodeLevel == TAPMODE_HOVER) { + displayMessageOnOSD("Touchscreen 'Tap Mode': Hover (No Click)"); + } + break; + } + return true; +} + +bool OSystem_GP2X::handleJoyButtonUp(SDL_Event &ev, Common::Event &event) { + _stickBtn[ev.jbutton.button] = 0; + event.kbd.flags = 0; + + switch (ev.jbutton.button) { + case BUTTON_UP: + case BUTTON_UPLEFT: + case BUTTON_LEFT: + case BUTTON_DOWNLEFT: + case BUTTON_DOWN: + case BUTTON_DOWNRIGHT: + case BUTTON_RIGHT: + case BUTTON_UPRIGHT: + moveStick(); + event.type = Common::EVENT_MOUSEMOVE; + fillMouseEvent(event, _km.x, _km.y); + break; + case BUTTON_B: + case BUTTON_CLICK: + if (BUTTON_STATE_L == true) { + break; + } else { + event.type = Common::EVENT_LBUTTONUP; + fillMouseEvent(event, _km.x, _km.y); + } + break; + case BUTTON_X: + event.type = Common::EVENT_RBUTTONUP; + fillMouseEvent(event, _km.x, _km.y); + break; + case BUTTON_L: + BUTTON_STATE_L = false; + break; + case BUTTON_SELECT: + case BUTTON_HOME: + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = Common::KEYCODE_ESCAPE; + event.kbd.ascii = mapKey(SDLK_ESCAPE, ev.key.keysym.mod, 0); + break; + case BUTTON_A: + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = Common::KEYCODE_PERIOD; + event.kbd.ascii = mapKey(SDLK_PERIOD, ev.key.keysym.mod, 0); + break; + case BUTTON_Y: + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = Common::KEYCODE_SPACE; + event.kbd.ascii = mapKey(SDLK_SPACE, ev.key.keysym.mod, 0); + break; + case BUTTON_MENU: + case BUTTON_HELP: + event.type = Common::EVENT_KEYUP; + if (BUTTON_STATE_L == true) { + event.type = Common::EVENT_MAINMENU; + } else { + event.kbd.keycode = Common::KEYCODE_F5; + event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0); + } + break; + case BUTTON_R: + event.type = Common::EVENT_KEYUP; + if (BUTTON_STATE_L == true) { +#ifdef ENABLE_VKEYBD + event.kbd.keycode = Common::KEYCODE_F7; + event.kbd.ascii = mapKey(SDLK_F7, ev.key.keysym.mod, 0); +#else + event.kbd.keycode = Common::KEYCODE_0; + event.kbd.ascii = mapKey(SDLK_0, ev.key.keysym.mod, 0); +#endif + } else { + event.kbd.keycode = Common::KEYCODE_RETURN; + event.kbd.ascii = mapKey(SDLK_RETURN, ev.key.keysym.mod, 0); + } + break; + case BUTTON_VOLUP: + break; + case BUTTON_VOLDOWN: + break; + case BUTTON_HOLD: + break; + case BUTTON_HELP2: + break; + } +return true; +} + +bool OSystem_GP2X::handleJoyAxisMotion(SDL_Event &ev, Common::Event &event) { + int axis = ev.jaxis.value; + if ( axis > JOY_DEADZONE) { + axis -= JOY_DEADZONE; + event.type = Common::EVENT_MOUSEMOVE; + } else if ( axis < -JOY_DEADZONE ) { + axis += JOY_DEADZONE; + event.type = Common::EVENT_MOUSEMOVE; + } else + axis = 0; + + if ( ev.jaxis.axis == JOY_XAXIS) { +#ifdef JOY_ANALOG + _km.x_vel = axis/2000; + _km.x_down_count = 0; +#else + if (axis != 0) { + _km.x_vel = (axis > 0) ? 1:-1; + _km.x_down_count = 1; + } else { + _km.x_vel = 0; + _km.x_down_count = 0; + } +#endif + + } else if (ev.jaxis.axis == JOY_YAXIS) { +#ifndef JOY_INVERT_Y + axis = -axis; +#endif +#ifdef JOY_ANALOG + _km.y_vel = -axis / 2000; + _km.y_down_count = 0; +#else + if (axis != 0) { + _km.y_vel = (-axis > 0) ? 1: -1; + _km.y_down_count = 1; + } else { + _km.y_vel = 0; + _km.y_down_count = 0; + } +#endif + } + + fillMouseEvent(event, _km.x, _km.y); + + return true; +} + + +bool OSystem_GP2X::remapKey(SDL_Event &ev, Common::Event &event) { + return false; +} diff --git a/backends/platform/gp2x/gp2x-common.h b/backends/platform/gp2x/gp2x-common.h index 4d2a9c33cc..1c8708a8b1 100644 --- a/backends/platform/gp2x/gp2x-common.h +++ b/backends/platform/gp2x/gp2x-common.h @@ -23,23 +23,384 @@ * */ -#ifndef PLATFORM_SDL_GP2X_H -#define PLATFORM_SDL_GP2X_H +#ifndef GP2X_COMMON_H +#define GP2X_COMMON_H -#include "backends/platform/sdl/posix/posix.h" +#include <SDL.h> +#include <SDL_gp2x.h> + +#include "backends/base-backend.h" +#include "graphics/scaler.h" + +#define __GP2X__ +#define USE_OSD +#define MIXER_DOUBLE_BUFFERING 1 + +namespace Audio { + class MixerImpl; +} + +enum { + GFX_NORMAL = 0 +}; -#ifndef PATH_MAX - #define PATH_MAX 255 -#endif -class OSystem_GP2X : public OSystem_POSIX { +class OSystem_GP2X : public BaseBackend { public: + OSystem_GP2X(); + virtual ~OSystem_GP2X(); + virtual void initBackend(); - virtual void quit(); + + void beginGFXTransaction(void); + TransactionError endGFXTransaction(void); + + // Set the size of the video bitmap. + // Typically, 320x200 + void initSize(uint w, uint h, const Graphics::PixelFormat *format); + + int getScreenChangeID() const { return _screenChangeCount; } + + // Set colors of the palette + void setPalette(const byte *colors, uint start, uint num); + + // Get colors of the palette + void grabPalette(byte *colors, uint start, uint num); + + // Draw a bitmap to screen. + // The screen will not be updated to reflect the new bitmap + void copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h); + + virtual Graphics::Surface *lockScreen(); + virtual void unlockScreen(); + + // Update the dirty areas of the screen + void updateScreen(); + + // Either show or hide the mouse cursor + bool showMouse(bool visible); + + // Warp the mouse cursor. Where set_mouse_pos() only informs the + // backend of the mouse cursor's current position, this function + // actually moves the cursor to the specified position. + void warpMouse(int x, int y); + + // Set the bitmap that's used when drawing the cursor. + void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format); + + // Set colors of cursor palette + void setCursorPalette(const byte *colors, uint start, uint num); + + // Disables or enables cursor palette + void disableCursorPalette(bool disable) { + _cursorPaletteDisabled = disable; + blitCursor(); + } + + // Shaking is used in SCUMM. Set current shake position. + void setShakePos(int shake_pos); + + // Get the number of milliseconds since the program was started. + uint32 getMillis(); + + // Delay for a specified amount of milliseconds + void delayMillis(uint msecs); + + // Get the next event. + // Returns true if an event was retrieved. + virtual bool pollEvent(Common::Event &event); // overloaded by CE backend + + // Sets up the keymapper with the backends hardware key set + void setupKeymapper(); + +protected: + virtual bool dispatchSDLEvent(SDL_Event &ev, Common::Event &event); + + // Handlers for specific SDL events, called by pollEvent. + // This way, if a backend inherits fromt the SDL backend, it can + // change the behavior of only a single event, without having to override all + // of pollEvent. + virtual bool handleKeyDown(SDL_Event &ev, Common::Event &event); + virtual bool handleKeyUp(SDL_Event &ev, Common::Event &event); + virtual bool handleMouseMotion(SDL_Event &ev, Common::Event &event); + virtual bool handleMouseButtonDown(SDL_Event &ev, Common::Event &event); + virtual bool handleMouseButtonUp(SDL_Event &ev, Common::Event &event); + virtual bool handleJoyButtonDown(SDL_Event &ev, Common::Event &event); + virtual bool handleJoyButtonUp(SDL_Event &ev, Common::Event &event); + virtual bool handleJoyAxisMotion(SDL_Event &ev, Common::Event &event); + +public: + + // Set function that generates samples + void setupMixer(); + static void mixCallback(void *s, byte *samples, int len); + + void closeMixer(); + + virtual Audio::Mixer *getMixer(); + + // Quit + void quit(); + + void getTimeAndDate(TimeDate &t) const; + virtual Common::TimerManager *getTimerManager(); + + // Mutex handling + MutexRef createMutex(); + void lockMutex(MutexRef mutex); + void unlockMutex(MutexRef mutex); + void deleteMutex(MutexRef mutex); + + // Overlay + Graphics::PixelFormat getOverlayFormat() const { return _overlayFormat; } + void showOverlay(); + void hideOverlay(); + void clearOverlay(); + void grabOverlay(OverlayColor *buf, int pitch); + void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h); + int16 getHeight(); + int16 getWidth(); + int16 getOverlayHeight() { return _videoMode.overlayHeight; } + int16 getOverlayWidth() { return _videoMode.overlayWidth; } + + const GraphicsMode *getSupportedGraphicsModes() const; + int getDefaultGraphicsMode() const; + bool setGraphicsMode(int mode); + int getGraphicsMode() const; + + bool hasFeature(Feature f); + void setFeatureState(Feature f, bool enable); + bool getFeatureState(Feature f); + void preprocessEvents(SDL_Event *event) {} + + void displayMessageOnOSD(const char *msg); + + virtual Common::SaveFileManager *getSavefileManager(); + virtual FilesystemFactory *getFilesystemFactory(); virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0); + virtual Common::SeekableReadStream *createConfigReadStream(); + virtual Common::WriteStream *createConfigWriteStream(); + protected: - virtual void initSDL(); -}; + bool _inited; + + SDL_Surface *_osdSurface; + Uint8 _osdAlpha; // Transparency level of the OSD + uint32 _osdFadeStartTime; // When to start the fade out + enum { + kOSDFadeOutDelay = 2 * 1000, // Delay before the OSD is faded out (in milliseconds) + kOSDFadeOutDuration = 500, // Duration of the OSD fade out (in milliseconds) + kOSDColorKey = 1, + kOSDInitialAlpha = 80 // Initial alpha level, in percent + }; + + // hardware screen + SDL_Surface *_hwscreen; + + // unseen game screen + SDL_Surface *_screen; + + // temporary screen (for scalers) + SDL_Surface *_tmpscreen; + SDL_Surface *_tmpscreen2; + // overlay + SDL_Surface *_overlayscreen; + bool _overlayVisible; + Graphics::PixelFormat _overlayFormat; + + enum { + kTransactionNone = 0, + kTransactionActive = 1, + kTransactionRollback = 2 + }; + + struct TransactionDetails { + bool sizeChanged; + bool needHotswap; + bool needUpdatescreen; + bool normal1xScaler; + }; + TransactionDetails _transactionDetails; + + struct VideoState { + bool setup; + + bool fullscreen; + bool aspectRatioCorrection; + + int mode; + int scaleFactor; + + int screenWidth, screenHeight; + int overlayWidth, overlayHeight; + }; + VideoState _videoMode, _oldVideoMode; + + virtual void setGraphicsModeIntern(); // overloaded by CE backend + + /** Force full redraw on next updateScreen */ + bool _forceFull; + ScalerProc *_scalerProc; + int _scalerType; + int _transactionMode; + + bool _screenIsLocked; + Graphics::Surface _framebuffer; + + /** Current video mode flags (see DF_* constants) */ + bool _modeChanged; + int _screenChangeCount; + + /* True if zoom on mouse is enabled. (only set by > 240 high games) */ + bool _adjustZoomOnMouse; + + enum { + NUM_DIRTY_RECT = 100, + MAX_MOUSE_W = 80, + MAX_MOUSE_H = 80, + MAX_SCALING = 3 + }; + + // Dirty rect management + SDL_Rect _dirtyRectList[NUM_DIRTY_RECT]; + int _numDirtyRects; + + // Keyboard mouse emulation. Disabled by fingolfin 2004-12-18. + // I am keeping the rest of the code in for now, since the joystick + // code (or rather, "hack") uses it, too. + struct KbdMouse { + int16 x, y, x_vel, y_vel, x_max, y_max, x_down_count, y_down_count; + uint32 last_time, delay_time, x_down_time, y_down_time; + }; + + struct MousePos { + // The mouse position, using either virtual (game) or real + // (overlay) coordinates. + int16 x, y; + + // The size and hotspot of the original cursor image. + int16 w, h; + int16 hotX, hotY; + + // The size and hotspot of the pre-scaled cursor image, in real + // coordinates. + int16 rW, rH; + int16 rHotX, rHotY; + + // The size and hotspot of the pre-scaled cursor image, in game + // coordinates. + int16 vW, vH; + int16 vHotX, vHotY; + + MousePos() : x(0), y(0), w(0), h(0), hotX(0), hotY(0), + rW(0), rH(0), rHotX(0), rHotY(0), vW(0), vH(0), + vHotX(0), vHotY(0) + { } + }; + + // mouse + KbdMouse _km; + bool _mouseVisible; + bool _mouseNeedsRedraw; + byte *_mouseData; + SDL_Rect _mouseBackup; + MousePos _mouseCurState; + byte _mouseKeyColor; + int _cursorTargetScale; + bool _cursorPaletteDisabled; + SDL_Surface *_mouseOrigSurface; + SDL_Surface *_mouseSurface; + enum { + kMouseColorKey = 1 + }; + + // Scroll lock state - since SDL doesn't track it + bool _scrollLock; + + // joystick + SDL_Joystick *_joystick; + bool _stickBtn[32]; + + // Shake mode + int _currentShakePos; + int _newShakePos; + + // Palette data + SDL_Color *_currentPalette; + uint _paletteDirtyStart, _paletteDirtyEnd; + + // Cursor palette data + SDL_Color *_cursorPalette; + + /** + * Mutex which prevents multiple threads from interfering with each other + * when accessing the screen. + */ + MutexRef _graphicsMutex; + +#ifdef MIXER_DOUBLE_BUFFERING + SDL_mutex *_soundMutex; + SDL_cond *_soundCond; + SDL_Thread *_soundThread; + bool _soundThreadIsRunning; + bool _soundThreadShouldQuit; + + byte _activeSoundBuf; + uint _soundBufSize; + byte *_soundBuffers[2]; + + void mixerProducerThread(); + static int SDLCALL mixerProducerThreadEntry(void *arg); + void initThreadedMixer(Audio::MixerImpl *mixer, uint bufSize); + void deinitThreadedMixer(); #endif + + FilesystemFactory *_fsFactory; + Common::SaveFileManager *_savefile; + Audio::MixerImpl *_mixer; + + SDL_TimerID _timerID; + Common::TimerManager *_timer; + +protected: + virtual void addDirtyRect(int x, int y, int w, int h, bool realCoordinates = false); + + void drawMouse(); + void undrawMouse(); + void blitCursor(); + + /** Set the position of the virtual mouse cursor. */ + void setMousePos(int x, int y); + void fillMouseEvent(Common::Event &event, int x, int y); + void toggleMouseGrab(); + + void internUpdateScreen(); + + bool loadGFXMode(); + void unloadGFXMode(); + bool hotswapGFXMode(); + + void setFullscreenMode(bool enable); + void setAspectRatioCorrection(bool enable); + + void setZoomOnMouse(); // GP2X: On > 240 high games zooms on the mouse + radius. + + bool saveScreenshot(const char *filename); + + int effectiveScreenHeight() const; + + void setupIcon(); + void handleKbdMouse(); + + virtual bool remapKey(SDL_Event &ev, Common::Event &event); + + bool handleScalerHotkeys(const SDL_KeyboardEvent &key); + bool isScalerHotkey(const Common::Event &event); + + void moveStick(); + int _gp2xInputType; +}; + +#endif // GP2X_COMMON_H diff --git a/backends/platform/gp2x/gp2x-hw.cpp b/backends/platform/gp2x/gp2x-hw.cpp index 75e4ca6471..8818ff9fe9 100644 --- a/backends/platform/gp2x/gp2x-hw.cpp +++ b/backends/platform/gp2x/gp2x-hw.cpp @@ -30,6 +30,9 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + #include "gp2x-common.h" #include "gp2x-hw.h" @@ -48,6 +51,10 @@ #include <sys/time.h> #include <unistd.h> +extern "C" { +static unsigned long gp2x_dev[8]={0,0,0,0,0,0,0,0};//, gp2x_ticks_per_second; +} + namespace GP2X_HW { enum { diff --git a/backends/platform/gp2x/gp2x-main.cpp b/backends/platform/gp2x/gp2x-main.cpp deleted file mode 100644 index 8dc5be764b..0000000000 --- a/backends/platform/gp2x/gp2x-main.cpp +++ /dev/null @@ -1,50 +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$ - * - */ - -#include "backends/platform/gp2x/gp2x-sdl.h" -#include "backends/plugins/posix/posix-provider.h" -#include "base/main.h" - -int main(int argc, char *argv[]) { - - // Create our OSystem instance - g_system = new OSystem_GP2X(); - assert(g_system); - - // Pre initialize the backend - ((OSystem_GP2X *)g_system)->init(); - -#ifdef DYNAMIC_MODULES - PluginManager::instance().addPluginProvider(new POSIXPluginProvider()); -#endif - - // Invoke the actual ScummVM main entry point: - int res = scummvm_main(argc, argv); - - // Free OSystem - delete (OSystem_GP2X *)g_system; - - return res; -} diff --git a/backends/platform/gp2x/gp2x-mem.cpp b/backends/platform/gp2x/gp2x-mem.cpp index 97a34ffb6a..0968087cfd 100644 --- a/backends/platform/gp2x/gp2x-mem.cpp +++ b/backends/platform/gp2x/gp2x-mem.cpp @@ -28,6 +28,9 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + #include <stdio.h> #include <signal.h> #include <setjmp.h> @@ -39,8 +42,11 @@ #include "backends/platform/gp2x/gp2x-mem.h" -void SetClock (unsigned c) -{ +extern "C" { +static volatile unsigned short *gp2x_memregs; +} + +void SetClock (unsigned c) { unsigned v; unsigned mdiv,pdiv=3,scale=0; @@ -54,8 +60,7 @@ void SetClock (unsigned c) gp2x_memregs[0x910>>1] = v; } -void patchMMU (void) -{ +void patchMMU (void) { //volatile unsigned int *secbuf = (unsigned int *)malloc (204800); printf ("Reconfiguring cached memory regions...\n"); @@ -68,19 +73,15 @@ void patchMMU (void) int mmufd = open("/dev/mmuhack", O_RDWR); - if(mmufd < 0) - { + if(mmufd < 0) { printf ("Upper memory uncached (attempt failed, access to upper memory will be slower)...\n"); - } - else - { + } else { printf ("Upper memory cached...\n"); close(mmufd); } } -void unpatchMMU (void) -{ +void unpatchMMU (void) { printf ("Restoreing cached memory regions...\n"); system("/sbin/rmmod mmuhack"); } diff --git a/backends/platform/gp2x/gp2x-mem.h b/backends/platform/gp2x/gp2x-mem.h index 24b2a3f569..aa49444164 100644 --- a/backends/platform/gp2x/gp2x-mem.h +++ b/backends/platform/gp2x/gp2x-mem.h @@ -47,9 +47,6 @@ extern void unpatchMMU (void); #define SYS_CLK_FREQ 7372800 -static unsigned long gp2x_dev[8]={0,0,0,0,0,0,0,0};//, gp2x_ticks_per_second; -static volatile unsigned short *gp2x_ram, *gp2x_memregs; - #ifdef __cplusplus } #endif diff --git a/backends/platform/gp2x/gp2x.cpp b/backends/platform/gp2x/gp2x.cpp index c297a45833..0811380be9 100644 --- a/backends/platform/gp2x/gp2x.cpp +++ b/backends/platform/gp2x/gp2x.cpp @@ -23,19 +23,32 @@ * */ +/* + * GP2X: Main backend. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + #include "backends/platform/gp2x/gp2x-common.h" #include "backends/platform/gp2x/gp2x-hw.h" #include "backends/platform/gp2x/gp2x-mem.h" - -#include "backends/graphics/gp2xsdl/gp2xsdl-graphics.h" -#include "backends/events/gp2xsdl/gp2xsdl-events.h" -#include "backends/saves/default/default-saves.h" - +#include "common/archive.h" #include "common/config-manager.h" #include "common/debug.h" +#include "common/EventRecorder.h" +#include "common/events.h" +#include "common/util.h" -// Disable for normal serial logging. -#define DUMP_STDOUT +#include "common/file.h" +#include "base/main.h" + +#include "backends/saves/default/default-saves.h" + +#include "backends/timer/default/default-timer.h" +#include "backends/plugins/posix/posix-provider.h" +#include "sound/mixer_intern.h" #include <stdio.h> #include <stdlib.h> @@ -43,14 +56,69 @@ #include <limits.h> #include <errno.h> #include <sys/stat.h> +#include <time.h> // for getTimeAndDate() + +// Disable for normal serial logging. +#define DUMP_STDOUT + +#define SAMPLES_PER_SEC 11025 +//#define SAMPLES_PER_SEC 22050 +//#define SAMPLES_PER_SEC 44100 + +#define DEFAULT_CONFIG_FILE ".scummvmrc" + +#include "backends/fs/posix/posix-fs-factory.h" + +static Uint32 timer_handler(Uint32 interval, void *param) { + ((DefaultTimerManager *)param)->handler(); + return interval; +} + +int main(int argc, char *argv[]) { + g_system = new OSystem_GP2X(); + assert(g_system); + +#ifdef DYNAMIC_MODULES + PluginManager::instance().addPluginProvider(new POSIXPluginProvider()); +#endif + + // Invoke the actual ScummVM main entry point: + int res = scummvm_main(argc, argv); + g_system->quit(); + return res; +} + +OSystem *OSystem_GP2X_create() { + return new OSystem_GP2X(); +} void OSystem_GP2X::initBackend() { + assert(!_inited); + + ConfMan.setInt("joystick_num", 0); + int joystick_num = ConfMan.getInt("joystick_num"); + uint32 sdlFlags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_EVENTTHREAD; + + if (ConfMan.hasKey("disable_sdl_parachute")) + sdlFlags |= SDL_INIT_NOPARACHUTE; + + if (joystick_num > -1) + sdlFlags |= SDL_INIT_JOYSTICK; + + if (SDL_Init(sdlFlags) == -1) { + error("Could not initialize SDL: %s", SDL_GetError()); + } + // Setup default save path to be workingdir/saves - char savePath[PATH_MAX + 1]; - char workDirName[PATH_MAX + 1]; + #ifndef PATH_MAX + #define PATH_MAX 255 + #endif + + char savePath[PATH_MAX+1]; + char workDirName[PATH_MAX+1]; if (getcwd(workDirName, PATH_MAX) == NULL) { - error("Could not obtain current working directory"); + error("Could not obtain current working directory."); } else { printf("Current working directory: %s\n", workDirName); } @@ -69,8 +137,8 @@ void OSystem_GP2X::initBackend() { #ifdef DUMP_STDOUT // The GP2X has a serial console but most users do not use this so we // output all our STDOUT and STDERR to files for debug purposes. - char STDOUT_FILE[PATH_MAX + 1]; - char STDERR_FILE[PATH_MAX + 1]; + char STDOUT_FILE[PATH_MAX+1]; + char STDERR_FILE[PATH_MAX+1]; strcpy(STDOUT_FILE, workDirName); strcpy(STDERR_FILE, workDirName); @@ -110,7 +178,12 @@ void OSystem_GP2X::initBackend() { printf("%s\n", "Debug: STDOUT and STDERR redirected to text files."); #endif /* DUMP_STDOUT */ + _graphicsMutex = createMutex(); + + SDL_ShowCursor(SDL_DISABLE); + // Setup other defaults. + ConfMan.registerDefault("aspect_ratio", true); /* Up default volume values as we use a seperate system level volume anyway. */ @@ -119,50 +192,146 @@ void OSystem_GP2X::initBackend() { ConfMan.registerDefault("speech_volume", 192); ConfMan.registerDefault("autosave_period", 3 * 60); // Trigger autosave every 3 minutes - On low batts 4 mins is about your warning time. + memset(&_oldVideoMode, 0, sizeof(_oldVideoMode)); + memset(&_videoMode, 0, sizeof(_videoMode)); + memset(&_transactionDetails, 0, sizeof(_transactionDetails)); + + _videoMode.mode = GFX_NORMAL; + _videoMode.scaleFactor = 1; + _scalerProc = Normal1x; + _videoMode.aspectRatioCorrection = ConfMan.getBool("aspect_ratio"); + _scalerType = 0; + _adjustZoomOnMouse = false; ConfMan.setBool("FM_low_quality", true); + // enable joystick + if (joystick_num > -1 && SDL_NumJoysticks() > 0) { + _joystick = SDL_JoystickOpen(joystick_num); + } + + _savefile = new DefaultSaveFileManager(); + // Create and hook up the mixer, if none exists yet (we check for this to + // allow subclasses to provide their own). + if (_mixer == 0) { + setupMixer(); + } + + // Create and hook up the timer manager, if none exists yet (we check for + // this to allow subclasses to provide their own). + if (_timer == 0) { + // Note: We could implement a custom SDLTimerManager by using + // SDL_AddTimer. That might yield better timer resolution, but it would + // also change the semantics of a timer: Right now, ScummVM timers + // *never* run in parallel, due to the way they are implemented. If we + // switched to SDL_AddTimer, each timer might run in a separate thread. + // However, not all our code is prepared for that, so we can't just + // switch. Still, it's a potential future change to keep in mind. + _timer = new DefaultTimerManager(); + _timerID = SDL_AddTimer(10, &timer_handler, _timer); + } + /* Initialise any GP2X specific stuff we may want (Batt Status, scaler etc.) */ GP2X_HW::deviceInit(); /* Set Default hardware mixer volume to a preset level (VOLUME_INITIAL). This is done to 'reset' volume level if set by other apps. */ GP2X_HW::mixerMoveVolume(0); - // Create the events manager - if (_eventManager == 0) - _eventManager = new GP2XSdlEventManager(this); + OSystem::initBackend(); - // Create the graphics manager - if (_graphicsManager == 0) - _graphicsManager = new GP2XSdlGraphicsManager(); + _inited = true; +} - // Call parent implementation of this method - OSystem_POSIX::initBackend(); +OSystem_GP2X::OSystem_GP2X() + : + _osdSurface(0), _osdAlpha(SDL_ALPHA_TRANSPARENT), _osdFadeStartTime(0), + _hwscreen(0), _screen(0), _tmpscreen(0), + _overlayVisible(false), + _overlayscreen(0), _tmpscreen2(0), + _scalerProc(0), _modeChanged(false), _screenChangeCount(0), + _mouseVisible(false), _mouseNeedsRedraw(false), _mouseData(0), _mouseSurface(0), + _mouseOrigSurface(0), _cursorTargetScale(1), _cursorPaletteDisabled(true), + _joystick(0), + _currentShakePos(0), _newShakePos(0), + _paletteDirtyStart(0), _paletteDirtyEnd(0), +#ifdef MIXER_DOUBLE_BUFFERING + _soundMutex(0), _soundCond(0), _soundThread(0), + _soundThreadIsRunning(false), _soundThreadShouldQuit(false), +#endif + _fsFactory(0), + _savefile(0), + _mixer(0), + _timer(0), + _screenIsLocked(false), + _graphicsMutex(0), _transactionMode(kTransactionNone) { + + // allocate palette storage + _currentPalette = (SDL_Color *)calloc(sizeof(SDL_Color), 256); + _cursorPalette = (SDL_Color *)calloc(sizeof(SDL_Color), 256); + + _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0; + + // reset mouse state + memset(&_km, 0, sizeof(_km)); + memset(&_mouseCurState, 0, sizeof(_mouseCurState)); + + _inited = false; + _fsFactory = new POSIXFilesystemFactory(); } -void OSystem_GP2X::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; +OSystem_GP2X::~OSystem_GP2X() { + SDL_RemoveTimer(_timerID); + closeMixer(); - // Initialize SDL (SDL Subsystems are initiliazed in the corresponding sdl managers) - if (SDL_Init(sdlFlags) == -1) - error("Could not initialize SDL: %s", SDL_GetError()); + free(_currentPalette); + free(_cursorPalette); + free(_mouseData); - // Enable unicode support if possible - SDL_EnableUNICODE(1); + delete _savefile; + delete _timer; +} - _initedSDL = true; - } +uint32 OSystem_GP2X::getMillis() { + uint32 millis = SDL_GetTicks(); + g_eventRec.processMillis(millis); + return millis; +} + +void OSystem_GP2X::delayMillis(uint msecs) { + SDL_Delay(msecs); +} + +void OSystem_GP2X::getTimeAndDate(TimeDate &td) const { + time_t curTime = time(0); + struct tm t = *localtime(&curTime); + td.tm_sec = t.tm_sec; + td.tm_min = t.tm_min; + td.tm_hour = t.tm_hour; + td.tm_mday = t.tm_mday; + td.tm_mon = t.tm_mon; + td.tm_year = t.tm_year; +} + +Common::TimerManager *OSystem_GP2X::getTimerManager() { + assert(_timer); + return _timer; +} + +Common::SaveFileManager *OSystem_GP2X::getSavefileManager() { + assert(_savefile); + return _savefile; +} + +FilesystemFactory *OSystem_GP2X::getFilesystemFactory() { + assert(_fsFactory); + return _fsFactory; } void OSystem_GP2X::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { /* Setup default extra data paths for engine data files and plugins */ - char workDirName[PATH_MAX + 1]; + char workDirName[PATH_MAX+1]; if (getcwd(workDirName, PATH_MAX) == NULL) { - error("Error: Could not obtain current working directory"); + error("Error: Could not obtain current working directory."); } Common::FSNode workdirNode(workDirName); @@ -191,14 +360,283 @@ void OSystem_GP2X::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) } } +static Common::String getDefaultConfigFileName() { + char configFile[MAXPATHLEN]; + strcpy(configFile, DEFAULT_CONFIG_FILE); + return configFile; +} + +Common::SeekableReadStream *OSystem_GP2X::createConfigReadStream() { + Common::FSNode file(getDefaultConfigFileName()); + return file.createReadStream(); +} + +Common::WriteStream *OSystem_GP2X::createConfigWriteStream() { + Common::FSNode file(getDefaultConfigFileName()); + return file.createWriteStream(); +} + +bool OSystem_GP2X::hasFeature(Feature f) { + return + (f == kFeatureFullscreenMode) || + (f == kFeatureAspectRatioCorrection) || + (f == kFeatureCursorHasPalette); +} + +void OSystem_GP2X::setFeatureState(Feature f, bool enable) { + switch (f) { + case kFeatureFullscreenMode: + return; + case kFeatureAspectRatioCorrection: + setAspectRatioCorrection(enable); + break; + case kFeatureDisableKeyFiltering: + // TODO: Extend as more support for this is added to engines. + return; + default: + break; + } +} + +bool OSystem_GP2X::getFeatureState(Feature f) { + assert (_transactionMode == kTransactionNone); + + switch (f) { + case kFeatureFullscreenMode: + return false; + case kFeatureAspectRatioCorrection: + return _videoMode.aspectRatioCorrection; + default: + return false; + } +} + void OSystem_GP2X::quit() { + unloadGFXMode(); + deleteMutex(_graphicsMutex); + + if (_joystick) + SDL_JoystickClose(_joystick); GP2X_HW::deviceDeinit(); + SDL_RemoveTimer(_timerID); + closeMixer(); + + free(_currentPalette); + free(_cursorPalette); + free(_mouseData); + + delete _timer; + SDL_ShowCursor(SDL_ENABLE); + SDL_Quit(); + + delete getEventManager(); + delete _savefile; + #ifdef DUMP_STDOUT printf("%s\n", "Debug: STDOUT and STDERR text files closed."); fclose(stdout); fclose(stderr); #endif /* DUMP_STDOUT */ - OSystem_POSIX::quit(); + exit(0); +} + +OSystem::MutexRef OSystem_GP2X::createMutex(void) { + return (MutexRef) SDL_CreateMutex(); +} + +void OSystem_GP2X::lockMutex(MutexRef mutex) { + SDL_mutexP((SDL_mutex *) mutex); +} + +void OSystem_GP2X::unlockMutex(MutexRef mutex) { + SDL_mutexV((SDL_mutex *) mutex); +} + +void OSystem_GP2X::deleteMutex(MutexRef mutex) { + SDL_DestroyMutex((SDL_mutex *) mutex); +} + +#pragma mark - +#pragma mark --- Audio --- +#pragma mark - + +#ifdef MIXER_DOUBLE_BUFFERING + +void OSystem_GP2X::mixerProducerThread() { + byte nextSoundBuffer; + + SDL_LockMutex(_soundMutex); + while (true) { + // Wait till we are allowed to produce data + SDL_CondWait(_soundCond, _soundMutex); + + if (_soundThreadShouldQuit) + break; + + // Generate samples and put them into the next buffer + nextSoundBuffer = _activeSoundBuf ^ 1; + _mixer->mixCallback(_soundBuffers[nextSoundBuffer], _soundBufSize); + + // Swap buffers + _activeSoundBuf = nextSoundBuffer; + } + SDL_UnlockMutex(_soundMutex); +} + +int SDLCALL OSystem_GP2X::mixerProducerThreadEntry(void *arg) { + OSystem_GP2X *this_ = (OSystem_GP2X *)arg; + assert(this_); + this_->mixerProducerThread(); + return 0; +} + + +void OSystem_GP2X::initThreadedMixer(Audio::MixerImpl *mixer, uint bufSize) { + _soundThreadIsRunning = false; + _soundThreadShouldQuit = false; + + // Create mutex and condition variable + _soundMutex = SDL_CreateMutex(); + _soundCond = SDL_CreateCond(); + + // Create two sound buffers + _activeSoundBuf = 0; + _soundBufSize = bufSize; + _soundBuffers[0] = (byte *)calloc(1, bufSize); + _soundBuffers[1] = (byte *)calloc(1, bufSize); + + _soundThreadIsRunning = true; + + // Finally start the thread + _soundThread = SDL_CreateThread(mixerProducerThreadEntry, this); +} + +void OSystem_GP2X::deinitThreadedMixer() { + // Kill thread?? _soundThread + + if (_soundThreadIsRunning) { + // Signal the producer thread to end, and wait for it to actually finish. + _soundThreadShouldQuit = true; + SDL_CondBroadcast(_soundCond); + SDL_WaitThread(_soundThread, NULL); + + // Kill the mutex & cond variables. + // Attention: AT this point, the mixer callback must not be running + // anymore, else we will crash! + SDL_DestroyMutex(_soundMutex); + SDL_DestroyCond(_soundCond); + + _soundThreadIsRunning = false; + + free(_soundBuffers[0]); + free(_soundBuffers[1]); + } +} + + +void OSystem_GP2X::mixCallback(void *arg, byte *samples, int len) { + OSystem_GP2X *this_ = (OSystem_GP2X *)arg; + assert(this_); + assert(this_->_mixer); + + assert((int)this_->_soundBufSize == len); + + // Lock mutex, to ensure our data is not overwritten by the producer thread + SDL_LockMutex(this_->_soundMutex); + + // Copy data from the current sound buffer + memcpy(samples, this_->_soundBuffers[this_->_activeSoundBuf], len); + + // Unlock mutex and wake up the produced thread + SDL_UnlockMutex(this_->_soundMutex); + SDL_CondSignal(this_->_soundCond); +} + +#else + +void OSystem_GP2X::mixCallback(void *sys, byte *samples, int len) { + OSystem_GP2X *this_ = (OSystem_GP2X *)sys; + assert(this_); + assert(this_->_mixer); + + this_->_mixer->mixCallback(samples, len); +} + +#endif + +void OSystem_GP2X::setupMixer() { + SDL_AudioSpec desired; + SDL_AudioSpec obtained; + + // Determine the desired output sampling frequency. + uint32 samplesPerSec = 0; + if (ConfMan.hasKey("output_rate")) + samplesPerSec = ConfMan.getInt("output_rate"); + if (samplesPerSec <= 0) + samplesPerSec = SAMPLES_PER_SEC; + + // Determine the sample buffer size. We want it to store enough data for + // at least 1/16th of a second (though at most 8192 samples). Note + // that it must be a power of two. So e.g. at 22050 Hz, we request a + // sample buffer size of 2048. + uint32 samples = 8192; + while (samples * 16 > samplesPerSec * 2) + samples >>= 1; + + memset(&desired, 0, sizeof(desired)); + desired.freq = samplesPerSec; + desired.format = AUDIO_S16SYS; + desired.channels = 2; + //desired.samples = (uint16)samples; + desired.samples = 128; // Samples hack + desired.callback = mixCallback; + desired.userdata = this; + + assert(!_mixer); + if (SDL_OpenAudio(&desired, &obtained) != 0) { + warning("Could not open audio device: %s", SDL_GetError()); + _mixer = new Audio::MixerImpl(this, samplesPerSec); + assert(_mixer); + _mixer->setReady(false); + } else { + // Note: This should be the obtained output rate, but it seems that at + // least on some platforms SDL will lie and claim it did get the rate + // even if it didn't. Probably only happens for "weird" rates, though. + samplesPerSec = obtained.freq; + debug(1, "Output sample rate: %d Hz", samplesPerSec); + + // Create the mixer instance and start the sound processing + _mixer = new Audio::MixerImpl(this, samplesPerSec); + assert(_mixer); + _mixer->setReady(true); + +#ifdef MIXER_DOUBLE_BUFFERING + initThreadedMixer(_mixer, obtained.samples * 4); +#endif + + // start the sound system + SDL_PauseAudio(0); + } +} + +void OSystem_GP2X::closeMixer() { + if (_mixer) + _mixer->setReady(false); + + SDL_CloseAudio(); + + delete _mixer; + _mixer = 0; + +#ifdef MIXER_DOUBLE_BUFFERING + deinitThreadedMixer(); +#endif + +} + +Audio::Mixer *OSystem_GP2X::getMixer() { + assert(_mixer); + return _mixer; } diff --git a/backends/platform/gp2x/graphics.cpp b/backends/platform/gp2x/graphics.cpp new file mode 100644 index 0000000000..d776db218e --- /dev/null +++ b/backends/platform/gp2x/graphics.cpp @@ -0,0 +1,1701 @@ +/* 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$ + * + */ + +/* + * GP2X: Graphics handling. + * + */ + +#include "backends/platform/gp2x/gp2x-common.h" +#include "common/util.h" +#include "common/mutex.h" +#include "common/str-array.h" +#include "graphics/font.h" +#include "graphics/fontman.h" +#include "graphics/scaler.h" +#include "graphics/scaler/aspect.h" +#include "graphics/surface.h" + +static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { + {"Fullscreen", "1x", GFX_NORMAL}, + {0, 0, 0} +}; + +// Table of relative scalers magnitudes +// [definedScale - 1][_scaleFactor - 1] +static ScalerProc *scalersMagn[3][3] = { + { Normal1x, Normal1x, Normal1x }, + { Normal1x, Normal1x, Normal1x }, + { Normal1x, Normal1x, Normal1x } +}; + +static const int s_gfxModeSwitchTable[][4] = { + { GFX_NORMAL } + }; + +static int cursorStretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY); + +const OSystem::GraphicsMode *OSystem_GP2X::getSupportedGraphicsModes() const { + return s_supportedGraphicsModes; +} + +int OSystem_GP2X::getDefaultGraphicsMode() const { + return GFX_NORMAL; +} + +void OSystem_GP2X::beginGFXTransaction(void) { + assert(_transactionMode == kTransactionNone); + + _transactionMode = kTransactionActive; + + _transactionDetails.sizeChanged = false; + + _transactionDetails.needHotswap = false; + _transactionDetails.needUpdatescreen = false; + + _transactionDetails.normal1xScaler = false; + + _oldVideoMode = _videoMode; +} + +OSystem::TransactionError OSystem_GP2X::endGFXTransaction(void) { + int errors = kTransactionSuccess; + + assert(_transactionMode != kTransactionNone); + + if (_transactionMode == kTransactionRollback) { + if (_videoMode.fullscreen != _oldVideoMode.fullscreen) { + errors |= kTransactionFullscreenFailed; + + _videoMode.fullscreen = _oldVideoMode.fullscreen; + } else if (_videoMode.aspectRatioCorrection != _oldVideoMode.aspectRatioCorrection) { + errors |= kTransactionAspectRatioFailed; + + _videoMode.aspectRatioCorrection = _oldVideoMode.aspectRatioCorrection; + } else if (_videoMode.mode != _oldVideoMode.mode) { + errors |= kTransactionModeSwitchFailed; + + _videoMode.mode = _oldVideoMode.mode; + _videoMode.scaleFactor = _oldVideoMode.scaleFactor; + } else if (_videoMode.screenWidth != _oldVideoMode.screenWidth || _videoMode.screenHeight != _oldVideoMode.screenHeight) { + errors |= kTransactionSizeChangeFailed; + + _videoMode.screenWidth = _oldVideoMode.screenWidth; + _videoMode.screenHeight = _oldVideoMode.screenHeight; + _videoMode.overlayWidth = _oldVideoMode.overlayWidth; + _videoMode.overlayHeight = _oldVideoMode.overlayHeight; + } + + if (_videoMode.fullscreen == _oldVideoMode.fullscreen && + _videoMode.aspectRatioCorrection == _oldVideoMode.aspectRatioCorrection && + _videoMode.mode == _oldVideoMode.mode && + _videoMode.screenWidth == _oldVideoMode.screenWidth && + _videoMode.screenHeight == _oldVideoMode.screenHeight) { + + // Our new video mode would now be exactly the same as the + // old one. Since we still can not assume SDL_SetVideoMode + // to be working fine, we need to invalidate the old video + // mode, so loadGFXMode would error out properly. + _oldVideoMode.setup = false; + } + } + + if (_transactionDetails.sizeChanged) { + unloadGFXMode(); + if (!loadGFXMode()) { + if (_oldVideoMode.setup) { + _transactionMode = kTransactionRollback; + errors |= endGFXTransaction(); + } + } else { + setGraphicsModeIntern(); + clearOverlay(); + + _videoMode.setup = true; + _modeChanged = true; + // OSystem_SDL::pollEvent used to update the screen change count, + // but actually it gives problems when a video mode was changed + // but OSystem_SDL::pollEvent was not called. This for example + // caused a crash under certain circumstances when doing an RTL. + // To fix this issue we update the screen change count right here. + _screenChangeCount++; + } + } else if (_transactionDetails.needHotswap) { + setGraphicsModeIntern(); + if (!hotswapGFXMode()) { + if (_oldVideoMode.setup) { + _transactionMode = kTransactionRollback; + errors |= endGFXTransaction(); + } + } else { + _videoMode.setup = true; + _modeChanged = true; + // OSystem_SDL::pollEvent used to update the screen change count, + // but actually it gives problems when a video mode was changed + // but OSystem_SDL::pollEvent was not called. This for example + // caused a crash under certain circumstances when doing an RTL. + // To fix this issue we update the screen change count right here. + _screenChangeCount++; + + if (_transactionDetails.needUpdatescreen) + internUpdateScreen(); + } + } else if (_transactionDetails.needUpdatescreen) { + setGraphicsModeIntern(); + internUpdateScreen(); + } + + _transactionMode = kTransactionNone; + return (TransactionError)errors; +} + +bool OSystem_GP2X::setGraphicsMode(int mode) { + Common::StackLock lock(_graphicsMutex); + + assert(_transactionMode == kTransactionActive); + + if (_oldVideoMode.setup && _oldVideoMode.mode == mode) + return true; + + int newScaleFactor = 1; + + switch (mode) { + case GFX_NORMAL: + newScaleFactor = 1; + break; + default: + warning("unknown gfx mode %d", mode); + return false; + } + + _transactionDetails.normal1xScaler = (mode == GFX_NORMAL); + if (_oldVideoMode.setup && _oldVideoMode.scaleFactor != newScaleFactor) + _transactionDetails.needHotswap = true; + + _transactionDetails.needUpdatescreen = true; + + _videoMode.mode = mode; + _videoMode.scaleFactor = newScaleFactor; + + return true; +} + +void OSystem_GP2X::setGraphicsModeIntern() { + Common::StackLock lock(_graphicsMutex); + ScalerProc *newScalerProc = 0; + + switch (_videoMode.mode) { + case GFX_NORMAL: + newScalerProc = Normal1x; + break; + + default: + error("Unknown gfx mode %d", _videoMode.mode); + } + + _scalerProc = newScalerProc; + + if (_videoMode.mode != GFX_NORMAL) { + for (int i = 0; i < ARRAYSIZE(s_gfxModeSwitchTable); i++) { + if (s_gfxModeSwitchTable[i][1] == _videoMode.mode || s_gfxModeSwitchTable[i][2] == _videoMode.mode) { + _scalerType = i; + break; + } + } + } + + if (!_screen || !_hwscreen) + return; + + // Blit everything to the screen + _forceFull = true; + + // Even if the old and new scale factors are the same, we may have a + // different scaler for the cursor now. + blitCursor(); +} + +int OSystem_GP2X::getGraphicsMode() const { + assert (_transactionMode == kTransactionNone); + return _videoMode.mode; +} + +void OSystem_GP2X::initSize(uint w, uint h, const Graphics::PixelFormat *format) { + assert(_transactionMode == kTransactionActive); + +#ifdef USE_RGB_COLOR + //avoid redundant format changes + Graphics::PixelFormat newFormat; + if (!format) + newFormat = Graphics::PixelFormat::createFormatCLUT8(); + else + newFormat = *format; + + assert(newFormat.bytesPerPixel > 0); + + if (newFormat != _videoMode.format) + { + _videoMode.format = newFormat; + _transactionDetails.formatChanged = true; + _screenFormat = newFormat; + } +#endif + + // Avoid redundant res changes + if ((int)w == _videoMode.screenWidth && (int)h == _videoMode.screenHeight) + return; + + _videoMode.screenWidth = w; + _videoMode.screenHeight = h; + + _transactionDetails.sizeChanged = true; +} + +int OSystem_GP2X::effectiveScreenHeight() const { + return (_videoMode.aspectRatioCorrection ? real2Aspect(_videoMode.screenHeight) : _videoMode.screenHeight) + * _videoMode.scaleFactor; +} + + +bool OSystem_GP2X::loadGFXMode() { + assert(_inited); + _forceFull = true; + + int hwW, hwH; + + _videoMode.overlayWidth = _videoMode.screenWidth * _videoMode.scaleFactor; + _videoMode.overlayHeight = _videoMode.screenHeight * _videoMode.scaleFactor; + + if (_videoMode.screenHeight != 200 && _videoMode.screenHeight != 400) + _videoMode.aspectRatioCorrection = false; + + if (_videoMode.aspectRatioCorrection) + _videoMode.overlayHeight = real2Aspect(_videoMode.overlayHeight); + + hwW = _videoMode.screenWidth * _videoMode.scaleFactor; + + if (_videoMode.screenHeight == 200) { + hwH = 240; + } else if (_videoMode.screenHeight == 400) { + hwH = 480; + } else { + hwH = _videoMode.screenHeight; + } + + printf ("Game Screen Height: %d\n", hwH); + + // + // Create the surface that contains the game data + // + + _screen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth, hwH, 8, 0, 0, 0, 0); + if (_screen == NULL) + error("allocating _screen failed"); + + // + // Create the surface that contains the scaled graphics in 16 bit mode + // + + _hwscreen = SDL_SetVideoMode(hwW, hwH, 16, SDL_SWSURFACE | SDL_NOFRAME | SDL_FULLSCREEN); + if (_hwscreen == NULL) { + // DON'T use error(), as this tries to bring up the debug + // console, which WON'T WORK now that _hwscreen is hosed. + + if (!_oldVideoMode.setup) { + warning("SDL_SetVideoMode says we can't switch to that mode (%s)", SDL_GetError()); + quit(); + } else { + return false; + } + } + + // GP2X Specific, must be called after any SDL_SetVideoMode to ensure the hardware cursor is off. + // Note: On the GP2X SDL_SetVideoMode recalls SDL_Init(). + SDL_ShowCursor(SDL_DISABLE); + + // + // Create the surface used for the graphics in 16 bit before scaling, and also the overlay + // + + // 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("allocating _tmpscreen failed"); + + _overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth, _videoMode.overlayHeight, + 16, + _hwscreen->format->Rmask, + _hwscreen->format->Gmask, + _hwscreen->format->Bmask, + _hwscreen->format->Amask); + + if (_overlayscreen == NULL) + error("allocating _overlayscreen failed"); + + _overlayFormat.bytesPerPixel = _overlayscreen->format->BytesPerPixel; + + _overlayFormat.rLoss = _overlayscreen->format->Rloss; + _overlayFormat.gLoss = _overlayscreen->format->Gloss; + _overlayFormat.bLoss = _overlayscreen->format->Bloss; + _overlayFormat.aLoss = _overlayscreen->format->Aloss; + + _overlayFormat.rShift = _overlayscreen->format->Rshift; + _overlayFormat.gShift = _overlayscreen->format->Gshift; + _overlayFormat.bShift = _overlayscreen->format->Bshift; + _overlayFormat.aShift = _overlayscreen->format->Ashift; + + _tmpscreen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth + 3, _videoMode.overlayHeight + 3, + 16, + _hwscreen->format->Rmask, + _hwscreen->format->Gmask, + _hwscreen->format->Bmask, + _hwscreen->format->Amask); + + if (_tmpscreen2 == NULL) + error("allocating _tmpscreen2 failed"); + + _osdSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, + _hwscreen->w, + _hwscreen->h, + 16, + _hwscreen->format->Rmask, + _hwscreen->format->Gmask, + _hwscreen->format->Bmask, + _hwscreen->format->Amask); + if (_osdSurface == NULL) + error("allocating _osdSurface failed"); + SDL_SetColorKey(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kOSDColorKey); + + // keyboard cursor control, some other better place for it? + _km.x_max = _videoMode.screenWidth * _videoMode.scaleFactor - 1; + _km.y_max = effectiveScreenHeight() - 1; + _km.delay_time = 25; + _km.last_time = 0; + + // Distinguish 555 and 565 mode + if (_hwscreen->format->Rmask == 0x7C00) + InitScalers(555); + else + InitScalers(565); + + return true; +} + +void OSystem_GP2X::unloadGFXMode() { + if (_screen) { + SDL_FreeSurface(_screen); + _screen = NULL; + } + + if (_hwscreen) { + SDL_FreeSurface(_hwscreen); + _hwscreen = NULL; + } + + if (_tmpscreen) { + SDL_FreeSurface(_tmpscreen); + _tmpscreen = NULL; + } + + if (_tmpscreen2) { + SDL_FreeSurface(_tmpscreen2); + _tmpscreen2 = NULL; + } + + if (_overlayscreen) { + SDL_FreeSurface(_overlayscreen); + _overlayscreen = NULL; + } + + if (_osdSurface) { + SDL_FreeSurface(_osdSurface); + _osdSurface = NULL; + } + DestroyScalers(); +} + +bool OSystem_GP2X::hotswapGFXMode() { + if (!_screen) + return false; + + // Keep around the old _screen & _overlayscreen so we can restore the screen data + // after the mode switch. + SDL_Surface *old_screen = _screen; + SDL_Surface *old_overlayscreen = _overlayscreen; + _screen = NULL; + _overlayscreen = NULL; + + // Release the HW screen surface + SDL_FreeSurface(_hwscreen); _hwscreen = NULL; + + SDL_FreeSurface(_tmpscreen); _tmpscreen = NULL; + SDL_FreeSurface(_tmpscreen2); _tmpscreen2 = NULL; + + // Release the OSD surface + SDL_FreeSurface(_osdSurface); _osdSurface = NULL; + + // 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_overlayscreen, NULL, _overlayscreen, NULL); + + // Free the old surfaces + SDL_FreeSurface(old_screen); + SDL_FreeSurface(old_overlayscreen); + + // Update cursor to new scale + blitCursor(); + + // Blit everything to the screen + internUpdateScreen(); + + return true; +} + +void OSystem_GP2X::updateScreen() { + assert (_transactionMode == kTransactionNone); + + Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends + + internUpdateScreen(); +} + +void OSystem_GP2X::internUpdateScreen() { + SDL_Surface *srcSurf, *origSurf; + int height, width; + ScalerProc *scalerProc; + int scale1; + +#if defined (DEBUG) && ! defined(_WIN32_WCE) // definitions not available for non-DEBUG here. (needed this to compile in SYMBIAN32 & linux?) + assert(_hwscreen != NULL); + assert(_hwscreen->map->sw_data != NULL); +#endif + + // If the shake position changed, fill the dirty area with blackness + if (_currentShakePos != _newShakePos) { + SDL_Rect blackrect = {0, 0, _videoMode.screenWidth * _videoMode.scaleFactor, _newShakePos * _videoMode.scaleFactor}; + + if (_videoMode.aspectRatioCorrection && !_overlayVisible) + blackrect.h = real2Aspect(blackrect.h - 1) + 1; + + SDL_FillRect(_hwscreen, &blackrect, 0); + + _currentShakePos = _newShakePos; + + _forceFull = true; + } + + // Check whether the palette was changed in the meantime and update the + // screen surface accordingly. + if (_screen && _paletteDirtyEnd != 0) { + SDL_SetColors(_screen, _currentPalette + _paletteDirtyStart, + _paletteDirtyStart, + _paletteDirtyEnd - _paletteDirtyStart); + + _paletteDirtyEnd = 0; + + _forceFull = true; + } + // OSD visible (i.e. non-transparent)? + if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + // Updated alpha value + const int diff = SDL_GetTicks() - _osdFadeStartTime; + if (diff > 0) { + if (diff >= kOSDFadeOutDuration) { + // Back to full transparency + _osdAlpha = SDL_ALPHA_TRANSPARENT; + } else { + // Do a linear fade out... + const int startAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100; + _osdAlpha = startAlpha + diff * (SDL_ALPHA_TRANSPARENT - startAlpha) / kOSDFadeOutDuration; + } + SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha); + _forceFull = true; + } + } + + if (!_overlayVisible) { + origSurf = _screen; + srcSurf = _tmpscreen; + width = _videoMode.screenWidth; + height = _videoMode.screenHeight; + scalerProc = _scalerProc; + scale1 = _videoMode.scaleFactor; + } else { + origSurf = _overlayscreen; + srcSurf = _tmpscreen2; + width = _videoMode.overlayWidth; + height = _videoMode.overlayHeight; + scalerProc = Normal1x; + + scale1 = 1; + } + + // Add the area covered by the mouse cursor to the list of dirty rects if + // we have to redraw the mouse. + if (_mouseNeedsRedraw) + undrawMouse(); + + // Force a full redraw if requested + if (_forceFull) { + _numDirtyRects = 1; + _dirtyRectList[0].x = 0; + _dirtyRectList[0].y = 0; + _dirtyRectList[0].w = width; + _dirtyRectList[0].h = height; + } + + // Only draw anything if necessary + if (_numDirtyRects > 0 || _mouseNeedsRedraw) { + SDL_Rect *r; + SDL_Rect dst; + uint32 srcPitch, dstPitch; + SDL_Rect *lastRect = _dirtyRectList + _numDirtyRects; + + for (r = _dirtyRectList; r != lastRect; ++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. + + 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; r != lastRect; ++r) { + register int dst_y = r->y + _currentShakePos; + register int dst_h = 0; + register int orig_dst_y = 0; + register int rx1 = r->x * scale1; + + if (dst_y < height) { + dst_h = r->h; + if (dst_h > height - dst_y) + dst_h = height - dst_y; + + orig_dst_y = dst_y; + dst_y = dst_y * scale1; + + if (_videoMode.aspectRatioCorrection && !_overlayVisible) + dst_y = real2Aspect(dst_y); + + assert(scalerProc != NULL); + scalerProc((byte *)srcSurf->pixels + (r->x * 2 + 2) + (r->y + 1) * srcPitch, srcPitch, + (byte *)_hwscreen->pixels + rx1 * 2 + dst_y * dstPitch, dstPitch, r->w, dst_h); + } + + r->x = rx1; + r->y = dst_y; + r->w = r->w * scale1; + r->h = dst_h * scale1; + + if (_videoMode.aspectRatioCorrection && orig_dst_y < height && !_overlayVisible) + r->h = stretch200To240((uint8 *) _hwscreen->pixels, dstPitch, r->w, r->h, r->x, r->y, orig_dst_y * scale1); + } + SDL_UnlockSurface(srcSurf); + SDL_UnlockSurface(_hwscreen); + + // Readjust the dirty rect list in case we are doing a full update. + // This is necessary if shaking is active. + if (_forceFull) { + _dirtyRectList[0].y = 0; + _dirtyRectList[0].h = effectiveScreenHeight(); + } + + drawMouse(); + + if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + SDL_BlitSurface(_osdSurface, 0, _hwscreen, 0); + } + + // Finally, blit all our changes to the screen + SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList); + } + + _numDirtyRects = 0; + _forceFull = false; + _mouseNeedsRedraw = false; +} + +bool OSystem_GP2X::saveScreenshot(const char *filename) { + assert(_hwscreen != NULL); + + Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends + return SDL_SaveBMP(_hwscreen, filename) == 0; +} + +void OSystem_GP2X::setFullscreenMode(bool enable) { + Common::StackLock lock(_graphicsMutex); + + if (_oldVideoMode.setup && _oldVideoMode.fullscreen == enable) + return; + + if (_transactionMode == kTransactionActive) { + _videoMode.fullscreen = enable; + _transactionDetails.needHotswap = true; + } +} + +void OSystem_GP2X::setAspectRatioCorrection(bool enable) { + Common::StackLock lock(_graphicsMutex); + + if (_oldVideoMode.setup && _oldVideoMode.aspectRatioCorrection == enable) + return; + + if (_transactionMode == kTransactionActive) { + _videoMode.aspectRatioCorrection = enable; + _transactionDetails.needHotswap = true; + } +} + +void OSystem_GP2X::setZoomOnMouse() { + if (_adjustZoomOnMouse == true) { + _adjustZoomOnMouse = false; + return; + } else { + _adjustZoomOnMouse = true; + return; + } +} + +void OSystem_GP2X::copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h) { + assert (_transactionMode == kTransactionNone); + assert(src); + + if (_screen == NULL) { + warning("OSystem_GP2X::copyRectToScreen: _screen == NULL"); + return; + } + + Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends + + assert(x >= 0 && x < _videoMode.screenWidth); + assert(y >= 0 && y < _videoMode.screenHeight); + assert(h > 0 && y + h <= _videoMode.screenHeight); + assert(w > 0 && x + w <= _videoMode.screenWidth); + + /* 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); + + // 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); +} + +Graphics::Surface *OSystem_GP2X::lockScreen() { + assert (_transactionMode == kTransactionNone); + + // Lock the graphics mutex + lockMutex(_graphicsMutex); + + // paranoia check + assert(!_screenIsLocked); + _screenIsLocked = true; + + // Try to lock the screen surface + if (SDL_LockSurface(_screen) == -1) + error("SDL_LockSurface failed: %s", SDL_GetError()); + + _framebuffer.pixels = _screen->pixels; + _framebuffer.w = _screen->w; + _framebuffer.h = _screen->h; + _framebuffer.pitch = _screen->pitch; + _framebuffer.bytesPerPixel = 1; + + return &_framebuffer; +} + +void OSystem_GP2X::unlockScreen() { + assert (_transactionMode == kTransactionNone); + + // paranoia check + assert(_screenIsLocked); + _screenIsLocked = false; + + // Unlock the screen surface + SDL_UnlockSurface(_screen); + + // Trigger a full screen update + _forceFull = true; + + // Finally unlock the graphics mutex + unlockMutex(_graphicsMutex); +} + +void OSystem_GP2X::addDirtyRect(int x, int y, int w, int h, bool realCoordinates) { + if (_forceFull) + return; + + if (_numDirtyRects == NUM_DIRTY_RECT) { + _forceFull = true; + return; + } + + int height, width; + + if (!_overlayVisible && !realCoordinates) { + width = _videoMode.screenWidth; + height = _videoMode.screenHeight; + } else { + width = _videoMode.overlayWidth; + height = _videoMode.overlayHeight; + } + + // Extend the dirty region by 1 pixel for scalers + // that "smear" the screen, e.g. 2xSAI + if (!realCoordinates) { + x--; + y--; + w+=2; + h+=2; + } + + // clip + if (x < 0) { + w += x; + x = 0; + } + + if (y < 0) { + h += y; + y=0; + } + + if (w > width - x) { + w = width - x; + } + + if (h > height - y) { + h = height - y; + } + + if (_videoMode.aspectRatioCorrection && !_overlayVisible && !realCoordinates) { + makeRectStretchable(x, y, w, h); + } + + if (w == width && h == height) { + _forceFull = true; + return; + } + + if (w > 0 && h > 0) { + SDL_Rect *r = &_dirtyRectList[_numDirtyRects++]; + + r->x = x; + r->y = y; + r->w = w; + r->h = h; + } +} + +int16 OSystem_GP2X::getHeight() { + return _videoMode.screenHeight; +} + +int16 OSystem_GP2X::getWidth() { + return _videoMode.screenWidth; +} + +void OSystem_GP2X::setPalette(const byte *colors, uint start, uint num) { + assert(colors); + + // Setting the palette before _screen is created is allowed - for now - + // since we don't actually set the palette until the screen is updated. + // But it could indicate a programming error, so let's warn about it. + + if (!_screen) + warning("OSystem_SDL::setPalette: _screen == NULL"); + + const byte *b = colors; + uint i; + SDL_Color *base = _currentPalette + start; + for (i = 0; i < num; i++) { + base[i].r = b[0]; + base[i].g = b[1]; + base[i].b = b[2]; + b += 4; + } + + if (start < _paletteDirtyStart) + _paletteDirtyStart = start; + + if (start + num > _paletteDirtyEnd) + _paletteDirtyEnd = start + num; + + // Some games blink cursors with palette + if (_cursorPaletteDisabled) + blitCursor(); +} + +void OSystem_GP2X::grabPalette(byte *colors, uint start, uint num) { + assert(colors); + const SDL_Color *base = _currentPalette + start; + + for (uint i = 0; i < num; ++i) { + colors[i * 4] = base[i].r; + colors[i * 4 + 1] = base[i].g; + colors[i * 4 + 2] = base[i].b; + colors[i * 4 + 3] = 0xFF; + } +} + +void OSystem_GP2X::setCursorPalette(const byte *colors, uint start, uint num) { + assert(colors); + const byte *b = colors; + uint i; + SDL_Color *base = _cursorPalette + start; + for (i = 0; i < num; i++) { + base[i].r = b[0]; + base[i].g = b[1]; + base[i].b = b[2]; + b += 4; + } + + _cursorPaletteDisabled = false; + + blitCursor(); +} + +void OSystem_GP2X::setShakePos(int shake_pos) { + assert (_transactionMode == kTransactionNone); + + _newShakePos = shake_pos; +} + +#pragma mark - +#pragma mark --- Overlays --- +#pragma mark - + +void OSystem_GP2X::showOverlay() { + assert (_transactionMode == kTransactionNone); + + int x, y; + + if (_overlayVisible) + return; + + _overlayVisible = true; + + // Since resolution could change, put mouse to adjusted position + // Fixes bug #1349059 + x = _mouseCurState.x * _videoMode.scaleFactor; + if (_videoMode.aspectRatioCorrection) + y = real2Aspect(_mouseCurState.y) * _videoMode.scaleFactor; + else + y = _mouseCurState.y * _videoMode.scaleFactor; + + warpMouse(x, y); + + clearOverlay(); +} + +void OSystem_GP2X::hideOverlay() { + assert (_transactionMode == kTransactionNone); + + if (!_overlayVisible) + return; + + int x, y; + + _overlayVisible = false; + + // Since resolution could change, put mouse to adjusted position + // Fixes bug #1349059 + x = _mouseCurState.x / _videoMode.scaleFactor; + y = _mouseCurState.y / _videoMode.scaleFactor; + if (_videoMode.aspectRatioCorrection) + y = aspect2Real(y); + + warpMouse(x, y); + + clearOverlay(); + + _forceFull = true; +} + +void OSystem_GP2X::clearOverlay() { + //assert (_transactionMode == kTransactionNone); + + Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends + + if (!_overlayVisible) + return; + + // Clear the overlay by making the game screen "look through" everywhere. + SDL_Rect src, dst; + src.x = src.y = 0; + dst.x = dst.y = 1; + src.w = dst.w = _videoMode.screenWidth; + src.h = dst.h = _videoMode.screenHeight; + if (SDL_BlitSurface(_screen, &src, _tmpscreen, &dst) != 0) + error("SDL_BlitSurface failed: %s", SDL_GetError()); + + SDL_LockSurface(_tmpscreen); + SDL_LockSurface(_overlayscreen); + _scalerProc((byte *)(_tmpscreen->pixels) + _tmpscreen->pitch + 2, _tmpscreen->pitch, + (byte *)_overlayscreen->pixels, _overlayscreen->pitch, _videoMode.screenWidth, _videoMode.screenHeight); + +#ifdef USE_SCALERS + if (_videoMode.aspectRatioCorrection) + stretch200To240((uint8 *)_overlayscreen->pixels, _overlayscreen->pitch, + _videoMode.overlayWidth, _videoMode.screenHeight * _videoMode.scaleFactor, 0, 0, 0); +#endif + SDL_UnlockSurface(_tmpscreen); + SDL_UnlockSurface(_overlayscreen); + + _forceFull = true; +} + +void OSystem_GP2X::grabOverlay(OverlayColor *buf, int pitch) { + assert (_transactionMode == kTransactionNone); + + if (_overlayscreen == NULL) + return; + + if (SDL_LockSurface(_overlayscreen) == -1) + error("SDL_LockSurface failed: %s", SDL_GetError()); + + byte *src = (byte *)_overlayscreen->pixels; + int h = _videoMode.overlayHeight; + do { + memcpy(buf, src, _videoMode.overlayWidth * 2); + src += _overlayscreen->pitch; + buf += pitch; + } while (--h); + + SDL_UnlockSurface(_overlayscreen); +} + +void OSystem_GP2X::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); + + 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); +} + + +#pragma mark - +#pragma mark --- Mouse --- +#pragma mark - + +bool OSystem_GP2X::showMouse(bool visible) { + if (_mouseVisible == visible) + return visible; + + bool last = _mouseVisible; + _mouseVisible = visible; + _mouseNeedsRedraw = true; + + return last; +} + +void OSystem_GP2X::setMousePos(int x, int y) { + if (x != _mouseCurState.x || y != _mouseCurState.y) { + _mouseNeedsRedraw = true; + _mouseCurState.x = x; + _mouseCurState.y = y; + } +} + +void OSystem_GP2X::warpMouse(int x, int y) { + int y1 = y; + + if (_videoMode.aspectRatioCorrection && !_overlayVisible) + y1 = real2Aspect(y); + + if (_mouseCurState.x != x || _mouseCurState.y != y) { + if (!_overlayVisible) + SDL_WarpMouse(x * _videoMode.scaleFactor, y1 * _videoMode.scaleFactor); + else + SDL_WarpMouse(x, y1); + + // SDL_WarpMouse() generates a mouse movement event, so + // setMousePos() 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_GP2X::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) { +#ifdef USE_RGB_COLOR + if (!format) + _cursorFormat = Graphics::PixelFormat::createFormatCLUT8(); + else if (format->bytesPerPixel <= _screenFormat.bytesPerPixel) + _cursorFormat = *format; + keycolor &= (1 << (_cursorFormat.bytesPerPixel << 3)) - 1; +#else + keycolor &= 0xFF; +#endif + + if (w == 0 || h == 0) + return; + + _mouseCurState.hotX = hotspot_x; + _mouseCurState.hotY = hotspot_y; + + _mouseKeyColor = keycolor; + + _cursorTargetScale = cursorTargetScale; + + if (_mouseCurState.w != (int)w || _mouseCurState.h != (int)h) { + _mouseCurState.w = w; + _mouseCurState.h = h; + + if (_mouseOrigSurface) + SDL_FreeSurface(_mouseOrigSurface); + + // Allocate bigger surface because AdvMame2x adds black pixel at [0,0] + _mouseOrigSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, + _mouseCurState.w + 2, + _mouseCurState.h + 2, + 16, + _hwscreen->format->Rmask, + _hwscreen->format->Gmask, + _hwscreen->format->Bmask, + _hwscreen->format->Amask); + + if (_mouseOrigSurface == NULL) + error("allocating _mouseOrigSurface failed"); + SDL_SetColorKey(_mouseOrigSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kMouseColorKey); + } + + free(_mouseData); +#ifdef USE_RGB_COLOR + _mouseData = (byte *)malloc(w * h * _cursorFormat.bytesPerPixel); + memcpy(_mouseData, buf, w * h * _cursorFormat.bytesPerPixel); +#else + _mouseData = (byte *)malloc(w * h); + memcpy(_mouseData, buf, w * h); +#endif + + blitCursor(); +} + +void OSystem_GP2X::blitCursor() { + byte *dstPtr; + const byte *srcPtr = _mouseData; +#ifdef USE_RGB_COLOR + uint32 color; + uint32 colormask = (1 << (_cursorFormat.bytesPerPixel << 3)) - 1; +#else + byte color; +#endif + int w, h, i, j; + + if (!_mouseOrigSurface || !_mouseData) + return; + + _mouseNeedsRedraw = true; + + w = _mouseCurState.w; + h = _mouseCurState.h; + + SDL_LockSurface(_mouseOrigSurface); + + // Make whole surface transparent + for (i = 0; i < h + 2; i++) { + dstPtr = (byte *)_mouseOrigSurface->pixels + _mouseOrigSurface->pitch * i; + for (j = 0; j < w + 2; j++) { + *(uint16 *)dstPtr = kMouseColorKey; + dstPtr += 2; + } + } + + // Draw from [1,1] since AdvMame2x adds artefact at 0,0 + dstPtr = (byte *)_mouseOrigSurface->pixels + _mouseOrigSurface->pitch + 2; + + SDL_Color *palette; + + if (_cursorPaletteDisabled) + palette = _currentPalette; + else + palette = _cursorPalette; + + for (i = 0; i < h; i++) { + for (j = 0; j < w; j++) { +#ifdef USE_RGB_COLOR + if (_cursorFormat.bytesPerPixel > 1) { + color = (*(uint32 *) srcPtr) & colormask; + if (color != _mouseKeyColor) { // transparent, don't draw + uint8 r,g,b; + _cursorFormat.colorToRGB(color,r,g,b); + *(uint16 *)dstPtr = SDL_MapRGB(_mouseOrigSurface->format, + r, g, b); + } + dstPtr += 2; + srcPtr += _cursorFormat.bytesPerPixel; + } else { +#endif + color = *srcPtr; + if (color != _mouseKeyColor) { // transparent, don't draw + *(uint16 *)dstPtr = SDL_MapRGB(_mouseOrigSurface->format, + palette[color].r, palette[color].g, palette[color].b); + } + dstPtr += 2; + srcPtr++; +#ifdef USE_RGB_COLOR + } +#endif + } + dstPtr += _mouseOrigSurface->pitch - w * 2; + } + + int rW, rH; + + if (_cursorTargetScale >= _videoMode.scaleFactor) { + // The cursor target scale is greater or equal to the scale at + // which the rest of the screen is drawn. We do not downscale + // the cursor image, we draw it at its original size. It will + // appear too large on screen. + + rW = w; + rH = h; + _mouseCurState.rHotX = _mouseCurState.hotX; + _mouseCurState.rHotY = _mouseCurState.hotY; + + // The virtual dimensions may be larger than the original. + + _mouseCurState.vW = w * _cursorTargetScale / _videoMode.scaleFactor; + _mouseCurState.vH = h * _cursorTargetScale / _videoMode.scaleFactor; + _mouseCurState.vHotX = _mouseCurState.hotX * _cursorTargetScale / + _videoMode.scaleFactor; + _mouseCurState.vHotY = _mouseCurState.hotY * _cursorTargetScale / + _videoMode.scaleFactor; + } else { + // The cursor target scale is smaller than the scale at which + // the rest of the screen is drawn. We scale up the cursor + // image to make it appear correct. + + rW = w * _videoMode.scaleFactor / _cursorTargetScale; + rH = h * _videoMode.scaleFactor / _cursorTargetScale; + _mouseCurState.rHotX = _mouseCurState.hotX * _videoMode.scaleFactor / + _cursorTargetScale; + _mouseCurState.rHotY = _mouseCurState.hotY * _videoMode.scaleFactor / + _cursorTargetScale; + + // The virtual dimensions will be the same as the original. + + _mouseCurState.vW = w; + _mouseCurState.vH = h; + _mouseCurState.vHotX = _mouseCurState.hotX; + _mouseCurState.vHotY = _mouseCurState.hotY; + } + + int rH1 = rH; // store original to pass to aspect-correction function later + + if (_videoMode.aspectRatioCorrection && _cursorTargetScale == 1) { + rH = real2Aspect(rH - 1) + 1; + _mouseCurState.rHotY = real2Aspect(_mouseCurState.rHotY); + } + + if (_mouseCurState.rW != rW || _mouseCurState.rH != rH) { + _mouseCurState.rW = rW; + _mouseCurState.rH = rH; + + if (_mouseSurface) + SDL_FreeSurface(_mouseSurface); + + _mouseSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, + _mouseCurState.rW, + _mouseCurState.rH, + 16, + _hwscreen->format->Rmask, + _hwscreen->format->Gmask, + _hwscreen->format->Bmask, + _hwscreen->format->Amask); + + if (_mouseSurface == NULL) + error("allocating _mouseSurface failed"); + + SDL_SetColorKey(_mouseSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kMouseColorKey); + } + + SDL_LockSurface(_mouseSurface); + + ScalerProc *scalerProc; + + if (_cursorTargetScale == 1 && _videoMode.screenWidth > 320) { + scalerProc = scalersMagn[_cursorTargetScale + 1][_videoMode.scaleFactor + 1]; + } else { + scalerProc = scalersMagn[_cursorTargetScale - 1][_videoMode.scaleFactor - 1]; + } + + scalerProc((byte *)_mouseOrigSurface->pixels + _mouseOrigSurface->pitch + 2, + _mouseOrigSurface->pitch, (byte *)_mouseSurface->pixels, _mouseSurface->pitch, + _mouseCurState.w, _mouseCurState.h); + + if (_videoMode.aspectRatioCorrection && _cursorTargetScale == 1) + cursorStretch200To240((uint8 *)_mouseSurface->pixels, _mouseSurface->pitch, rW, rH1, 0, 0, 0); + + SDL_UnlockSurface(_mouseSurface); + SDL_UnlockSurface(_mouseOrigSurface); +} + +// Basically it is kVeryFastAndUglyAspectMode of stretch200To240 from +// common/scale/aspect.cpp +static int cursorStretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY) { + int maxDstY = real2Aspect(origSrcY + height - 1); + int y; + const uint8 *startSrcPtr = buf + srcX * 2 + (srcY - origSrcY) * pitch; + uint8 *dstPtr = buf + srcX * 2 + maxDstY * pitch; + + for (y = maxDstY; y >= srcY; y--) { + const uint8 *srcPtr = startSrcPtr + aspect2Real(y) * pitch; + + if (srcPtr == dstPtr) + break; + memcpy(dstPtr, srcPtr, width * 2); + dstPtr -= pitch; + } + + return 1 + maxDstY - srcY; +} + +void OSystem_GP2X::toggleMouseGrab() { + if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF) + SDL_WM_GrabInput(SDL_GRAB_ON); + else + SDL_WM_GrabInput(SDL_GRAB_OFF); +} + +void OSystem_GP2X::undrawMouse() { + const int x = _mouseBackup.x; + const int y = _mouseBackup.y; + + // When we switch bigger overlay off mouse jumps. Argh! + // This is intended to prevent undrawing offscreen mouse + if (!_overlayVisible && (x >= _videoMode.screenWidth || y >= _videoMode.screenHeight)) + return; + + if (_mouseBackup.w != 0 && _mouseBackup.h != 0) + addDirtyRect(x, y, _mouseBackup.w, _mouseBackup.h); +} + +void OSystem_GP2X::drawMouse() { + if (!_mouseVisible || !_mouseSurface) { + _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0; + return; + } + + SDL_Rect zoomdst; + SDL_Rect dst; + int scale; + int hotX, hotY; + int tmpScreenWidth, tmpScreenHeight; + + // Temp vars to ensure we zoom to the LCD resolution or greater. + tmpScreenWidth = _videoMode.screenWidth; + tmpScreenHeight = _videoMode.screenHeight; + + if (_videoMode.screenHeight <= 240) { + tmpScreenHeight = 240; + } + + if (_videoMode.screenWidth <= 320) { + tmpScreenWidth = 320; + } + + dst.x = _mouseCurState.x; + dst.y = _mouseCurState.y; + + if (!_overlayVisible) { + scale = _videoMode.scaleFactor; + dst.w = _mouseCurState.vW; + dst.h = _mouseCurState.vH; + hotX = _mouseCurState.vHotX; + hotY = _mouseCurState.vHotY; + } else { + scale = 1; + dst.w = _mouseCurState.rW; + dst.h = _mouseCurState.rH; + hotX = _mouseCurState.rHotX; + hotY = _mouseCurState.rHotY; + } + + // The mouse is undrawn using virtual coordinates, i.e. they may be + // scaled and aspect-ratio corrected. + + _mouseBackup.x = dst.x - hotX; + _mouseBackup.y = dst.y - hotY; + _mouseBackup.w = dst.w; + _mouseBackup.h = dst.h; + + // We draw the pre-scaled cursor image, so now we need to adjust for + // scaling, shake position and aspect ratio correction manually. + + if (!_overlayVisible) { + dst.y += _currentShakePos; + } + + if (_videoMode.aspectRatioCorrection && !_overlayVisible) + dst.y = real2Aspect(dst.y); + + dst.x = scale * dst.x - _mouseCurState.rHotX; + dst.y = scale * dst.y - _mouseCurState.rHotY; + dst.w = _mouseCurState.rW; + dst.h = _mouseCurState.rH; + + // Hacking about with the zoom around mouse pointer stuff. + if (_adjustZoomOnMouse == true){ + + zoomdst.w = (tmpScreenWidth / 2); + zoomdst.h = (tmpScreenHeight / 2); + + // Create a zoomed rect centered on the mouse pointer. + // Will pan 1/4 of the screen. + + if (dst.x > ((tmpScreenWidth / 4) * 3)) { + zoomdst.x = (tmpScreenWidth / 2); + } else { + zoomdst.x = (dst.x - (tmpScreenWidth / 4)); + if (zoomdst.x < 0) { + zoomdst.x = 0; + } + } + + if (dst.y > ((tmpScreenHeight / 4) * 3)) { + zoomdst.y = (tmpScreenHeight / 2); + } else { + zoomdst.y = (dst.y - (tmpScreenHeight / 4)); + if (zoomdst.y < 0) { + zoomdst.y = 0; + } + } + SDL_GP2X_Display(&zoomdst); + } else { + + // Make sure we are looking at the whole screen otherwise. + + zoomdst.x = 0; + zoomdst.y = 0; + zoomdst.w = (tmpScreenWidth); + zoomdst.h = (tmpScreenHeight); + + SDL_GP2X_Display(&zoomdst); + }; + + // Note that SDL_BlitSurface() and addDirtyRect() will both perform any + // clipping necessary + + if (SDL_BlitSurface(_mouseSurface, NULL, _hwscreen, &dst) != 0) + error("SDL_BlitSurface failed: %s", SDL_GetError()); + + // The screen will be updated using real surface coordinates, i.e. + // they will not be scaled or aspect-ratio corrected. + + addDirtyRect(dst.x, dst.y, dst.w, dst.h, true); +} + +#pragma mark - +#pragma mark --- On Screen Display --- +#pragma mark - + +void OSystem_GP2X::displayMessageOnOSD(const char *msg) { + assert (_transactionMode == kTransactionNone); + assert(msg); + + Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends + + uint i; + + // Lock the OSD surface for drawing + if (SDL_LockSurface(_osdSurface)) + error("displayMessageOnOSD: SDL_LockSurface failed: %s", SDL_GetError()); + + Graphics::Surface dst; + dst.pixels = _osdSurface->pixels; + dst.w = _osdSurface->w; + dst.h = _osdSurface->h; + dst.pitch = _osdSurface->pitch; + dst.bytesPerPixel = _osdSurface->format->BytesPerPixel; + + // The font we are going to use: + const Graphics::Font *font = FontMan.getFontByUsage(Graphics::FontManager::kOSDFont); + + // Clear everything with the "transparent" color, i.e. the colorkey + SDL_FillRect(_osdSurface, 0, kOSDColorKey); + + // Split the message into separate lines. + Common::StringArray lines; + const char *ptr; + for (ptr = msg; *ptr; ++ptr) { + if (*ptr == '\n') { + lines.push_back(Common::String(msg, ptr - msg)); + msg = ptr + 1; + } + } + lines.push_back(Common::String(msg, ptr - msg)); + + // Determine a rect which would contain the message string (clipped to the + // screen dimensions). + const int vOffset = 6; + const int lineSpacing = 1; + const int lineHeight = font->getFontHeight() + 2 * lineSpacing; + int width = 0; + int height = lineHeight * lines.size() + 2 * vOffset; + for (i = 0; i < lines.size(); i++) { + width = MAX(width, font->getStringWidth(lines[i]) + 14); + } + + // Clip the rect + if (width > dst.w) + width = dst.w; + if (height > dst.h) + height = dst.h; + + // Draw a dark gray rect + // TODO: Rounded corners ? Border? + SDL_Rect osdRect; + osdRect.x = (dst.w - width) / 2; + osdRect.y = (dst.h - height) / 2; + osdRect.w = width; + osdRect.h = height; + SDL_FillRect(_osdSurface, &osdRect, SDL_MapRGB(_osdSurface->format, 64, 64, 64)); + + // Render the message, centered, and in white + for (i = 0; i < lines.size(); i++) { + font->drawString(&dst, lines[i], + osdRect.x, osdRect.y + i * lineHeight + vOffset + lineSpacing, osdRect.w, + SDL_MapRGB(_osdSurface->format, 255, 255, 255), + Graphics::kTextAlignCenter); + } + + // Finished drawing, so unlock the OSD surface again + SDL_UnlockSurface(_osdSurface); + + // Init the OSD display parameters, and the fade out + _osdAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100; + _osdFadeStartTime = SDL_GetTicks() + kOSDFadeOutDelay; + SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha); + + // Ensure a full redraw takes place next time the screen is updated + _forceFull = true; +} + +#pragma mark - +#pragma mark --- Misc --- +#pragma mark - + +bool OSystem_GP2X::handleScalerHotkeys(const SDL_KeyboardEvent &key) { + // Ctrl-Alt-a toggles aspect ratio correction + if (key.keysym.sym == 'a') { + beginGFXTransaction(); + setFeatureState(kFeatureAspectRatioCorrection, !_videoMode.aspectRatioCorrection); + endGFXTransaction(); + char buffer[128]; + if (_videoMode.aspectRatioCorrection) + sprintf(buffer, "Enabled aspect ratio correction\n%d x %d -> %d x %d", + _videoMode.screenWidth, _videoMode.screenHeight, + _hwscreen->w, _hwscreen->h + ); + else + sprintf(buffer, "Disabled aspect ratio correction\n%d x %d -> %d x %d", + _videoMode.screenWidth, _videoMode.screenHeight, + _hwscreen->w, _hwscreen->h + ); + displayMessageOnOSD(buffer); + + internUpdateScreen(); + return true; + } + + int newMode = -1; + int factor = _videoMode.scaleFactor - 1; + + // Increase/decrease the scale factor + if (key.keysym.sym == SDLK_EQUALS || key.keysym.sym == SDLK_PLUS || key.keysym.sym == SDLK_MINUS || + key.keysym.sym == SDLK_KP_PLUS || key.keysym.sym == SDLK_KP_MINUS) { + factor += (key.keysym.sym == SDLK_MINUS || key.keysym.sym == SDLK_KP_MINUS) ? -1 : +1; + if (0 <= factor && factor <= 3) { + newMode = s_gfxModeSwitchTable[_scalerType][factor]; + } + } + + const bool isNormalNumber = (SDLK_1 <= key.keysym.sym && key.keysym.sym <= SDLK_9); + const bool isKeypadNumber = (SDLK_KP1 <= key.keysym.sym && key.keysym.sym <= SDLK_KP9); + if (isNormalNumber || isKeypadNumber) { + _scalerType = key.keysym.sym - (isNormalNumber ? SDLK_1 : SDLK_KP1); + if (_scalerType >= ARRAYSIZE(s_gfxModeSwitchTable)) + return false; + + while (s_gfxModeSwitchTable[_scalerType][factor] < 0) { + assert(factor > 0); + factor--; + } + newMode = s_gfxModeSwitchTable[_scalerType][factor]; + } + + if (newMode >= 0) { + beginGFXTransaction(); + setGraphicsMode(newMode); + endGFXTransaction(); + + if (_osdSurface) { + const char *newScalerName = 0; + const GraphicsMode *g = getSupportedGraphicsModes(); + while (g->name) { + if (g->id == _videoMode.mode) { + newScalerName = g->description; + break; + } + g++; + } + if (newScalerName) { + char buffer[128]; + sprintf(buffer, "Active graphics filter: %s\n%d x %d -> %d x %d", + newScalerName, + _videoMode.screenWidth, _videoMode.screenHeight, + _hwscreen->w, _hwscreen->h + ); + displayMessageOnOSD(buffer); + } + } + internUpdateScreen(); + + return true; + } else { + return false; + } +} + +bool OSystem_GP2X::isScalerHotkey(const Common::Event &event) { + if ((event.kbd.flags & (Common::KBD_CTRL|Common::KBD_ALT)) == (Common::KBD_CTRL|Common::KBD_ALT)) { + const bool isNormalNumber = (Common::KEYCODE_1 <= event.kbd.keycode && event.kbd.keycode <= Common::KEYCODE_9); + const bool isKeypadNumber = (Common::KEYCODE_KP1 <= event.kbd.keycode && event.kbd.keycode <= Common::KEYCODE_KP9); + const bool isScaleKey = (event.kbd.keycode == Common::KEYCODE_EQUALS || event.kbd.keycode == Common::KEYCODE_PLUS || event.kbd.keycode == Common::KEYCODE_MINUS || + event.kbd.keycode == Common::KEYCODE_KP_PLUS || event.kbd.keycode == Common::KEYCODE_KP_MINUS); + + if (isNormalNumber || isKeypadNumber) { + int keyValue = event.kbd.keycode - (isNormalNumber ? Common::KEYCODE_1 : Common::KEYCODE_KP1); + if (keyValue >= ARRAYSIZE(s_gfxModeSwitchTable)) + return false; + } + return (isScaleKey || event.kbd.keycode == 'a'); + } + return false; +} diff --git a/backends/platform/gp2x/module.mk b/backends/platform/gp2x/module.mk index 837ad99d7b..d4f145c64f 100644 --- a/backends/platform/gp2x/module.mk +++ b/backends/platform/gp2x/module.mk @@ -2,9 +2,10 @@ MODULE := backends/platform/gp2x MODULE_OBJS := \ gp2x-hw.o \ - gp2x-main.o \ gp2x-mem.o \ - gp2x.o + events.o \ + graphics.o \ + gp2x.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/gph/build/README-GP2XWIZ b/backends/platform/gph/build/README-GP2XWIZ deleted file mode 100644 index 269fa901c9..0000000000 --- a/backends/platform/gph/build/README-GP2XWIZ +++ /dev/null @@ -1,140 +0,0 @@ -ScummVM - GP2X WIZ SPECIFIC README - HEAD SVN ------------------------------------------------------------------------- - -Contents: - - * About the backend/port <#About_the_backendport> - * Game compatability <#Game_compatibility> - * Included engines <#Included_engines> - * Supported audio options <#Supported_audio_options> - * Supported cut-scene options <#Supported_cut-scene_options> - * Recent changes <#Recent_changes> - * How to save <#How_to_save> - * Controller mappings <#Controller_mappings> - * Known issues <#Knonw_issues> - * Additional resources/links <#Additional_resourceslinks> - * Credits <#Credits> - ------------------------------------------------------------------------- - -Please refer to the: - -GP2X/GP2XWiz ScummVM Forum: <http://forums.scummvm.org/viewforum.php?f=14> -WiKi: <http://wiki.scummvm.org/index.php/GP2XWiz> - -for the most current information on the port and any updates to this -documentation. - ------------------------------------------------------------------------- -About the backend/port - -This is the readme for the official GP2XWiz ScummVM backend (also known as -the GP2XWiz port). - -This is an SVN test release of ScummVM for the GP2XWiz, it would be -appreciated if this SVN test distribution was not mirrored and that -people be directed to http://scummvm.distant-earth.com/ instead for -updated SVN builds. - -Full supported official releases of the GP2X WIZ ScummVM backend are made in -line with main official releases and are avalalble from the ScummVM -downloads page <http://www.scummvm.org/downloads.php>. - -This build is in an active state of development and as such no -"expected" behavior can be guaranteed ;). - ------------------------------------------------------------------------- -Game compatibility - -For information on the compatability of a specific game please refer to -the GP2XWiz compatability section of the ScummVM WiKi -<http://wiki.scummvm.org/index.php/GP2XWiz#Compatibility_List>. - -Please note the version and date of the ScummVM build you are running -when reviewing the above list. - ------------------------------------------------------------------------- -Supported audio options - -Raw audio. -MP3 audio. -OGG Vorbis audio. - -FLAC audio is currently unsupported. - -For best results use uncompressed audio in games. - ------------------------------------------------------------------------- -How to save - -NOTE: Everything is saved to the SD card, saves are stored in the saves -folder under your main ScummVM executable unless you set another save -location. - -The configiration file for ScummVM (.scummvmrc) is stored in the same -place as the ScummVM executable. - -The save process below is for Scumm engine games but the principle is -the same for all. - -In Game. - -1. Menu Button -2. Select SAVE with B -3. Select a position with B -4. Right trigger puts 0 in the name box for some text. -5. Press B to save - -Basically the emulated keys you can use are equivelent to the values -buttons are mapped to, - ------------------------------------------------------------------------- -Controller mappings - -Touch screen: -Touch: Move Pointer and Left click - -Mouse emulation: - -dPad: Move Pointer -B: Left click -X: Right click - -Keyboard emulation: - -Right Trigger: Return -Select: Escape -Y: Space Bar (Pause) -Menu: Game Menu (Save, Load, Quit etc.) -Volume Buttons: Increase and Decrease volume - -Fancy button combos: - -NOTE: To use button combos press and hold the Left Trigger then... - -Right Trigger: Display Virtual Keyboard -Menu: Bring up the Global main menu for ScummVM -Select: Exit ScummVM completely (and gracefully) - ------------------------------------------------------------------------- -Known issues - -No major known issues - ------------------------------------------------------------------------- -Additional resources/links - - * ScummVM WiKi GP2X page <http://wiki.scummvm.org/index.php/GP2X> - * ScummVM forums GP2X forum - <http://forums.scummvm.org/viewforum.php?f=14> - * My own ScummVM page <http://scummvm.distant-earth.com/> (for - SVN/test builds) - * Main ScummVM site <http://www.scummvm.org> (for official supported - release builds) - ------------------------------------------------------------------------- -Credits - -Core ScummVM code (c) The ScummVM Team -GP2X Wiz backend (c) John Willis -Detailed (c) information can be found within the source code diff --git a/backends/platform/gph/build/README-GPH b/backends/platform/gph/build/README-GPH new file mode 100644 index 0000000000..64b9fcb76b --- /dev/null +++ b/backends/platform/gph/build/README-GPH @@ -0,0 +1,60 @@ +ScummVM - GPH SPECIFIC README +------------------------------------------------------------------------ + +Contents: + + * About the backend/port <#About_the_backendport> + * Supported audio options <#Supported_audio_options> + * Credits <#Credits> + +------------------------------------------------------------------------ + +Please refer to the: + +GPH ScummVM Forum: <http://forums.scummvm.org/viewforum.php?f=14> + +WiKi: (Select your device) + +<http://wiki.scummvm.org/index.php/GP2X> +<http://wiki.scummvm.org/index.php/GP2XWiz> +<http://wiki.scummvm.org/index.php/Caanoo> + +for the most current information on the port and any updates to this +documentation. + +The wiki includes detailed instructions on how to use the port and +control information. + +------------------------------------------------------------------------ +About the backend/port + +This is the readme for the official GPH ScummVM backend (also known as +the GP2X port/GP2XWiz port and Caanoo port). + +This is an SVN test release of ScummVM for GPH devices, it would be +appreciated if this SVN test distribution was not mirrored and that +people be directed to http://scummvm.distant-earth.com/ instead for +updated SVN builds. + +Fully supported official releases of the GPH ScummVM backend are made in +line with main official releases and are avalalble from the ScummVM +downloads page <http://www.scummvm.org/downloads.php> for the GP2X, +GP2XWiz and Caanoo. + +------------------------------------------------------------------------ +Supported audio options + +Raw audio. +MP3 audio. +OGG Vorbis audio. + +FLAC audio is currently unsupported. + +For best results use uncompressed audio in games. + +------------------------------------------------------------------------ +Credits + +Core ScummVM code (c) The ScummVM Team +Portions of the GPH backend (c) John Willis +Detailed (c) information can be found within the source code diff --git a/backends/platform/gph/build/config-alleng.sh b/backends/platform/gph/build/config-alleng.sh index cfed463edf..9ec8a09cd2 100755 --- a/backends/platform/gph/build/config-alleng.sh +++ b/backends/platform/gph/build/config-alleng.sh @@ -13,10 +13,15 @@ export CXX=arm-open2x-linux-g++ export CXXFLAGS="-mcpu=arm926ej-s -mtune=arm926ej-s" export CPPFLAGS=-I/opt/open2x/gcc-4.1.1-glibc-2.3.6/include export LDFLAGS=-L/opt/open2x/gcc-4.1.1-glibc-2.3.6/lib -export DEFINES=-DNDEBUG # Edit the configure line to suit. cd ../../../.. -./configure --backend=gp2xwiz --disable-mt32emu --host=gp2xwiz --disable-flac --disable-nasm --disable-hq-scalers --with-sdl-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin --with-mpeg2-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-tremor --with-tremor-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-zlib --with-zlib-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-mad --with-mad-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-all-engines --enable-vkeybd --enable-plugins --default-dynamic +./configure --backend=gph --disable-mt32emu --host=gp2xwiz --disable-flac --disable-nasm --disable-hq-scalers \ + --with-sdl-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin --with-mpeg2-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \ + --enable-tremor --with-tremor-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \ + --enable-zlib --with-zlib-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \ + --enable-mad --with-mad-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \ + --enable-png --with-png-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \ + --enable-vkeybd --enable-all-engines --enable-plugins --default-dynamic echo Generating config for GP2X Wiz complete. Check for errors. diff --git a/backends/platform/gph/build/config.sh b/backends/platform/gph/build/config.sh index 25c3a83da0..ac7c34ad12 100755 --- a/backends/platform/gph/build/config.sh +++ b/backends/platform/gph/build/config.sh @@ -13,10 +13,15 @@ export CXX=arm-open2x-linux-g++ export CXXFLAGS="-mcpu=arm926ej-s -mtune=arm926ej-s" export CPPFLAGS=-I/opt/open2x/gcc-4.1.1-glibc-2.3.6/include export LDFLAGS=-L/opt/open2x/gcc-4.1.1-glibc-2.3.6/lib -export DEFINES=-DNDEBUG # Edit the configure line to suit. cd ../../../.. -./configure --backend=gp2xwiz --disable-mt32emu --host=gp2xwiz --disable-flac --disable-nasm --disable-hq-scalers --with-sdl-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin --with-mpeg2-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-tremor --with-tremor-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-zlib --with-zlib-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-mad --with-mad-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 --enable-vkeybd --enable-plugins --default-dynamic +./configure --backend=gph --disable-mt32emu --host=gp2xwiz --disable-flac --disable-nasm --disable-hq-scalers \ + --with-sdl-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin --with-mpeg2-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \ + --enable-tremor --with-tremor-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \ + --enable-zlib --with-zlib-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \ + --enable-mad --with-mad-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \ + --enable-png --with-png-prefix=/opt/open2x/gcc-4.1.1-glibc-2.3.6 \ + --enable-vkeybd --enable-plugins --default-dynamic echo Generating config for GP2X Wiz complete. Check for errors. diff --git a/backends/platform/gph/build/scummvm-gdb.gpe b/backends/platform/gph/build/scummvm-gdb.gpe index f486c288ee..63ce193ca8 100755 --- a/backends/platform/gph/build/scummvm-gdb.gpe +++ b/backends/platform/gph/build/scummvm-gdb.gpe @@ -6,7 +6,7 @@ export LD_LIBRARY_PATH=`pwd`/lib:$LD_LIBRARY_PATH # Run ScummVM via GDB (so make sure you have a terminal open or serial). # Oh, and GDB installed of course ;) -gdb --args ./scummvm.wiz --fullscreen --gfx-mode=1x --config=$(pwd)/.scummvmrc +gdb --args ./scummvm.gph --fullscreen --gfx-mode=1x --config=$(pwd)/.scummvmrc # Sync the SD card to check that everything is written. sync diff --git a/backends/platform/gph/build/scummvm.gpe b/backends/platform/gph/build/scummvm.gpe index 2866825e91..59ff562aeb 100755 --- a/backends/platform/gph/build/scummvm.gpe +++ b/backends/platform/gph/build/scummvm.gpe @@ -5,7 +5,7 @@ export LD_LIBRARY_PATH=`pwd`/lib:$LD_LIBRARY_PATH # Run ScummVM, important this bit. -./scummvm.wiz --fullscreen --gfx-mode=1x --config=$(pwd)/.scummvmrc +./scummvm.gph --fullscreen --gfx-mode=1x --config=$(pwd)/.scummvmrc # Sync the SD card to check that everything is written. sync diff --git a/backends/platform/gph/caanoo-bundle.mk b/backends/platform/gph/caanoo-bundle.mk index c411310688..b7b3c9e188 100755 --- a/backends/platform/gph/caanoo-bundle.mk +++ b/backends/platform/gph/caanoo-bundle.mk @@ -17,7 +17,7 @@ caanoo-bundle: $(EXECUTABLE) $(CP) $(srcdir)/backends/platform/gph/caanoo/scummvm.gpe $(bundle_name)/scummvm/ $(CP) $(srcdir)/backends/platform/gph/build/scummvm.png $(bundle_name)/scummvm/ $(CP) $(srcdir)/backends/platform/gph/build/scummvmb.png $(bundle_name)/scummvm/ - $(CP) $(srcdir)/backends/platform/gph/build/README-GP2XWIZ $(bundle_name)/scummvm/README-CAANOO + $(CP) $(srcdir)/backends/platform/gph/build/README-GPH $(bundle_name)/scummvm/ $(CP) $(srcdir)/backends/platform/gph/build/scummvm.ini $(bundle_name)/ $(INSTALL) -c -m 644 $(DIST_FILES_DOCS) $(bundle_name)/scummvm/ @@ -48,7 +48,7 @@ caanoo-bundle-debug: $(EXECUTABLE) $(CP) $(srcdir)/backends/platform/gph/caanoo/scummvm-gdb.gpe $(bundle_name)/scummvm/scummvm.gpe $(CP) $(srcdir)/backends/platform/gph/build/scummvm.png $(bundle_name)/scummvm/ $(CP) $(srcdir)/backends/platform/gph/build/scummvmb.png $(bundle_name)/scummvm/ - $(CP) $(srcdir)/backends/platform/gph/build/README-GP2XWIZ $(bundle_name)/scummvm/README-CAANOO + $(CP) $(srcdir)/backends/platform/gph/build/README-GPH $(bundle_name)/scummvm/ $(CP) $(srcdir)/backends/platform/gph/build/scummvm.ini $(bundle_name)/ $(INSTALL) -c -m 644 $(DIST_FILES_DOCS) $(bundle_name)/scummvm/ diff --git a/backends/platform/gph/caanoo/config-alleng.sh b/backends/platform/gph/caanoo/config-alleng.sh index 7a097c268b..97fed942fa 100755 --- a/backends/platform/gph/caanoo/config-alleng.sh +++ b/backends/platform/gph/caanoo/config-alleng.sh @@ -3,14 +3,19 @@ echo Quick script to make running configure all the time less painful echo and let all the build work be done from the backend/build folder. -# Assume Caanoo toolchain/build env. +# Assume Caanoo toolchain/build env and source it. . /opt/arm-caanoo/environment-setup -# Export the tool names for cross-compiling -export DEFINES=-DNDEBUG - # Edit the configure line to suit. cd ../../../.. -./configure --backend=caanoo --disable-mt32emu --host=caanoo --disable-alsa --disable-flac --disable-nasm --disable-vorbis --disable-hq-scalers --with-sdl-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr/bin --with-mpeg2-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --enable-tremor --with-tremor-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --enable-zlib --with-zlib-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --enable-mad --with-mad-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr --enable-all-engines --enable-vkeybd --enable-plugins --default-dynamic +./configure --backend=caanoo --disable-mt32emu --host=caanoo --disable-alsa --disable-flac \ + --disable-nasm --disable-vorbis --disable-hq-scalers \ + --with-sdl-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr/bin \ + --with-mpeg2-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \ + --enable-tremor --with-tremor-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \ + --enable-zlib --with-zlib-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \ + --enable-mad --with-mad-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \ + --enable-png --with-png-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \ + --enable-all-engines --enable-vkeybd --enable-plugins --default-dynamic -echo Generating config for GP2X Caanoo complete. Check for errors. +echo Generating config for Caanoo complete. Check for errors. diff --git a/backends/platform/gph/caanoo/config.sh b/backends/platform/gph/caanoo/config.sh index 82e3774dbf..11d597481a 100755 --- a/backends/platform/gph/caanoo/config.sh +++ b/backends/platform/gph/caanoo/config.sh @@ -6,11 +6,16 @@ echo and let all the build work be done from the backend/build folder. # Assume Caanoo toolchain/build env. . /opt/arm-caanoo/environment-setup -# Export the tool names for cross-compiling -export DEFINES=-DNDEBUG - # Edit the configure line to suit. cd ../../../.. -./configure --backend=caanoo --disable-mt32emu --host=caanoo --disable-alsa --disable-flac --disable-nasm --disable-vorbis --disable-hq-scalers --with-sdl-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr/bin --with-mpeg2-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr --enable-tremor --with-tremor-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr --enable-zlib --with-zlib-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr --enable-mad --with-mad-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr --enable-vkeybd --enable-plugins --default-dynamic +./configure --backend=caanoo --disable-mt32emu --host=caanoo --disable-alsa --disable-flac \ + --disable-nasm --disable-vorbis --disable-hq-scalers \ + --with-sdl-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr/bin \ + --with-mpeg2-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \ + --enable-tremor --with-tremor-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \ + --enable-zlib --with-zlib-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \ + --enable-mad --with-mad-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \ + --enable-png --with-png-prefix=/opt/arm-caanoo/arm-none-linux-gnueabi/usr \ + --enable-vkeybd --enable-plugins --default-dynamic echo Generating config for GP2X Caanoo complete. Check for errors. diff --git a/backends/platform/gph/caanoo/scummvm-gdb.gpe b/backends/platform/gph/caanoo/scummvm-gdb.gpe index 2d776f1bc3..63ce193ca8 100755 --- a/backends/platform/gph/caanoo/scummvm-gdb.gpe +++ b/backends/platform/gph/caanoo/scummvm-gdb.gpe @@ -6,7 +6,7 @@ export LD_LIBRARY_PATH=`pwd`/lib:$LD_LIBRARY_PATH # Run ScummVM via GDB (so make sure you have a terminal open or serial). # Oh, and GDB installed of course ;) -gdb --args ./scummvm.caanoo --fullscreen --gfx-mode=1x --config=$(pwd)/.scummvmrc +gdb --args ./scummvm.gph --fullscreen --gfx-mode=1x --config=$(pwd)/.scummvmrc # Sync the SD card to check that everything is written. sync diff --git a/backends/platform/gph/caanoo/scummvm.gpe b/backends/platform/gph/caanoo/scummvm.gpe index 52bb7a98cd..37d0f65d18 100755 --- a/backends/platform/gph/caanoo/scummvm.gpe +++ b/backends/platform/gph/caanoo/scummvm.gpe @@ -5,7 +5,7 @@ export LD_LIBRARY_PATH=`pwd`/lib:$LD_LIBRARY_PATH # Run ScummVM, important this bit. -./scummvm.caanoo --fullscreen --gfx-mode=1x --config=$(pwd)/.scummvmrc +./scummvm.gph --fullscreen --gfx-mode=1x --config=$(pwd)/.scummvmrc # Sync the SD card to check that everything is written. sync diff --git a/backends/platform/gph/gp2xwiz-bundle.mk b/backends/platform/gph/gp2xwiz-bundle.mk index 5ca6c0a9c7..df4cae7f4f 100755 --- a/backends/platform/gph/gp2xwiz-bundle.mk +++ b/backends/platform/gph/gp2xwiz-bundle.mk @@ -17,7 +17,7 @@ gp2xwiz-bundle: $(EXECUTABLE) $(CP) $(srcdir)/backends/platform/gph/build/scummvm.gpe $(bundle_name)/scummvm/ $(CP) $(srcdir)/backends/platform/gph/build/scummvm.png $(bundle_name)/scummvm/ $(CP) $(srcdir)/backends/platform/gph/build/scummvmb.png $(bundle_name)/scummvm/ - $(CP) $(srcdir)/backends/platform/gph/build/README-GP2XWIZ $(bundle_name)/scummvm/ + $(CP) $(srcdir)/backends/platform/gph/build/README-GPH $(bundle_name)/scummvm/ $(CP) $(srcdir)/backends/platform/gph/build/scummvm.ini $(bundle_name)/ $(INSTALL) -c -m 644 $(DIST_FILES_DOCS) $(bundle_name)/scummvm/ @@ -51,7 +51,7 @@ gp2xwiz-bundle-debug: $(EXECUTABLE) $(CP) $(srcdir)/backends/platform/gph/build/scummvm-gdb.gpe $(bundle_name)/scummvm/scummvm.gpe $(CP) $(srcdir)/backends/platform/gph/build/scummvm.png $(bundle_name)/scummvm/ $(CP) $(srcdir)/backends/platform/gph/build/scummvmb.png $(bundle_name)/scummvm/ - $(CP) $(srcdir)/backends/platform/gph/build/README-GP2XWIZ $(bundle_name)/scummvm/ + $(CP) $(srcdir)/backends/platform/gph/build/README-GPH $(bundle_name)/scummvm/ $(CP) $(srcdir)/backends/platform/gph/build/scummvm.ini $(bundle_name)/ $(INSTALL) -c -m 644 $(DIST_FILES_DOCS) $(bundle_name)/scummvm/ diff --git a/backends/platform/gph/gph-events.cpp b/backends/platform/gph/gph-events.cpp index 91ea30bdc9..2a6237c794 100644 --- a/backends/platform/gph/gph-events.cpp +++ b/backends/platform/gph/gph-events.cpp @@ -253,7 +253,6 @@ bool OSystem_GPH::handleMouseButtonUp(SDL_Event &ev, Common::Event &event) { event.type = Common::EVENT_MOUSEMOVE; else event.type = Common::EVENT_LBUTTONUP; /* For normal mice etc. */ - } else if (ev.button.button == SDL_BUTTON_RIGHT) event.type = Common::EVENT_RBUTTONUP; diff --git a/backends/platform/gph/gph-hw.cpp b/backends/platform/gph/gph-hw.cpp index b43324b547..fa52526f01 100644 --- a/backends/platform/gph/gph-hw.cpp +++ b/backends/platform/gph/gph-hw.cpp @@ -28,6 +28,9 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + #include "backends/platform/gph/gph-hw.h" #include <fcntl.h> diff --git a/backends/platform/gph/gph-main.cpp b/backends/platform/gph/gph-main.cpp index 727d599cc8..c433ba9f3f 100644 --- a/backends/platform/gph/gph-main.cpp +++ b/backends/platform/gph/gph-main.cpp @@ -23,9 +23,13 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + #include "common/scummsys.h" #include <SDL/SDL.h> +// #include "backends/platform/gph/gph-options.h" #include "backends/platform/gph/gph-sdl.h" #include "backends/platform/gph/gph-hw.h" #include "backends/plugins/posix/posix-provider.h" @@ -78,7 +82,7 @@ void OSystem_GPH::initBackend() { char workDirName[PATH_MAX+1]; if (getcwd(workDirName, PATH_MAX) == NULL) { - error("Could not obtain current working directory"); + error("Could not obtain current working directory."); } else { printf("Current working directory: %s\n", workDirName); } @@ -158,6 +162,9 @@ void OSystem_GPH::initBackend() { /* Make sure SDL knows that we have a joystick we want to use. */ ConfMan.setInt("joystick_num", 0); + /* Now setup any device specific user options (Left handed mode, that sort of thing). */ + // GPH::setOptions(); + printf("%s\n", "Passing to OSystem::SDL initBackend."); /* Pass to SDL backend to do the heavy lifting */ @@ -170,7 +177,7 @@ void OSystem_GPH::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) char workDirName[PATH_MAX+1]; if (getcwd(workDirName, PATH_MAX) == NULL) { - error("Error: Could not obtain current working directory"); + error("Error: Could not obtain current working directory."); } Common::FSNode workdirNode(workDirName); diff --git a/backends/platform/iphone/osys_events.cpp b/backends/platform/iphone/osys_events.cpp index 22f529dfac..c30e34dd05 100644 --- a/backends/platform/iphone/osys_events.cpp +++ b/backends/platform/iphone/osys_events.cpp @@ -23,6 +23,9 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + #include "gui/message.h" #include "common/translation.h" diff --git a/backends/platform/iphone/osys_main.cpp b/backends/platform/iphone/osys_main.cpp index a1fb8f0d5e..9dc4e202c4 100644 --- a/backends/platform/iphone/osys_main.cpp +++ b/backends/platform/iphone/osys_main.cpp @@ -23,6 +23,9 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + #include <unistd.h> #include <pthread.h> diff --git a/backends/platform/iphone/osys_sound.cpp b/backends/platform/iphone/osys_sound.cpp index 55892580f6..cd364f57ac 100644 --- a/backends/platform/iphone/osys_sound.cpp +++ b/backends/platform/iphone/osys_sound.cpp @@ -23,6 +23,9 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + #include "osys_main.h" void OSystem_IPHONE::AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB) { diff --git a/backends/platform/iphone/osys_video.cpp b/backends/platform/iphone/osys_video.cpp index d30a412a9f..88368a0eec 100644 --- a/backends/platform/iphone/osys_video.cpp +++ b/backends/platform/iphone/osys_video.cpp @@ -23,6 +23,9 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + #include "osys_main.h" const OSystem::GraphicsMode* OSystem_IPHONE::getSupportedGraphicsModes() const { diff --git a/backends/platform/linuxmoto/linuxmoto-events.cpp b/backends/platform/linuxmoto/linuxmoto-events.cpp new file mode 100644 index 0000000000..eb1bbc9394 --- /dev/null +++ b/backends/platform/linuxmoto/linuxmoto-events.cpp @@ -0,0 +1,228 @@ +/* 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 "backends/platform/linuxmoto/linuxmoto-sdl.h" +#include "graphics/scaler/aspect.h" // for aspect2Real + +static int mapKey(SDLKey key, SDLMod mod, Uint16 unicode) { + if (key >= SDLK_F1 && key <= SDLK_F9) { + return key - SDLK_F1 + Common::ASCII_F1; + } else if (key >= SDLK_KP0 && key <= SDLK_KP9) { + return key - SDLK_KP0 + '0'; + } else if (key >= SDLK_UP && key <= SDLK_PAGEDOWN) { + return key; + } else if (unicode) { + return unicode; + } else if (key >= 'a' && key <= 'z' && (mod & KMOD_SHIFT)) { + return key & ~0x20; + } else if (key >= SDLK_NUMLOCK && key <= SDLK_EURO) { + return 0; + } + return key; +} + +void OSystem_LINUXMOTO::fillMouseEvent(Common::Event &event, int x, int y) { + if (_videoMode.mode == GFX_HALF && !_overlayVisible) { + event.mouse.x = x*2; + event.mouse.y = y*2; + } else { + event.mouse.x = x; + event.mouse.y = y; + } + + // Update the "keyboard mouse" coords + _km.x = x; + _km.y = y; + + // Adjust for the screen scaling + if (!_overlayVisible) { + event.mouse.x /= _videoMode.scaleFactor; + event.mouse.y /= _videoMode.scaleFactor; + if (_videoMode.aspectRatioCorrection) + event.mouse.y = aspect2Real(event.mouse.y); + } +} + +bool OSystem_LINUXMOTO::remapKey(SDL_Event &ev, Common::Event &event) { + // Motorol A1200/E6/A1600 remapkey by Lubomyr +#ifdef MOTOEZX + // Quit on MOD+Camera Key on A1200 + if (ev.key.keysym.sym == SDLK_e) { + event.type = Common::EVENT_QUIT; + return true; + } + // '1' Bypass security protection - MOD+Call key + if (ev.key.keysym.sym == SDLK_f) { + ev.key.keysym.sym = SDLK_1; + } + // F5 Game Menu - Call key + else if (ev.key.keysym.sym == SDLK_SPACE) { + ev.key.keysym.sym = SDLK_F5; + } + // VirtualKeyboard - Camera key + else if (ev.key.keysym.sym == SDLK_PAUSE) { + ev.key.keysym.sym = SDLK_F7; + } + // Enter - mod+fire key + else if (ev.key.keysym.sym == SDLK_b) { + ev.key.keysym.sym = SDLK_RETURN; + } + // '3' - mod+up key + else if (ev.key.keysym.sym == SDLK_j) { + ev.key.keysym.sym = SDLK_3; + } + // '6' - mod+up key + else if (ev.key.keysym.sym == SDLK_i) { + ev.key.keysym.sym = SDLK_6; + } + // 'y' - mod+right key + else if (ev.key.keysym.sym == SDLK_g) { + ev.key.keysym.sym = SDLK_y; + } + // 'n' - mod+right key + else if (ev.key.keysym.sym == SDLK_h) { + ev.key.keysym.sym = SDLK_n; + } + // mod+vol'+' -> volume'+' + else if (ev.key.keysym.sym == SDLK_c) { + ev.key.keysym.sym = SDLK_RIGHTBRACKET; + } + // mod+vol'-' -> volume'-' + else if (ev.key.keysym.sym == SDLK_d) { + ev.key.keysym.sym = SDLK_LEFTBRACKET; + } +#endif + +#ifdef MOTOMAGX + // Quit on Clr + if (ev.key.keysym.sym == SDLK_BACKSPACE) { + event.type = Common::EVENT_QUIT; + return true; + } + // Game Menu - Left Soft key + else if (ev.key.keysym.sym == SDLK_F9) { + ev.key.keysym.sym = SDLK_F5; + } + // VirtualKeyboard - Right Soft key + else if (ev.key.keysym.sym == SDLK_F11) { + ev.key.keysym.sym = SDLK_F7; + } +#endif + +// Joystick to Mouse + else if (ev.key.keysym.sym == SDLK_LEFT) { + if (ev.type == SDL_KEYDOWN) { + _km.x_vel = -1; + _km.x_down_count = 1; + } else { + _km.x_vel = 0; + _km.x_down_count = 0; + } + + event.type = Common::EVENT_MOUSEMOVE; + fillMouseEvent(event, _km.x, _km.y); + return true; + } else if (ev.key.keysym.sym == SDLK_RIGHT) { + if (ev.type == SDL_KEYDOWN) { + _km.x_vel = 1; + _km.x_down_count = 1; + } else { + _km.x_vel = 0; + _km.x_down_count = 0; + } + + event.type = Common::EVENT_MOUSEMOVE; + fillMouseEvent(event, _km.x, _km.y); + + return true; + } else if (ev.key.keysym.sym == SDLK_DOWN) { + if (ev.type == SDL_KEYDOWN) { + _km.y_vel = 1; + _km.y_down_count = 1; + } else { + _km.y_vel = 0; + _km.y_down_count = 0; + } + + event.type = Common::EVENT_MOUSEMOVE; + fillMouseEvent(event, _km.x, _km.y); + + return true; + } else if (ev.key.keysym.sym == SDLK_UP) { + if (ev.type == SDL_KEYDOWN) { + _km.y_vel = -1; + _km.y_down_count = 1; + } else { + _km.y_vel = 0; + _km.y_down_count = 0; + } + + event.type = Common::EVENT_MOUSEMOVE; + fillMouseEvent(event, _km.x, _km.y); + + return true; + } else if (ev.key.keysym.sym == SDLK_RETURN) { + // Joystick center to pressing Left Mouse + if (ev.key.type == SDL_KEYDOWN) { + event.type = Common::EVENT_LBUTTONDOWN; + } else { + event.type = Common::EVENT_LBUTTONUP; + } + + fillMouseEvent(event, _km.x, _km.y); + + return true; + } else if (ev.key.keysym.sym == SDLK_PLUS) { + // Volume Up to pressing Right Mouse + if (ev.key.type == SDL_KEYDOWN ) { + event.type = Common::EVENT_RBUTTONDOWN; + } else { + event.type = Common::EVENT_RBUTTONUP; + } + fillMouseEvent(event, _km.x, _km.y); + + return true; + } else if (ev.key.keysym.sym == SDLK_MINUS) { + // Volume Down to pressing Left Mouse + if (ev.key.type == SDL_KEYDOWN) { + event.type = Common::EVENT_LBUTTONDOWN; + } else { + event.type = Common::EVENT_LBUTTONUP; + } + + fillMouseEvent(event, _km.x, _km.y); + + return true; + } else { + // Let the events fall through if we didn't change them, this may not be the best way to + // set it up, but i'm not sure how sdl would like it if we let if fall through then redid it though. + // and yes i have an huge terminal size so i dont wrap soon enough. + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym; + event.kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode); + } + + return false; +} diff --git a/backends/platform/linuxmoto/linuxmoto-graphics.cpp b/backends/platform/linuxmoto/linuxmoto-graphics.cpp new file mode 100644 index 0000000000..a39416ebc4 --- /dev/null +++ b/backends/platform/linuxmoto/linuxmoto-graphics.cpp @@ -0,0 +1,470 @@ +/* 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 "backends/platform/linuxmoto/linuxmoto-sdl.h" + +#include "common/mutex.h" +#include "graphics/font.h" +#include "graphics/fontman.h" +#include "graphics/scaler.h" +#include "graphics/scaler/aspect.h" +#include "graphics/scaler/downscaler.h" +#include "graphics/surface.h" + +static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { + {"1x", "Fullscreen", GFX_NORMAL}, + {"½x", "Downscale", GFX_HALF}, + {0, 0, 0} +}; + + +const OSystem::GraphicsMode *OSystem_LINUXMOTO::getSupportedGraphicsModes() const { + return s_supportedGraphicsModes; +} + +int OSystem_LINUXMOTO::getDefaultGraphicsMode() const { + return GFX_NORMAL; +} + +bool OSystem_LINUXMOTO::setGraphicsMode(int mode) { + Common::StackLock lock(_graphicsMutex); + + assert(_transactionMode == kTransactionActive); + + if (_oldVideoMode.setup && _oldVideoMode.mode == mode) + return true; + + int newScaleFactor = 1; + + switch (mode) { + case GFX_NORMAL: + newScaleFactor = 1; + break; + case GFX_HALF: + newScaleFactor = 1; + break; + default: + warning("unknown gfx mode %d", mode); + return false; + } + + _transactionDetails.normal1xScaler = (mode == GFX_NORMAL); + if (_oldVideoMode.setup && _oldVideoMode.scaleFactor != newScaleFactor) + _transactionDetails.needHotswap = true; + + _transactionDetails.needUpdatescreen = true; + + _videoMode.mode = mode; + _videoMode.scaleFactor = newScaleFactor; + + return true; +} + +void OSystem_LINUXMOTO::setGraphicsModeIntern() { + Common::StackLock lock(_graphicsMutex); + ScalerProc *newScalerProc = 0; + + switch (_videoMode.mode) { + case GFX_NORMAL: + newScalerProc = Normal1x; + break; + case GFX_HALF: + newScalerProc = DownscaleAllByHalf; + break; + + default: + error("Unknown gfx mode %d", _videoMode.mode); + } + + _scalerProc = newScalerProc; + + if (!_screen || !_hwscreen) + return; + + // Blit everything to the screen + _forceFull = true; + + // Even if the old and new scale factors are the same, we may have a + // different scaler for the cursor now. + blitCursor(); +} + + +void OSystem_LINUXMOTO::initSize(uint w, uint h) { + assert(_transactionMode == kTransactionActive); + + // Avoid redundant res changes + if ((int)w == _videoMode.screenWidth && (int)h == _videoMode.screenHeight) + return; + + _videoMode.screenWidth = w; + _videoMode.screenHeight = h; + + if (w > 320 || h > 240) { + setGraphicsMode(GFX_HALF); + setGraphicsModeIntern(); + toggleMouseGrab(); + } + + _transactionDetails.sizeChanged = true; +} + +bool OSystem_LINUXMOTO::loadGFXMode() { + printf("Game ScreenMode = %d*%d\n",_videoMode.screenWidth, _videoMode.screenHeight); + if (_videoMode.screenWidth > 320 || _videoMode.screenHeight > 240) { + _videoMode.aspectRatioCorrection = false; + setGraphicsMode(GFX_HALF); + printf("GraphicsMode set to HALF\n"); + } else { + setGraphicsMode(GFX_NORMAL); + printf("GraphicsMode set to NORMAL\n"); + } + if (_videoMode.mode == GFX_HALF && !_overlayVisible) { + _videoMode.overlayWidth = 320; + _videoMode.overlayHeight = 240; + _videoMode.fullscreen = true; + } else { + + _videoMode.overlayWidth = _videoMode.screenWidth * _videoMode.scaleFactor; + _videoMode.overlayHeight = _videoMode.screenHeight * _videoMode.scaleFactor; + + if (_videoMode.aspectRatioCorrection) + _videoMode.overlayHeight = real2Aspect(_videoMode.overlayHeight); + + _videoMode.hardwareWidth = _videoMode.screenWidth * _videoMode.scaleFactor; + _videoMode.hardwareHeight = effectiveScreenHeight(); + } + + return OSystem_SDL::loadGFXMode(); +} + +void OSystem_LINUXMOTO::drawMouse() { + if (!_mouseVisible || !_mouseSurface) { + _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0; + return; + } + + SDL_Rect dst; + int scale; + int hotX, hotY; + + if (_videoMode.mode == GFX_HALF && !_overlayVisible) { + dst.x = _mouseCurState.x/2; + dst.y = _mouseCurState.y/2; + } else { + dst.x = _mouseCurState.x; + dst.y = _mouseCurState.y; + } + + if (!_overlayVisible) { + scale = _videoMode.scaleFactor; + dst.w = _mouseCurState.vW; + dst.h = _mouseCurState.vH; + hotX = _mouseCurState.vHotX; + hotY = _mouseCurState.vHotY; + } else { + scale = 1; + dst.w = _mouseCurState.rW; + dst.h = _mouseCurState.rH; + hotX = _mouseCurState.rHotX; + hotY = _mouseCurState.rHotY; + } + + // The mouse is undrawn using virtual coordinates, i.e. they may be + // scaled and aspect-ratio corrected. + + _mouseBackup.x = dst.x - hotX; + _mouseBackup.y = dst.y - hotY; + _mouseBackup.w = dst.w; + _mouseBackup.h = dst.h; + + // We draw the pre-scaled cursor image, so now we need to adjust for + // scaling, shake position and aspect ratio correction manually. + + if (!_overlayVisible) { + dst.y += _currentShakePos; + } + + if (_videoMode.aspectRatioCorrection && !_overlayVisible) + dst.y = real2Aspect(dst.y); + + dst.x = scale * dst.x - _mouseCurState.rHotX; + dst.y = scale * dst.y - _mouseCurState.rHotY; + dst.w = _mouseCurState.rW; + dst.h = _mouseCurState.rH; + + // Note that SDL_BlitSurface() and addDirtyRect() will both perform any + // clipping necessary + + if (SDL_BlitSurface(_mouseSurface, NULL, _hwscreen, &dst) != 0) + error("SDL_BlitSurface failed: %s", SDL_GetError()); + + // The screen will be updated using real surface coordinates, i.e. + // they will not be scaled or aspect-ratio corrected. + addDirtyRect(dst.x, dst.y, dst.w, dst.h, true); +} + +void OSystem_LINUXMOTO::undrawMouse() { + const int x = _mouseBackup.x; + const int y = _mouseBackup.y; + + // When we switch bigger overlay off mouse jumps. Argh! + // This is intended to prevent undrawing offscreen mouse + if (!_overlayVisible && (x >= _videoMode.screenWidth || y >= _videoMode.screenHeight)) + return; + + if (_mouseBackup.w != 0 && _mouseBackup.h != 0) { + if (_videoMode.mode == GFX_HALF && !_overlayVisible) { + addDirtyRect(x*2, y*2, _mouseBackup.w*2, _mouseBackup.h*2); + } else { + addDirtyRect(x, y, _mouseBackup.w, _mouseBackup.h); + } + } +} + +void OSystem_LINUXMOTO::internUpdateScreen() { + SDL_Surface *srcSurf, *origSurf; + int height, width; + ScalerProc *scalerProc; + int scale1; + +#if defined (DEBUG) && ! defined(_WIN32_WCE) // definitions not available for non-DEBUG here. (needed this to compile in SYMBIAN32 & linux?) + assert(_hwscreen != NULL); + assert(_hwscreen->map->sw_data != NULL); +#endif + + // If the shake position changed, fill the dirty area with blackness + if (_currentShakePos != _newShakePos) { + SDL_Rect blackrect = {0, 0, _videoMode.screenWidth * _videoMode.scaleFactor, _newShakePos * _videoMode.scaleFactor}; + + if (_videoMode.aspectRatioCorrection && !_overlayVisible) + blackrect.h = real2Aspect(blackrect.h - 1) + 1; + + SDL_FillRect(_hwscreen, &blackrect, 0); + + _currentShakePos = _newShakePos; + + _forceFull = true; + } + + // Check whether the palette was changed in the meantime and update the + // screen surface accordingly. + if (_screen && _paletteDirtyEnd != 0) { + SDL_SetColors(_screen, _currentPalette + _paletteDirtyStart, + _paletteDirtyStart, + _paletteDirtyEnd - _paletteDirtyStart); + + _paletteDirtyEnd = 0; + + _forceFull = true; + } + +#ifdef USE_OSD + // OSD visible (i.e. non-transparent)? + if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + // Updated alpha value + const int diff = SDL_GetTicks() - _osdFadeStartTime; + if (diff > 0) { + if (diff >= kOSDFadeOutDuration) { + // Back to full transparency + _osdAlpha = SDL_ALPHA_TRANSPARENT; + } else { + // Do a linear fade out... + const int startAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100; + _osdAlpha = startAlpha + diff * (SDL_ALPHA_TRANSPARENT - startAlpha) / kOSDFadeOutDuration; + } + SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha); + _forceFull = true; + } + } +#endif + + if (!_overlayVisible) { + origSurf = _screen; + srcSurf = _tmpscreen; + width = _videoMode.screenWidth; + height = _videoMode.screenHeight; + scalerProc = _scalerProc; + scale1 = _videoMode.scaleFactor; + } else { + origSurf = _overlayscreen; + srcSurf = _tmpscreen2; + width = _videoMode.overlayWidth; + height = _videoMode.overlayHeight; + scalerProc = Normal1x; + scale1 = 1; + } + + // Add the area covered by the mouse cursor to the list of dirty rects if + // we have to redraw the mouse. + if (_mouseNeedsRedraw) + undrawMouse(); + + // Force a full redraw if requested + if (_forceFull) { + _numDirtyRects = 1; + _dirtyRectList[0].x = 0; + _dirtyRectList[0].y = 0; + _dirtyRectList[0].w = width; + _dirtyRectList[0].h = height; + } + + // Only draw anything if necessary + if (_numDirtyRects > 0 || _mouseNeedsRedraw) { + SDL_Rect *r; + SDL_Rect dst; + uint32 srcPitch, dstPitch; + SDL_Rect *lastRect = _dirtyRectList + _numDirtyRects; + + for (r = _dirtyRectList; r != lastRect; ++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. + + 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; r != lastRect; ++r) { + register int dst_y = r->y + _currentShakePos; + register int dst_h = 0; + register int dst_w = r->w; + register int orig_dst_y = 0; + register int dst_x = r->x; + register int src_y; + register int src_x; + + if (dst_y < height) { + dst_h = r->h; + if (dst_h > height - dst_y) + dst_h = height - dst_y; + + orig_dst_y = dst_y; + src_x = dst_x; + src_y = dst_y; + + if (_videoMode.aspectRatioCorrection && !_overlayVisible) + dst_y = real2Aspect(dst_y); + + assert(scalerProc != NULL); + + if (_videoMode.mode == GFX_HALF && scalerProc == DownscaleAllByHalf) { + + if (dst_x%2==1) { + dst_x--; + dst_w++; + } + if (dst_y%2==1) { + dst_y--; + dst_h++; + } + + if (dst_w&1) + dst_w++; + if (dst_h&1) + dst_h++; + + src_x = dst_x; + src_y = dst_y; + dst_x = dst_x / 2; + dst_y = dst_y / 2; + } + scalerProc((byte *)srcSurf->pixels + (src_x * 2 + 2) + (src_y + 1) * srcPitch, srcPitch, + (byte *)_hwscreen->pixels + dst_x * 2 + dst_y * dstPitch, dstPitch, dst_w, dst_h); + } + + if (_videoMode.mode == GFX_HALF && scalerProc == DownscaleAllByHalf) { + r->w = r->w / 2; + r->h = dst_h / 2; + } else { + r->w = r->w; + r->h = dst_h; + } + + r->x = dst_x; + r->y = dst_y; + +#ifdef USE_SCALERS + if (_videoMode.aspectRatioCorrection && orig_dst_y < height && !_overlayVisible) + r->h = stretch200To240((uint8 *) _hwscreen->pixels, dstPitch, r->w, r->h, r->x, r->y, orig_dst_y * scale1); +#endif + } + SDL_UnlockSurface(srcSurf); + SDL_UnlockSurface(_hwscreen); + + // Readjust the dirty rect list in case we are doing a full update. + // This is necessary if shaking is active. + if (_forceFull) { + _dirtyRectList[0].y = 0; + _dirtyRectList[0].h = (_videoMode.mode == GFX_HALF) ? effectiveScreenHeight()/2 : effectiveScreenHeight(); + } + + drawMouse(); + +#ifdef USE_OSD + if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + SDL_BlitSurface(_osdSurface, 0, _hwscreen, 0); + } +#endif + // Finally, blit all our changes to the screen + SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList); + } + + _numDirtyRects = 0; + _forceFull = false; + _mouseNeedsRedraw = false; +} + +void OSystem_LINUXMOTO::showOverlay() { + if (_videoMode.mode == GFX_HALF) { + _mouseCurState.x = _mouseCurState.x / 2; + _mouseCurState.y = _mouseCurState.y / 2; + } + OSystem_SDL::showOverlay(); +} + +void OSystem_LINUXMOTO::hideOverlay() { + if (_videoMode.mode == GFX_HALF) { + _mouseCurState.x = _mouseCurState.x * 2; + _mouseCurState.y = _mouseCurState.y * 2; + } + OSystem_SDL::hideOverlay(); +} + +void OSystem_LINUXMOTO::warpMouse(int x, int y) { + if (_mouseCurState.x != x || _mouseCurState.y != y) { + if (_videoMode.mode == GFX_HALF && !_overlayVisible) { + x = x / 2; + y = y / 2; + } + } + OSystem_SDL::warpMouse(x, y); +} diff --git a/backends/platform/linuxmoto/linuxmoto-main.cpp b/backends/platform/linuxmoto/linuxmoto-main.cpp index e9f2e661de..09b03c31d6 100644 --- a/backends/platform/linuxmoto/linuxmoto-main.cpp +++ b/backends/platform/linuxmoto/linuxmoto-main.cpp @@ -23,23 +23,24 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "common/scummsys.h" +#include "common/system.h" + +#include <SDL/SDL.h> +#include <SDL/SDL_syswm.h> + #include "backends/platform/linuxmoto/linuxmoto-sdl.h" #include "base/main.h" int main(int argc, char *argv[]) { - - // Create our OSystem instance g_system = new OSystem_LINUXMOTO(); assert(g_system); - - // Pre initialize the backend - ((OSystem_POSIX *)g_system)->init(); - // Invoke the actual ScummVM main entry point: int res = scummvm_main(argc, argv); - - // Free OSystem - delete (OSystem_LINUXMOTO *)g_system; + g_system->quit(); // TODO: Consider removing / replacing this! return res; } diff --git a/backends/platform/linuxmoto/linuxmoto-sdl.cpp b/backends/platform/linuxmoto/linuxmoto-sdl.cpp index 6ef03ed3ac..ad1af455c3 100644 --- a/backends/platform/linuxmoto/linuxmoto-sdl.cpp +++ b/backends/platform/linuxmoto/linuxmoto-sdl.cpp @@ -25,17 +25,44 @@ #include "backends/platform/linuxmoto/linuxmoto-sdl.h" -#include "backends/graphics/linuxmotosdl/linuxmotosdl-graphics.h" -#include "backends/events/linuxmotosdl/linuxmotosdl-events.h" +void OSystem_LINUXMOTO::preprocessEvents(SDL_Event *event) { + if (event->type == SDL_ACTIVEEVENT) { + if (event->active.state == SDL_APPINPUTFOCUS && !event->active.gain) { + suspendAudio(); + for (;;) { + if (!SDL_WaitEvent(event)) { + SDL_Delay(10); + continue; + } + if (event->type == SDL_QUIT) + return; + if (event->type != SDL_ACTIVEEVENT) + continue; + if (event->active.state == SDL_APPINPUTFOCUS && event->active.gain) { + resumeAudio(); + return; + } + } + } + } +} -void OSystem_LINUXMOTO::initBackend() { - // Create the backend custom managers - if (_eventManager == 0) - _eventManager = new LinuxmotoSdlEventManager(this); +void OSystem_LINUXMOTO::suspendAudio() { + SDL_CloseAudio(); + _audioSuspended = true; +} - if (_graphicsManager == 0) - _graphicsManager = new LinuxmotoSdlGraphicsManager(); +int OSystem_LINUXMOTO::resumeAudio() { + if (!_audioSuspended) + return -2; + if (SDL_OpenAudio(&_obtainedRate, NULL) < 0){ + return -1; + } + SDL_PauseAudio(0); + _audioSuspended = false; + return 0; +} - // Call parent implementation of this method - OSystem_POSIX::initBackend(); +void OSystem_LINUXMOTO::setupMixer() { + OSystem_SDL::setupMixer(); } diff --git a/backends/platform/linuxmoto/linuxmoto-sdl.h b/backends/platform/linuxmoto/linuxmoto-sdl.h index 78b9f81fd2..c01d375603 100644 --- a/backends/platform/linuxmoto/linuxmoto-sdl.h +++ b/backends/platform/linuxmoto/linuxmoto-sdl.h @@ -23,17 +23,43 @@ * */ -#ifndef PLATFORM_SDL_LINUXMOTO_H -#define PLATFORM_SDL_LINUXMOTO_H +#ifndef LINUXMOTO_SDL +#define LINUXMOTO_SDL -#include "backends/platform/sdl/posix/posix.h" +#include "backends/platform/sdl/sdl.h" -class OSystem_LINUXMOTO : public OSystem_POSIX { +// FIXME: For now keep hacks in this header to save polluting the SDL backend. +enum { + GFX_HALF = 12 +}; + +class OSystem_LINUXMOTO : public OSystem_SDL { +private: + bool _audioSuspended; public: - virtual void initBackend(); + /* Graphics */ + void initSize(uint w, uint h); + void setGraphicsModeIntern(); + bool setGraphicsMode(int mode); + void internUpdateScreen(); + const OSystem::GraphicsMode *getSupportedGraphicsModes() const; + bool setGraphicsMode(const char *name); + int getDefaultGraphicsMode() const; + bool loadGFXMode(); + void drawMouse(); + void undrawMouse(); + void showOverlay(); + void hideOverlay(); - // FIXME: This just calls parent methods, is it needed? + /* Event Stuff */ + virtual bool remapKey(SDL_Event &ev, Common::Event &event); + virtual void preprocessEvents(SDL_Event *event); + virtual void setupMixer(); virtual Common::HardwareKeySet *getHardwareKeySet(); + void fillMouseEvent(Common::Event&, int, int); + void suspendAudio(); + int resumeAudio(); + void warpMouse(int, int); }; #endif diff --git a/backends/platform/linuxmoto/module.mk b/backends/platform/linuxmoto/module.mk index c604d69da1..316ecbf78e 100644 --- a/backends/platform/linuxmoto/module.mk +++ b/backends/platform/linuxmoto/module.mk @@ -1,6 +1,8 @@ MODULE := backends/platform/linuxmoto MODULE_OBJS := \ + linuxmoto-events.o \ + linuxmoto-graphics.o \ linuxmoto-main.o \ linuxmoto-sdl.o \ hardwarekeys.o diff --git a/backends/platform/null/null.cpp b/backends/platform/null/null.cpp index d888e632d6..51166baae7 100644 --- a/backends/platform/null/null.cpp +++ b/backends/platform/null/null.cpp @@ -23,14 +23,22 @@ * */ -#include "backends/modular-backend.h" +#include "backends/base-backend.h" #include "base/main.h" #if defined(USE_NULL_DRIVER) + +#ifdef UNIX +#include <unistd.h> +#include <sys/time.h> +#endif + +#include "common/rect.h" +#include "graphics/colormasks.h" + #include "backends/saves/default/default-saves.h" #include "backends/timer/default/default-timer.h" #include "sound/mixer_intern.h" -#include "common/scummsys.h" /* * Include header files needed for the getFilesystemFactory() method. @@ -43,24 +51,82 @@ #include "backends/fs/windows/windows-fs-factory.h" #endif -class OSystem_NULL : public ModularBackend { +class OSystem_NULL : public BaseBackend { +protected: + Common::SaveFileManager *_savefile; + Audio::MixerImpl *_mixer; + Common::TimerManager *_timer; + FilesystemFactory *_fsFactory; + + timeval _startTime; public: + OSystem_NULL(); virtual ~OSystem_NULL(); virtual void initBackend(); - virtual bool pollEvent(Common::Event &event); + 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 int16 getHeight(); + virtual int16 getWidth(); + virtual void setPalette(const byte *colors, uint start, uint num); + virtual void grabPalette(byte *colors, uint start, uint num); + 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 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 { return Graphics::createPixelFormat<565>(); } + + 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 bool pollEvent(Common::Event &event); virtual uint32 getMillis(); - virtual void delayMillis(uint msecs) {} - virtual void getTimeAndDate(TimeDate &t) const {} + 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 Common::SaveFileManager *getSavefileManager(); + virtual Audio::Mixer *getMixer(); + virtual void getTimeAndDate(TimeDate &t) const; + virtual Common::TimerManager *getTimerManager(); + FilesystemFactory *getFilesystemFactory(); - virtual Common::SeekableReadStream *createConfigReadStream(); - virtual Common::WriteStream *createConfigWriteStream(); +}; + +static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { + {0, 0, 0} }; OSystem_NULL::OSystem_NULL() { + _savefile = 0; + _mixer = 0; + _timer = 0; + #if defined(__amigaos4__) _fsFactory = new AmigaOSFilesystemFactory(); #elif defined(UNIX) @@ -73,18 +139,20 @@ OSystem_NULL::OSystem_NULL() { } OSystem_NULL::~OSystem_NULL() { + delete _savefile; + delete _mixer; + delete _timer; + delete _fsFactory; } void OSystem_NULL::initBackend() { - _mutexManager = (MutexManager *)new NullMutexManager(); - _timerManager = new DefaultTimerManager(); - _eventManager = new DefaultEventManager(this); - _savefileManager = new DefaultSaveFileManager(); - _graphicsManager = (GraphicsManager *)new NullGraphicsManager(); - _audiocdManager = (AudioCDManager *)new DefaultAudioCDManager(); + _savefile = new DefaultSaveFileManager(); _mixer = new Audio::MixerImpl(this, 22050); - - ((Audio::MixerImpl *)_mixer)->setReady(false); + _timer = new DefaultTimerManager(); + + _mixer->setReady(false); + + gettimeofday(&_startTime, NULL); // Note that both the mixer and the timer manager are useless // this way; they need to be hooked into the system somehow to @@ -93,38 +161,163 @@ void OSystem_NULL::initBackend() { OSystem::initBackend(); } -bool OSystem_NULL::pollEvent(Common::Event &event) { +bool OSystem_NULL::hasFeature(Feature f) { return false; } -uint32 OSystem_NULL::getMillis() { +void OSystem_NULL::setFeatureState(Feature f, bool enable) { +} + +bool OSystem_NULL::getFeatureState(Feature f) { + return false; +} + +const OSystem::GraphicsMode* OSystem_NULL::getSupportedGraphicsModes() const { + return s_supportedGraphicsModes; +} + + +int OSystem_NULL::getDefaultGraphicsMode() const { + return -1; +} + +bool OSystem_NULL::setGraphicsMode(const char *mode) { + return true; +} + +bool OSystem_NULL::setGraphicsMode(int mode) { + return true; +} + +int OSystem_NULL::getGraphicsMode() const { + return -1; +} + +void OSystem_NULL::initSize(uint width, uint height, const Graphics::PixelFormat *format) { +} + +int16 OSystem_NULL::getHeight() { + return 200; +} + +int16 OSystem_NULL::getWidth() { + return 320; +} + +void OSystem_NULL::setPalette(const byte *colors, uint start, uint num) { +} + +void OSystem_NULL::grabPalette(byte *colors, uint start, uint num) { + +} + +void OSystem_NULL::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { +} + +void OSystem_NULL::updateScreen() { +} + +Graphics::Surface *OSystem_NULL::lockScreen() { return 0; } -#if defined(UNIX) -#if defined(SAMSUNGTV) -#define DEFAULT_CONFIG_FILE "/dtv/usb/sda1/.scummvmrc" +void OSystem_NULL::unlockScreen() { +} + +void OSystem_NULL::setShakePos(int shakeOffset) { +} + +void OSystem_NULL::showOverlay() { +} + +void OSystem_NULL::hideOverlay() { +} + +void OSystem_NULL::clearOverlay() { +} + +void OSystem_NULL::grabOverlay(OverlayColor *buf, int pitch) { +} + +void OSystem_NULL::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) { +} + +int16 OSystem_NULL::getOverlayHeight() { + return getHeight(); +} + +int16 OSystem_NULL::getOverlayWidth() { + return getWidth(); +} + + +bool OSystem_NULL::showMouse(bool visible) { + return true; +} + +void OSystem_NULL::warpMouse(int x, int y) { +} + +void OSystem_NULL::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) { +} + +bool OSystem_NULL::pollEvent(Common::Event &event) { + return false; +} + +uint32 OSystem_NULL::getMillis() { +#ifdef UNIX + timeval curTime; + gettimeofday(&curTime, NULL); + return (uint32)(((curTime.tv_sec - _startTime.tv_sec) * 1000) + \ + ((curTime.tv_usec - _startTime.tv_usec) / 1000)); #else -#define DEFAULT_CONFIG_FILE ".scummvmrc" -#endif + return 0; #endif +} -#if !defined(UNIX) -#define DEFAULT_CONFIG_FILE "scummvm.ini" +void OSystem_NULL::delayMillis(uint msecs) { +#ifdef UNIX + usleep(msecs * 1000); #endif +} -Common::SeekableReadStream *OSystem_NULL::createConfigReadStream() { - Common::FSNode file(DEFAULT_CONFIG_FILE); - return file.createReadStream(); +OSystem::MutexRef OSystem_NULL::createMutex(void) { + return NULL; } -Common::WriteStream *OSystem_NULL::createConfigWriteStream() { -#ifdef __DC__ - return 0; -#else - Common::FSNode file(DEFAULT_CONFIG_FILE); - return file.createWriteStream(); -#endif +void OSystem_NULL::lockMutex(MutexRef mutex) { +} + +void OSystem_NULL::unlockMutex(MutexRef mutex) { +} + +void OSystem_NULL::deleteMutex(MutexRef mutex) { +} + +void OSystem_NULL::quit() { +} + +Common::SaveFileManager *OSystem_NULL::getSavefileManager() { + assert(_savefile); + return _savefile; +} + +Audio::Mixer *OSystem_NULL::getMixer() { + assert(_mixer); + return _mixer; +} + +Common::TimerManager *OSystem_NULL::getTimerManager() { + assert(_timer); + return _timer; +} + +void OSystem_NULL::getTimeAndDate(TimeDate &t) const { +} + +FilesystemFactory *OSystem_NULL::getFilesystemFactory() { + return _fsFactory; } OSystem *OSystem_NULL_create() { @@ -137,7 +330,7 @@ int main(int argc, char *argv[]) { // Invoke the actual ScummVM main entry point: int res = scummvm_main(argc, argv); - delete (OSystem_NULL *)g_system; + g_system->quit(); // TODO: Consider removing / replacing this! return res; } diff --git a/backends/platform/openpandora/build/README-OPENPANDORA b/backends/platform/openpandora/build/README-OPENPANDORA index c3aa5e8ea9..c8aabcbb7a 100755 --- a/backends/platform/openpandora/build/README-OPENPANDORA +++ b/backends/platform/openpandora/build/README-OPENPANDORA @@ -1,4 +1,4 @@ -ScummVM - OPENPANDORA SPECIFIC README - HEAD SVN +ScummVM - OPENPANDORA SPECIFIC README ------------------------------------------------------------------------ Please refer to the: diff --git a/backends/platform/openpandora/build/config-alleng.sh b/backends/platform/openpandora/build/config-alleng.sh index cd9a17ef40..f3fa1a0f94 100755 --- a/backends/platform/openpandora/build/config-alleng.sh +++ b/backends/platform/openpandora/build/config-alleng.sh @@ -17,6 +17,13 @@ export DEFINES=-DNDEBUG # Edit the configure line to suit. cd ../../../.. -./configure --backend=openpandora --host=openpandora --disable-nasm --with-sdl-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr/bin --with-mpeg2-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --disable-vorbis --enable-tremor --with-tremor-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --enable-zlib --with-zlib-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --enable-mad --with-mad-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --enable-all-engines --enable-plugins --default-dynamic +./configure --backend=openpandora --host=openpandora --disable-nasm \ + --with-sdl-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr/bin \ + --with-mpeg2-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \ + --disable-vorbis --enable-tremor --with-tremor-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \ + --enable-zlib --with-zlib-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \ + --enable-mad --with-mad-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \ + --enable-png --with-png-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \ + --enable-all-engines --enable-plugins --default-dynamic echo Generating config for OpenPandora complete. Check for errors. diff --git a/backends/platform/openpandora/build/config.sh b/backends/platform/openpandora/build/config.sh index 8be16f1317..9bc52a9bc4 100755 --- a/backends/platform/openpandora/build/config.sh +++ b/backends/platform/openpandora/build/config.sh @@ -17,6 +17,13 @@ export DEFINES=-DNDEBUG # Edit the configure line to suit. cd ../../../.. -./configure --backend=openpandora --host=openpandora --disable-nasm --with-sdl-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr/bin --with-mpeg2-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --disable-vorbis --enable-tremor --with-tremor-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --enable-zlib --with-zlib-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --enable-mad --with-mad-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr --enable-plugins --default-dynamic +./configure --backend=openpandora --host=openpandora --disable-nasm \ + --with-sdl-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr/bin \ + --with-mpeg2-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \ + --disable-vorbis --enable-tremor --with-tremor-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \ + --enable-zlib --with-zlib-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \ + --enable-mad --with-mad-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \ + --enable-png --with-png-prefix=/usr/local/angstrom/arm/arm-angstrom-linux-gnueabi/usr \ + --enable-plugins --default-dynamic echo Generating config for OpenPandora complete. Check for errors. diff --git a/backends/platform/openpandora/op-main.cpp b/backends/platform/openpandora/op-main.cpp index 4febd404c3..3f4208a95a 100755 --- a/backends/platform/openpandora/op-main.cpp +++ b/backends/platform/openpandora/op-main.cpp @@ -23,6 +23,9 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + #include "common/scummsys.h" #include <SDL/SDL.h> diff --git a/backends/platform/ps2/fileio.cpp b/backends/platform/ps2/fileio.cpp index 8c10156aaf..826a2578e4 100644 --- a/backends/platform/ps2/fileio.cpp +++ b/backends/platform/ps2/fileio.cpp @@ -23,6 +23,9 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + #include "backends/platform/ps2/fileio.h" #include <tamtypes.h> diff --git a/backends/platform/ps2/systemps2.cpp b/backends/platform/ps2/systemps2.cpp index 7659d5194d..1b3ae6ba47 100644 --- a/backends/platform/ps2/systemps2.cpp +++ b/backends/platform/ps2/systemps2.cpp @@ -23,6 +23,12 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + #include <kernel.h> #include <stdio.h> #include <stdlib.h> @@ -59,6 +65,8 @@ #include "backends/platform/ps2/ps2debug.h" #include "backends/fs/ps2/ps2-fs-factory.h" +#include "backends/plugins/ps2/ps2-provider.h" + #include "backends/saves/default/default-saves.h" #include "common/config-manager.h" @@ -105,7 +113,6 @@ extern "C" int scummvm_main(int argc, char *argv[]); extern "C" int main(int argc, char *argv[]) { SifInitRpc(0); - ee_thread_t thisThread; int tid = GetThreadId(); ReferThreadStatus(tid, &thisThread); @@ -130,8 +137,11 @@ extern "C" int main(int argc, char *argv[]) { sioprintf("Creating system\n"); g_system = g_systemPs2 = new OSystem_PS2(argv[0]); - g_systemPs2->init(); +#ifdef DYNAMIC_MODULES + PluginManager::instance().addPluginProvider(new PS2PluginProvider()); +#endif + g_systemPs2->init(); sioprintf("init done. starting ScummVM.\n"); int res = scummvm_main(argc, argv); sioprintf("scummvm_main terminated: %d\n", res); diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile index 7f9ae153eb..dab3c34b51 100644 --- a/backends/platform/psp/Makefile +++ b/backends/platform/psp/Makefile @@ -67,7 +67,7 @@ endif # Variables for common Scummvm makefile CXX = psp-g++ CXXFLAGS = -O3 -Wall -Wno-multichar -fno-exceptions -fno-rtti -DEFINES = -D__PSP__ -DNONSTANDARD_PORT -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE -DUSE_ZLIB -DDISABLE_DOSBOX_OPL -DUSE_RGB_COLOR +DEFINES = -D__PSP__ -DNONSTANDARD_PORT -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE -DUSE_ZLIB -DDISABLE_DOSBOX_OPL -DUSE_RGB_COLOR -DUSE_ELF_LOADER -DMIPS_TARGET LDFLAGS := INCDIR := $(srcdir) . $(srcdir)/engines/ $(PSPSDK)/include @@ -87,8 +87,8 @@ CXX_UPDATE_DEP_FLAG = -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP # Variables for dynamic plugin building PLUGIN_PREFIX = PLUGIN_SUFFIX = .plg -PLUGIN_EXTRA_DEPS = plugin.syms scummvm-psp.elf -PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols=scummvm-psp.org.elf,-Tplugin.ld,--retain-symbols-file,plugin.syms -lstdc++ -lc +PLUGIN_EXTRA_DEPS = $(srcdir)/backends/plugins/elf/plugin.syms scummvm-psp.elf +PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols=scummvm-psp.org.elf,-T$(srcdir)/backends/plugins/psp/plugin.ld,--retain-symbols-file,$(srcdir)/backends/plugins/elf/plugin.syms -lstdc++ -lc # PSP-specific variables STRIP = psp-strip @@ -126,7 +126,8 @@ endif # PSP LIBS PSPLIBS = -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk \ -lpsputility -lpspuser -lpsppower -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lpspaudiocodec \ - -lpspkernel + -lpspkernel -lpspnet_inet + # Add in PSPSDK includes and libraries. LIBS += -lpng -lz -lstdc++ -lc -lm $(PSPLIBS) @@ -142,14 +143,16 @@ OBJS := powerman.o \ input.o \ cursor.o \ trace.o \ - psploader.o \ pspkeyboard.o \ audio.o \ thread.o \ rtc.o \ mp3.o \ png_loader.o \ - tests.o + image_viewer.o \ + tests.o \ + dummy.o + BACKEND := psp @@ -167,7 +170,7 @@ PSP_EBOOT_PIC1 = pic1.png PSP_EBOOT_SND0 = NULL PSP_EBOOT_PSAR = NULL -LDFLAGS += -Wl,-Tmain_prog.ld +LDFLAGS += -Wl,-T../../plugins/psp/main_prog.ld all: $(PSP_EBOOT) diff --git a/backends/platform/psp/README.PSP b/backends/platform/psp/README.PSP index 0849d68c78..b83f1cab6d 100644 --- a/backends/platform/psp/README.PSP +++ b/backends/platform/psp/README.PSP @@ -6,6 +6,7 @@ Installation - Copy the relevant game datafiles to your memory stick (location doesn't matter). - Install ScummVM like any other homebrew. - Run ScummVM and use the launcher to add games and run them. + - Press Start to return to the launcher and play another game. Controls ======== @@ -20,9 +21,10 @@ Cross - Left Mouse Button (usually the main button) Circle - Right Mouse Button (secondary button in some games) Square - '.' (skip dialogue in some games e.g. Scumm) Right trigger + Square - Spacebar (useful in Gobli*ns and SCI games) -Start - Global Menu. Allows you to 'Return To Launcher' to play another game Right trigger + Start - F5 (Main Menu in some games) Select - Show/Hide Virtual Keyboard. Hold down to move keyboard onscreen (with D-Pad). +Right trigger + Select - Show Image Viewer (see below) +Start - Global Menu. Allows you to 'Return To Launcher' to play another game Virtual Keyboard Mode ===================== @@ -37,6 +39,34 @@ Buttons/Triggers - Choose a specific character in the square. The four center c Analog - Moves in a direction (left/right/up/down) (Useful to keep moving while typing in AGI games among other things) + +Image Viewer +============ +For your convenience, I've included a simple image viewer in the PSP port. +You can view anything you want while playing a game. +There are a few simple rules to follow: + +- Images must be of PNG format. If you have images in another format, many + graphics utilities will convert them for you. +- Images must be named psp_image1.png, psp_image2.png etc. This is to make + sure there's no possible conflict between image files and game files. +- Images must be placed in the game directories. When using the image viewer, + only the images of the particular game being played will be available for viewing. +- Don't place any images in the ScummVM directory, or you won't be able to see + the images in the game directories. +- There's no guarantee that you'll be able to view your image. This is because + big images take a lot of memory (more than the size of the image on disk). If there + isn't enough memory left to show the image, ScummVM will tell you so. Try to make the + image smaller by either shrinking it or reducing the colors to 256 color palette mode. + +Image Viewer Controls: +===================== +Left/Right - previous/next image (e.g. go from psp_image1.png to psp_image2.png) +Up/down - zoom in/out +Analog - move around the image +Triggers, Start: - exit image viewer + + 1st Person Game Mode (Can be ignored by most users) ==================== This is a special mode built for 1st person games like Lands of Lore. If you don't have these games you can @@ -49,9 +79,12 @@ Square - Is the modifier key instead of Right Trigger. Left/Right Trigger - Strafe left/right D-Pad Left/Right - Turn left/right Square + D-Pad - F1/F2/F3/F4 +Square + Select - Image Viewer Square + Start - Esc (shows game menu) + + Notes ===== - Notice that you can switch between games! This is much faster than quitting diff --git a/backends/platform/psp/display_client.cpp b/backends/platform/psp/display_client.cpp index 916b6c1aae..9d4f573e28 100644 --- a/backends/platform/psp/display_client.cpp +++ b/backends/platform/psp/display_client.cpp @@ -347,7 +347,6 @@ void Buffer::copyFromRect(const byte *buf, uint32 pitch, int destX, int destY, u PspMemory::fastCopy(dst, buf, _pixelFormat.pixelsToBytes(recHeight * recWidth)); } else { do { - //memcpy(dst, buf, recWidthInBytes); if (_pixelFormat.swapRB) PspMemorySwap::fastSwap(dst, buf, recWidthInBytes, _pixelFormat); else @@ -379,45 +378,45 @@ void Buffer::copyToArray(byte *dst, int pitch) { } while (--h); } -/* We can size the buffer either by texture size (multiple of 2^n) or source size. The GU can - really handle both, but is supposed to get only 2^n size buffers */ void Buffer::setSize(uint32 width, uint32 height, HowToSize textureOrSource/*=kSizeByTextureSize*/) { DEBUG_ENTER_FUNC(); - PSP_DEBUG_PRINT("w[%u], h[%u], %s\n", width, height, textureOrSource ? "size by source" : "size by texture"); - + + // We can size the buffer either by texture size (multiple of 2^n) or source size. + // At higher sizes, increasing the texture size to 2^n is a waste of space. At these sizes kSizeBySourceSize should be used. + _sourceSize.width = width; _sourceSize.height = height; - _textureSize.width = scaleUpToPowerOfTwo(width); + _textureSize.width = scaleUpToPowerOfTwo(width); // can only scale up to 512 _textureSize.height = scaleUpToPowerOfTwo(height); - + if (textureOrSource == kSizeByTextureSize) { _width = _textureSize.width; _height = _textureSize.height; - } else { /* kSizeBySourceSize */ - _width = _sourceSize.width; + } else { // sizeBySourceSize + _width = _sourceSize.width; _height = _sourceSize.height; + + // adjust allocated width to be divisible by 32. + // The GU can only handle multiples of 16 bytes. A 4 bit image x 32 will give us 16 bytes + // We don't necessarily know the depth of the pixels here. So just make it divisible by 32. + uint32 checkDiv = _width & 31; + if (checkDiv) + _width += 32 - checkDiv; } + + PSP_DEBUG_PRINT("width[%u], height[%u], texW[%u], texH[%u], sourceW[%d], sourceH[%d] %s\n", _width, _height, _textureSize.width, _textureSize.height, _sourceSize.width, _sourceSize.height, textureOrSource ? "size by source" : "size by texture"); } -/* Scale a dimension (width/height) up to power of 2 for the texture */ +// Scale a dimension (width/height) up to power of 2 for the texture +// Will only go up to 512 since that's the maximum PSP texture size uint32 Buffer::scaleUpToPowerOfTwo(uint32 size) { - uint32 textureDimension = 0; - if (size <= 16) - textureDimension = 16; - else if (size <= 32) - textureDimension = 32; - else if (size <= 64) - textureDimension = 64; - else if (size <= 128) - textureDimension = 128; - else if (size <= 256) - textureDimension = 256; - else - textureDimension = 512; + uint32 textureDimension = 16; + while (size > textureDimension && textureDimension < 512) + textureDimension <<= 1; - PSP_DEBUG_PRINT("power of 2 = %u\n", textureDimension); + PSP_DEBUG_PRINT("size[%u]. power of 2[%u]\n", size, textureDimension); return textureDimension; } @@ -540,51 +539,41 @@ void GuRenderer::render() { DEBUG_ENTER_FUNC(); PSP_DEBUG_PRINT("Buffer[%p] Palette[%p]\n", _buffer->getPixels(), _palette->getRawValues()); - setMaxTextureOffsetByIndex(0, 0); - guProgramDrawBehavior(); if (_buffer->hasPalette()) guLoadPalette(); guProgramTextureFormat(); - guLoadTexture(); - - Vertex *vertices = guGetVertices(); - fillVertices(vertices); - - guDrawVertices(vertices); - - if (_buffer->getSourceWidth() > 512) { - setMaxTextureOffsetByIndex(1, 0); - guLoadTexture(); - - vertices = guGetVertices(); - fillVertices(vertices); - - guDrawVertices(vertices); + // Loop over patches of 512x512 pixel textures and draw them + for (uint32 j = 0; j < _buffer->getSourceHeight(); j += 512) { + _textureLoadOffset.y = j; + + for (uint32 i = 0; i < _buffer->getSourceWidth(); i += 512) { + _textureLoadOffset.x = i; + + guLoadTexture(); + Vertex *vertices = guGetVertices(); + fillVertices(vertices); + + guDrawVertices(vertices); + } } } -inline void GuRenderer::setMaxTextureOffsetByIndex(uint32 x, uint32 y) { - DEBUG_ENTER_FUNC(); - const uint32 maxTextureSizeShift = 9; /* corresponds to 512 = max texture size*/ - - _maxTextureOffset.x = x << maxTextureSizeShift; /* x times 512 */ - _maxTextureOffset.y = y << maxTextureSizeShift; /* y times 512 */ -} - inline void GuRenderer::guProgramDrawBehavior() { DEBUG_ENTER_FUNC(); - PSP_DEBUG_PRINT("blending[%s] colorTest[%s] reverseAlpha[%s] keyColor[%u]\n", _blending ? "on" : "off", _colorTest ? "on" : "off", _alphaReverse ? "on" : "off", _keyColor); + PSP_DEBUG_PRINT("blending[%s] colorTest[%s] reverseAlpha[%s] keyColor[%u]\n", + _blending ? "on" : "off", _colorTest ? "on" : "off", + _alphaReverse ? "on" : "off", _keyColor); if (_blending) { sceGuEnable(GU_BLEND); - if (_alphaReverse) // Reverse the alpha value (0 is 1) + if (_alphaReverse) // Reverse the alpha value (ie. 0 is 1) easier to do in some cases sceGuBlendFunc(GU_ADD, GU_ONE_MINUS_SRC_ALPHA, GU_SRC_ALPHA, 0, 0); - else // Normal alpha values + else // Normal alpha values sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); } else @@ -592,7 +581,9 @@ inline void GuRenderer::guProgramDrawBehavior() { if (_colorTest) { sceGuEnable(GU_COLOR_TEST); - sceGuColorFunc(GU_NOTEQUAL, _keyColor, 0x00ffffff); + sceGuColorFunc(GU_NOTEQUAL, // show only colors not equal to this color + _keyColor, + 0x00ffffff); // match everything but alpha } else sceGuDisable(GU_COLOR_TEST); } @@ -613,7 +604,8 @@ inline void GuRenderer::guLoadPalette() { PSP_DEBUG_PRINT("bpp[%d], pixelformat[%d], mask[%x]\n", _buffer->getBitsPerPixel(), _palette->getPixelFormat(), mask); sceGuClutMode(convertToGuPixelFormat(_palette->getPixelFormat()), 0, mask, 0); - sceGuClutLoad(_palette->getNumOfEntries() >> 3, _palette->getRawValues()); + sceGuClutLoad(_palette->getNumOfEntries() >> 3, // it's in batches of 8 for some reason + _palette->getRawValues()); } inline void GuRenderer::guProgramTextureFormat() { @@ -659,7 +651,17 @@ inline uint32 GuRenderer::convertToGuPixelFormat(PSPPixelFormat::Type format) { inline void GuRenderer::guLoadTexture() { DEBUG_ENTER_FUNC(); - sceGuTexImage(0, _buffer->getTextureWidth(), _buffer->getTextureHeight(), _buffer->getWidth(), _buffer->getPixels() + _buffer->_pixelFormat.pixelsToBytes(_maxTextureOffset.x)); + byte *startPoint = _buffer->getPixels(); + if (_textureLoadOffset.x) + startPoint += _buffer->_pixelFormat.pixelsToBytes(_textureLoadOffset.x); + if (_textureLoadOffset.y) + startPoint += _buffer->getWidthInBytes() * _textureLoadOffset.y; + + sceGuTexImage(0, + _buffer->getTextureWidth(), // texture width (must be power of 2) + _buffer->getTextureHeight(), // texture height (must be power of 2) + _buffer->getWidth(), // width of a line of the image (to get to the next line) + startPoint); // where to start reading } inline Vertex *GuRenderer::guGetVertices() { @@ -677,40 +679,40 @@ void GuRenderer::fillVertices(Vertex *vertices) { uint32 outputWidth = _displayManager->getOutputWidth(); uint32 outputHeight = _displayManager->getOutputHeight(); - float textureStartX, textureStartY, textureEndX, textureEndY; - // Texture adjustments for eliminating half-pixel artifacts from scaling // Not necessary if we don't scale - float textureAdjustment = 0.0f; + float textureFix = 0.0f; if (_useGlobalScaler && - (_displayManager->getScaleX() != 1.0f || _displayManager->getScaleX() != 1.0f)) - textureAdjustment = 0.5f; - - textureStartX = textureAdjustment + _offsetInBuffer.x; //debug - textureStartY = textureAdjustment + _offsetInBuffer.y; - // We subtract maxTextureOffset because our shifted texture starts at 512 and will go to 640 - textureEndX = _offsetInBuffer.x + _drawSize.width - textureAdjustment - _maxTextureOffset.x; - textureEndY = _offsetInBuffer.y + _drawSize.height - textureAdjustment; - + (_displayManager->getScaleX() != 1.0f || _displayManager->getScaleY() != 1.0f)) + textureFix = 0.5f; + + // These coordinates describe an area within the texture. ie. we already loaded a square of texture, + // now the coordinates within it are 0 to the edge of the area of the texture we want to draw + float textureStartX = textureFix + _offsetInBuffer.x; + float textureStartY = textureFix + _offsetInBuffer.y; + // even when we draw one of several textures, we use the whole drawsize of the image. The GU + // will draw what it can with the texture it has and scale it properly for us. + float textureEndX = -textureFix + _offsetInBuffer.x + _drawSize.width - _textureLoadOffset.x; + float textureEndY = -textureFix + _offsetInBuffer.y + _drawSize.height - _textureLoadOffset.y; // For scaling to the final image size, calculate the gaps on both sides uint32 gapX = _useGlobalScaler ? (PSP_SCREEN_WIDTH - outputWidth) >> 1 : 0; uint32 gapY = _useGlobalScaler ? (PSP_SCREEN_HEIGHT - outputHeight) >> 1 : 0; // Save scaled offset on screen - float scaledOffsetOnScreenX = scaleSourceToOutputX(_offsetOnScreen.x); - float scaledOffsetOnScreenY = scaleSourceToOutputY(_offsetOnScreen.y); - - float imageStartX, imageStartY, imageEndX, imageEndY; + float scaledOffsetOnScreenX = scaleSourceToOutput(true, _offsetOnScreen.x); + float scaledOffsetOnScreenY = scaleSourceToOutput(false, _offsetOnScreen.y); - imageStartX = gapX + scaledOffsetOnScreenX + (scaleSourceToOutputX(_maxTextureOffset.x)); - imageStartY = gapY + scaledOffsetOnScreenY; + float imageStartX = gapX + scaledOffsetOnScreenX + (scaleSourceToOutput(true, stretch(true, _textureLoadOffset.x))); + float imageStartY = gapY + scaledOffsetOnScreenY + (scaleSourceToOutput(false, stretch(false, _textureLoadOffset.y))); + float imageEndX, imageEndY; + if (_fullScreen) { // shortcut imageEndX = PSP_SCREEN_WIDTH - gapX + scaledOffsetOnScreenX; imageEndY = PSP_SCREEN_HEIGHT - gapY + scaledOffsetOnScreenY; // needed for screen shake } else { /* !fullScreen */ - imageEndX = imageStartX + scaleSourceToOutputX(_drawSize.width); - imageEndY = imageStartY + scaleSourceToOutputY(_drawSize.height); + imageEndX = gapX + scaledOffsetOnScreenX + scaleSourceToOutput(true, stretch(true, _drawSize.width)); + imageEndY = gapY + scaledOffsetOnScreenY + scaleSourceToOutput(false, stretch(false, _drawSize.height)); } vertices[0].u = textureStartX; @@ -729,8 +731,8 @@ void GuRenderer::fillVertices(Vertex *vertices) { PSP_DEBUG_PRINT("ImageStart: X[%f] Y[%f] ImageEnd: X[%.1f] Y[%.1f]\n", imageStartX, imageStartY, imageEndX, imageEndY); } -/* Scale the input X offset to appear in proper position on the screen */ -inline float GuRenderer::scaleSourceToOutputX(float offset) { +/* Scale the input X/Y offset to appear in proper position on the screen */ +inline float GuRenderer::scaleSourceToOutput(bool x, float offset) { float result; if (!_useGlobalScaler) @@ -738,28 +740,22 @@ inline float GuRenderer::scaleSourceToOutputX(float offset) { else if (!offset) result = 0.0f; else - result = offset * _displayManager->getScaleX(); + result = x ? offset * _displayManager->getScaleX() : offset * _displayManager->getScaleY(); return result; } -/* Scale the input Y offset to appear in proper position on the screen */ -inline float GuRenderer::scaleSourceToOutputY(float offset) { - float result; - - if (!_useGlobalScaler) - result = offset; - else if (!offset) - result = 0.0f; - else - result = offset * _displayManager->getScaleY(); - - return result; +/* Scale the input X/Y offset to appear in proper position on the screen */ +inline float GuRenderer::stretch(bool x, float size) { + if (!_stretch) + return size; + return (x ? size * _stretchX : size * _stretchY); } inline void GuRenderer::guDrawVertices(Vertex *vertices) { DEBUG_ENTER_FUNC(); + // This function shouldn't need changing. The '32' here refers to floating point vertices. sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, 2, 0, vertices); } diff --git a/backends/platform/psp/display_client.h b/backends/platform/psp/display_client.h index feec477282..005fc76c7c 100644 --- a/backends/platform/psp/display_client.h +++ b/backends/platform/psp/display_client.h @@ -174,8 +174,13 @@ protected: class GuRenderer { public: // Constructors - GuRenderer() : _useGlobalScaler(false), _buffer(0), _palette(0), _blending(false), _alphaReverse(false), _colorTest(false), _keyColor(0), _fullScreen(false) {} - GuRenderer(Buffer *buffer, Palette *palette) : _useGlobalScaler(false), _buffer(buffer), _palette(palette), _blending(false), _alphaReverse(false), _colorTest(false), _keyColor(0), _fullScreen(false) {} + GuRenderer() : _useGlobalScaler(false), _buffer(0), _palette(0), + _blending(false), _alphaReverse(false), _colorTest(false), + _keyColor(0), _fullScreen(false), _stretch(false), _stretchX(1.0f), _stretchY(1.0f) {} + GuRenderer(Buffer *buffer, Palette *palette) : + _useGlobalScaler(false), _buffer(buffer), _palette(palette), + _blending(false), _alphaReverse(false), _colorTest(false), + _keyColor(0), _fullScreen(false), _stretch(false), _stretchX(1.0f), _stretchY(1.0f) {} static void setDisplayManager(DisplayManager *dm) { _displayManager = dm; } // Called by the Display Manager // Setters @@ -190,8 +195,7 @@ public: } void setBuffer(Buffer *buffer) { _buffer = buffer; } void setPalette(Palette *palette) { _palette = palette; } - void setMaxTextureOffsetByIndex(uint32 x, uint32 y); // For drawing multiple textures - void setOffsetOnScreen(uint32 x, uint32 y) { _offsetOnScreen.x = x; _offsetOnScreen.y = y; } + void setOffsetOnScreen(int x, int y) { _offsetOnScreen.x = x; _offsetOnScreen.y = y; } void setOffsetInBuffer(uint32 x, uint32 y) { _offsetInBuffer.x = x; _offsetInBuffer.y = y; } void setColorTest(bool value) { _colorTest = value; } void setKeyColor(uint32 value) { _keyColor = _buffer->_pixelFormat.convertTo32BitColor(value); } @@ -199,6 +203,8 @@ public: void setAlphaReverse(bool value) { _alphaReverse = value; } void setFullScreen(bool value) { _fullScreen = value; } // Shortcut for rendering void setUseGlobalScaler(bool value) { _useGlobalScaler = value; } // Scale to screen + void setStretch(bool active) { _stretch = active; } + void setStretchXY(float x, float y) { _stretchX = x; _stretchY = y; } static void cacheInvalidate(void *pointer, uint32 size); @@ -216,11 +222,11 @@ protected: void guDrawVertices(Vertex *vertices); uint32 convertToGuPixelFormat(PSPPixelFormat::Type format); - float scaleSourceToOutputX(float offset); - float scaleSourceToOutputY(float offset); + float scaleSourceToOutput(bool x, float offset); + float stretch(bool x, float size); friend class MasterGuRenderer; - Point _maxTextureOffset; ///> For rendering textures > 512 pixels + Point _textureLoadOffset; ///> For rendering textures > 512 pixels Point _offsetOnScreen; ///> Where on screen to draw Point _offsetInBuffer; ///> Where in the texture to draw bool _useGlobalScaler; ///> Scale to the output size on screen @@ -233,6 +239,8 @@ protected: bool _colorTest; uint32 _keyColor; ///> Color to test against for color test. in 32 bits. bool _fullScreen; ///> Speeds up for fullscreen rendering + bool _stretch; ///> Whether zooming is activated + float _stretchX, _stretchY; }; #endif /* PSP_SCREEN_H */ diff --git a/backends/platform/psp/display_manager.cpp b/backends/platform/psp/display_manager.cpp index 5d75ac531e..2c94882a63 100644 --- a/backends/platform/psp/display_manager.cpp +++ b/backends/platform/psp/display_manager.cpp @@ -34,6 +34,7 @@ #include "backends/platform/psp/default_display_client.h" #include "backends/platform/psp/cursor.h" #include "backends/platform/psp/pspkeyboard.h" +#include "backends/platform/psp/image_viewer.h" #define USE_DISPLAY_CALLBACK // to use callback for finishing the render #include "backends/platform/psp/display_manager.h" @@ -385,10 +386,12 @@ bool DisplayManager::renderAll() { #endif /* USE_DISPLAY_CALLBACK */ // This is cheaper than checking time, so we do it first + // Any one of these being dirty causes everything to draw if (!_screen->isDirty() && - (!_overlay->isDirty()) && - (!_cursor->isDirty()) && - (!_keyboard->isDirty())) { + !_overlay->isDirty() && + !_cursor->isDirty() && + !_keyboard->isDirty() && + !_imageViewer->isDirty()) { PSP_DEBUG_PRINT("Nothing dirty\n"); return true; // nothing to render } @@ -396,34 +399,35 @@ bool DisplayManager::renderAll() { if (!isTimeToUpdate()) return false; // didn't render - PSP_DEBUG_PRINT("screen[%s], overlay[%s], cursor[%s], keyboard[%s]\n", + PSP_DEBUG_PRINT("dirty: screen[%s], overlay[%s], cursor[%s], keyboard[%s], imageViewer[%s]\n", _screen->isDirty() ? "true" : "false", _overlay->isDirty() ? "true" : "false", _cursor->isDirty() ? "true" : "false", - _keyboard->isDirty() ? "true" : "false" + _keyboard->isDirty() ? "true" : "false", + _imageViewer->isDirty() ? "true" : "false", ); _masterGuRenderer.guPreRender(); // Set up rendering _screen->render(); - _screen->setClean(); // clean out dirty bit + + if (_imageViewer->isVisible()) + _imageViewer->render(); + _imageViewer->setClean(); if (_overlay->isVisible()) - _overlay->render(); - + _overlay->render(); _overlay->setClean(); if (_cursor->isVisible()) _cursor->render(); - _cursor->setClean(); if (_keyboard->isVisible()) _keyboard->render(); - _keyboard->setClean(); - + _masterGuRenderer.guPostRender(); return true; // rendered successfully diff --git a/backends/platform/psp/display_manager.h b/backends/platform/psp/display_manager.h index 00d3851243..4537af0096 100644 --- a/backends/platform/psp/display_manager.h +++ b/backends/platform/psp/display_manager.h @@ -96,6 +96,7 @@ class Screen; class Overlay; class Cursor; class PSPKeyboard; +class ImageViewer; /** * Class that manages all display clients @@ -107,7 +108,8 @@ public: KEEP_ASPECT_RATIO, STRETCHED_FULL_SCREEN }; - DisplayManager() : _screen(0), _cursor(0), _overlay(0), _keyboard(0), _lastUpdateTime(0), _graphicsMode(0) {} + DisplayManager() : _screen(0), _cursor(0), _overlay(0), _keyboard(0), + _imageViewer(0), _lastUpdateTime(0), _graphicsMode(0) {} ~DisplayManager(); void init(); @@ -118,11 +120,13 @@ public: uint32 getDefaultGraphicsMode() const { return STRETCHED_FULL_SCREEN; } const OSystem::GraphicsMode* getSupportedGraphicsModes() const { return _supportedModes; } - // Setters + // Setters for pointers void setScreen(Screen *screen) { _screen = screen; } void setCursor(Cursor *cursor) { _cursor = cursor; } void setOverlay(Overlay *overlay) { _overlay = overlay; } void setKeyboard(PSPKeyboard *keyboard) { _keyboard = keyboard; } + void setImageViewer(ImageViewer *imageViewer) { _imageViewer = imageViewer; } + void setSizeAndPixelFormat(uint width, uint height, const Graphics::PixelFormat *format); // Getters @@ -148,6 +152,7 @@ private: Cursor *_cursor; Overlay *_overlay; PSPKeyboard *_keyboard; + ImageViewer *_imageViewer; MasterGuRenderer _masterGuRenderer; uint32 _lastUpdateTime; // For limiting FPS diff --git a/backends/platform/psp/dummy.cpp b/backends/platform/psp/dummy.cpp new file mode 100644 index 0000000000..4236734d4b --- /dev/null +++ b/backends/platform/psp/dummy.cpp @@ -0,0 +1,59 @@ +/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $ + * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $ + * + */ + + //#include "common/scummsys.h" + #include <time.h> + #include <stdlib.h> + #include <stdio.h> + #include <png.h> + #include <sys/socket.h> + +//void userWriteFn(png_structp png_ptr, png_bytep data, png_size_t length) { +//} + +//void userFlushFn(png_structp png_ptr) { +//} + + // Dummy functions are pulled in so that we don't need to build the plugins with certain libs + + int dummyFunc() { + + // For Broken Sword 2.5 + volatile int i; + i = clock(); + rename("dummyA", "dummyB"); + + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + png_set_write_fn(png_ptr, NULL, NULL, NULL); + png_infop info_ptr; + png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + png_destroy_write_struct(&png_ptr, &info_ptr); + + // For lua's usage of libc: very heavy usage so it pulls in sockets? + setsockopt(0, 0, 0, NULL, 0); + getsockopt(0, 0, 0, NULL, NULL); + + return i; +}
\ No newline at end of file diff --git a/backends/platform/psp/elf32.h b/backends/platform/psp/elf32.h deleted file mode 100644 index 616cc4b4d2..0000000000 --- a/backends/platform/psp/elf32.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$ - * - */ - -#ifndef BACKENDS_ELF_H -#define BACKENDS_ELF_H - -/* ELF stuff */ - -typedef unsigned short Elf32_Half, Elf32_Section; -typedef unsigned int Elf32_Word, Elf32_Addr, Elf32_Off; -typedef signed int Elf32_Sword; -typedef Elf32_Half Elf32_Versym; - -#define EI_NIDENT (16) -#define SELFMAG 6 - -/* ELF File format structures. Look up ELF structure for more details */ - -// ELF header (contains info about the file) -typedef struct { - unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ - Elf32_Half e_type; /* Object file type */ - Elf32_Half e_machine; /* Architecture */ - Elf32_Word e_version; /* Object file version */ - Elf32_Addr e_entry; /* Entry point virtual address */ - Elf32_Off e_phoff; /* Program header table file offset */ - Elf32_Off e_shoff; /* Section header table file offset */ - Elf32_Word e_flags; /* Processor-specific flags */ - Elf32_Half e_ehsize; /* ELF header size in bytes */ - Elf32_Half e_phentsize; /* Program header table entry size */ - Elf32_Half e_phnum; /* Program header table entry count */ - Elf32_Half e_shentsize; /* Section header table entry size */ - Elf32_Half e_shnum; /* Section header table entry count */ - Elf32_Half e_shstrndx; /* Section header string table index */ -} Elf32_Ehdr; - -// Should be in e_ident -#define ELFMAG "\177ELF\1\1" /* ELF Magic number */ - -// e_type values -#define ET_NONE 0 /* no file type */ -#define ET_REL 1 /* relocatable */ -#define ET_EXEC 2 /* executable */ -#define ET_DYN 3 /* shared object */ -#define ET_CORE 4 /* core file */ - -// e_machine values -#define EM_MIPS 8 - - -// Program header (contains info about segment) -typedef struct { - Elf32_Word p_type; /* Segment type */ - Elf32_Off p_offset; /* Segment file offset */ - Elf32_Addr p_vaddr; /* Segment virtual address */ - Elf32_Addr p_paddr; /* Segment physical address */ - Elf32_Word p_filesz; /* Segment size in file */ - Elf32_Word p_memsz; /* Segment size in memory */ - Elf32_Word p_flags; /* Segment flags */ - Elf32_Word p_align; /* Segment alignment */ -} Elf32_Phdr; - -// p_type values -#define PT_NULL 0 /* ignored */ -#define PT_LOAD 1 /* loadable segment */ -#define PT_DYNAMIC 2 /* dynamic linking info */ -#define PT_INTERP 3 /* info about interpreter */ -#define PT_NOTE 4 /* note segment */ -#define PT_SHLIB 5 /* reserved */ -#define PT_PHDR 6 /* Program header table */ -#define PT_MIPS_REGINFO 0x70000000 /* register usage info */ - -// p_flags value -#define PF_X 1 /* execute */ -#define PF_W 2 /* write */ -#define PF_R 4 /* read */ - -// Section header (contains info about section) -typedef struct { - Elf32_Word sh_name; /* Section name (string tbl index) */ - Elf32_Word sh_type; /* Section type */ - Elf32_Word sh_flags; /* Section flags */ - Elf32_Addr sh_addr; /* Section virtual addr at execution */ - Elf32_Off sh_offset; /* Section file offset */ - Elf32_Word sh_size; /* Section size in bytes */ - Elf32_Word sh_link; /* Link to another section */ - Elf32_Word sh_info; /* Additional section information */ - Elf32_Word sh_addralign; /* Section alignment */ - Elf32_Word sh_entsize; /* Entry size if section holds table */ -} Elf32_Shdr; - -// sh_type values -#define SHT_NULL 0 /* Inactive section */ -#define SHT_PROGBITS 1 /* Proprietary */ -#define SHT_SYMTAB 2 /* Symbol table */ -#define SHT_STRTAB 3 /* String table */ -#define SHT_RELA 4 /* Relocation entries with addend */ -#define SHT_HASH 5 /* Symbol hash table */ -#define SHT_DYNAMIC 6 /* Info for dynamic linking */ -#define SHT_NOTE 7 /* Note section */ -#define SHT_NOBITS 8 /* Occupies no space */ -#define SHT_REL 9 /* Relocation entries without addend */ -#define SHT_SHLIB 10 /* Reserved */ -#define SHT_DYNSYM 11 /* Minimal set of dynamic linking symbols */ -#define SHT_MIPS_LIBLSIT 0x70000000 /* Info about dynamic shared object libs */ -#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicts btw executables and shared objects */ -#define SHT_MIPS_GPTAB 0x70000003 /* Global pointer table */ - -// sh_flags values -#define SHF_WRITE 0 /* writable section */ -#define SHF_ALLOC 2 /* section occupies memory */ -#define SHF_EXECINSTR 4 /* machine instructions */ -#define SHF_MIPS_GPREL 0x10000000 /* Must be made part of global data area */ - - -// Symbol entry (contain info about a symbol) -typedef struct { - Elf32_Word st_name; /* Symbol name (string tbl index) */ - Elf32_Addr st_value; /* Symbol value */ - Elf32_Word st_size; /* Symbol size */ - unsigned char st_info; /* Symbol type and binding */ - unsigned char st_other; /* Symbol visibility */ - Elf32_Section st_shndx; /* Section index */ -} Elf32_Sym; - -// Extract from the st_info -#define SYM_TYPE(x) ((x)&0xF) -#define SYM_BIND(x) ((x)>>4) - - -// Symbol binding values from st_info -#define STB_LOCAL 0 /* Symbol not visible outside object */ -#define STB_GLOBAL 1 /* Symbol visible to all object files */ -#define STB_WEAK 2 /* Similar to STB_GLOBAL */ - -// Symbol type values from st_info -#define STT_NOTYPE 0 /* Not specified */ -#define STT_OBJECT 1 /* Data object e.g. variable */ -#define STT_FUNC 2 /* Function */ -#define STT_SECTION 3 /* Section */ -#define STT_FILE 4 /* Source file associated with object file */ - -// Special section header index values from st_shndex -#define SHN_UNDEF 0 -#define SHN_LOPROC 0xFF00 /* Extended values */ -#define SHN_ABS 0xFFF1 /* Absolute value: don't relocate */ -#define SHN_COMMON 0xFFF2 /* Common block. Not allocated yet */ -#define SHN_HIPROC 0xFF1F -#define SHN_HIRESERVE 0xFFFF - -// Relocation entry (info about how to relocate) -typedef struct { - Elf32_Addr r_offset; /* Address */ - Elf32_Word r_info; /* Relocation type and symbol index */ -} Elf32_Rel; - -// Access macros for the relocation info -#define REL_TYPE(x) ((x)&0xFF) /* Extract relocation type */ -#define REL_INDEX(x) ((x)>>8) /* Extract relocation index into symbol table */ - -// MIPS relocation types -#define R_MIPS_NONE 0 -#define R_MIPS_16 1 -#define R_MIPS_32 2 -#define R_MIPS_REL32 3 -#define R_MIPS_26 4 -#define R_MIPS_HI16 5 -#define R_MIPS_LO16 6 -#define R_MIPS_GPREL16 7 -#define R_MIPS_LITERAL 8 -#define R_MIPS_GOT16 9 -#define R_MIPS_PC16 10 -#define R_MIPS_CALL16 11 -#define R_MIPS_GPREL32 12 -#define R_MIPS_GOTHI16 13 -#define R_MIPS_GOTLO16 14 -#define R_MIPS_CALLHI16 15 -#define R_MIPS_CALLLO16 16 - -// Mock function to get value of global pointer -#define getGP() ({ \ - unsigned int __valgp; \ - __asm__ ("add %0, $gp, $0" : "=r"(__valgp) : ); \ - __valgp; \ -}) - -#endif /* BACKENDS_ELF_H */ diff --git a/backends/platform/psp/image_viewer.cpp b/backends/platform/psp/image_viewer.cpp new file mode 100644 index 0000000000..26b7f31c97 --- /dev/null +++ b/backends/platform/psp/image_viewer.cpp @@ -0,0 +1,327 @@ +/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $ + * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $ + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "common/scummsys.h" +#include "common/str.h" +#include "common/stream.h" +#include "common/archive.h" +#include "common/events.h" +#include "common/ptr.h" +#include "gui/message.h" +#include "engines/engine.h" +#include "backends/platform/psp/input.h" +#include "backends/platform/psp/display_manager.h" +#include "backends/platform/psp/display_client.h" +#include "backends/platform/psp/image_viewer.h" +#include "backends/platform/psp/png_loader.h" +#include "backends/platform/psp/thread.h" + +static const char *imageName = "psp_image"; +#define PSP_SCREEN_HEIGHT 272 +#define PSP_SCREEN_WIDTH 480 + +bool ImageViewer::load(int imageNum) { + if (_init) + unload(); + + // build string + char number[8]; + sprintf(number, "%d", imageNum); + Common::String imageNameStr(imageName); + Common::String specificImageName = imageNameStr + Common::String(number) + Common::String(".png"); + + // search for image file + if (!SearchMan.hasFile(specificImageName)) { + PSP_ERROR("file %s not found\n", specificImageName.c_str()); + return false; + } + + Common::ScopedPtr<Common::SeekableReadStream> file(SearchMan.createReadStreamForMember(specificImageName)); + + _buffer = new Buffer(); + _palette = new Palette(); + _renderer = new GuRenderer(); + + assert(_buffer); + assert(_palette); + assert(_renderer); + + // Load a PNG into our buffer and palette. Size it by the actual size of the image + PngLoader image(file, *_buffer, *_palette, Buffer::kSizeBySourceSize); + + PngLoader::Status status = image.allocate(); // allocate the buffers for the file + + char error[100]; + if (status == PngLoader::BAD_FILE) { + sprintf(error, "Cannot display %s. Not a proper PNG file", specificImageName.c_str()); + GUI::TimedMessageDialog dialog(error, 4000); + dialog.runModal(); + return false; + } else if (status == PngLoader::OUT_OF_MEMORY) { + sprintf(error, "Out of memory loading %s. Try making the image smaller", specificImageName.c_str()); + GUI::TimedMessageDialog dialog(error, 4000); + dialog.runModal(); + return false; + } + // try to load the image file + if (!image.load()) { + sprintf(error, "Cannot display %s. Not a proper PNG file", specificImageName.c_str()); + GUI::TimedMessageDialog dialog(error, 4000); + dialog.runModal(); + return false; + } + + setConstantRendererOptions(); + setFullScreenImageParams(); // prepare renderer for full screen view + + _imageNum = imageNum; // now we can say we displayed this image + _init = true; + + return true; +} + +void ImageViewer::setConstantRendererOptions() { + _renderer->setBuffer(_buffer); + _renderer->setPalette(_palette); + + _renderer->setAlphaBlending(false); + _renderer->setColorTest(false); + _renderer->setUseGlobalScaler(false); + _renderer->setStretch(true); + _renderer->setOffsetInBuffer(0, 0); + _renderer->setDrawWholeBuffer(); +} + +void ImageViewer::unload() { + _init = false; + delete _buffer; + delete _palette; + delete _renderer; + _buffer = 0; + _palette = 0; + _renderer = 0; +} + +void ImageViewer::resetOnEngineDone() { + _imageNum = 0; +} + +void ImageViewer::setVisible(bool visible) { + DEBUG_ENTER_FUNC(); + + if (_visible == visible) + return; + + // from here on, we're making the loader visible + if (visible && g_engine) { // we can only run the image viewer when there's an engine + g_engine->pauseEngine(true); + + load(_imageNum ? _imageNum : 1); // load the 1st image or the current + } + + if (visible && _init) { // we managed to load + _visible = true; + setViewerButtons(true); + + { // so dialog goes out of scope, destroying all allocations + GUI::TimedMessageDialog dialog("Image Viewer", 1000); + dialog.runModal(); + } + + runLoop(); // only listen to viewer events + } else { // we were asked to make invisible or failed to load + _visible = false; + unload(); + setViewerButtons(false); + + if (g_engine && g_engine->isPaused()) + g_engine->pauseEngine(false); + } + setDirty(); +} + +// This is the only way we can truly pause the games +// Sad but true. +void ImageViewer::runLoop() { + while (_visible) { + Common::Event event; + PspThread::delayMillis(30); + _inputHandler->getAllInputs(event); + _displayManager->renderAll(); + } +} + +void ImageViewer::setViewerButtons(bool active) { + _inputHandler->setImageViewerMode(active); +} + +void ImageViewer::loadNextImage() { + if (!load(_imageNum+1)) { // try to load the next image + if (!load(_imageNum)) // we failed, so reload the current image + setVisible(false); // just hide + } + setDirty(); +} + +void ImageViewer::loadLastImage() { + if (_imageNum - 1 > 0) { + if (!load(_imageNum-1)) + if (!load(_imageNum)) + setVisible(false); // we can't even show the old image so hide + } + setDirty(); +} + +void ImageViewer::setFullScreenImageParams() { + // we try to fit the image fullscreen at least in one dimension + uint32 width = _buffer->getSourceWidth(); + uint32 height = _buffer->getSourceHeight(); + + _centerX = PSP_SCREEN_WIDTH / 2.0f; + _centerY = PSP_SCREEN_HEIGHT / 2.0f; + + // see if we fit width wise + if (PSP_SCREEN_HEIGHT >= (int)((height * PSP_SCREEN_WIDTH) / (float)width)) { + setZoom(PSP_SCREEN_WIDTH / (float)width); + } else { + setZoom(PSP_SCREEN_HEIGHT / (float)height); + } +} + +void ImageViewer::render() { + if (_init) { + assert(_buffer); + assert(_renderer); + + // move the image slightly. Note that we count on the renderer's timing + switch (_movement) { + case EVENT_MOVE_LEFT: + moveImageX(-_visibleWidth / 100.0f); + break; + case EVENT_MOVE_UP: + moveImageY(-_visibleHeight / 100.0f); + break; + case EVENT_MOVE_RIGHT: + moveImageX(_visibleWidth / 100.0f); + break; + case EVENT_MOVE_DOWN: + moveImageY(_visibleHeight / 100.0f); + break; + default: + break; + } + _renderer->render(); + } +} + +void ImageViewer::modifyZoom(bool up) { + float factor = _zoomFactor; + if (up) + factor += 0.1f; + else // down + factor -= 0.1f; + + setZoom(factor); +} + +void ImageViewer::setZoom(float value) { + if (value <= 0.0f) // don't want 0 or negative zoom + return; + + _zoomFactor = value; + _renderer->setStretchXY(value, value); + setOffsetParams(); +} + +void ImageViewer::moveImageX(float val) { + float newVal = _centerX + val; + + if (newVal - (_visibleWidth / 2) > PSP_SCREEN_WIDTH - 4 || newVal + (_visibleWidth / 2) < 4) + return; + _centerX = newVal; + setOffsetParams(); +} + +void ImageViewer::moveImageY(float val) { + float newVal = _centerY + val; + + if (newVal - (_visibleHeight / 2) > PSP_SCREEN_HEIGHT - 4 || newVal + (_visibleHeight / 2) < 4) + return; + _centerY = newVal; + setOffsetParams(); +} + +// Set the renderer with the proper offset on the screen +// +void ImageViewer::setOffsetParams() { + _visibleWidth = _zoomFactor * _buffer->getSourceWidth(); + _visibleHeight = _zoomFactor * _buffer->getSourceHeight(); + + int offsetX = _centerX - (int)(_visibleWidth * 0.5f); + int offsetY = _centerY - (int)(_visibleHeight * 0.5f); + + _renderer->setOffsetOnScreen(offsetX, offsetY); + setDirty(); +} + +// Handler events coming in from the inputHandler +// +void ImageViewer::handleEvent(uint32 event) { + DEBUG_ENTER_FUNC(); + + switch (event) { + case EVENT_HIDE: + setVisible(false); + break; + case EVENT_SHOW: + setVisible(true); + break; + case EVENT_ZOOM_IN: + modifyZoom(true); + break; + case EVENT_ZOOM_OUT: + modifyZoom(false); + break; + case EVENT_MOVE_LEFT: + case EVENT_MOVE_UP: + case EVENT_MOVE_RIGHT: + case EVENT_MOVE_DOWN: + case EVENT_MOVE_STOP: + _movement = (Event)event; + break; + case EVENT_NEXT_IMAGE: + loadNextImage(); + break; + case EVENT_LAST_IMAGE: + loadLastImage(); + break; + default: + PSP_ERROR("Unknown event %d\n", event); + break; + } +}
\ No newline at end of file diff --git a/backends/platform/psp/image_viewer.h b/backends/platform/psp/image_viewer.h new file mode 100644 index 0000000000..ef8b196dbe --- /dev/null +++ b/backends/platform/psp/image_viewer.h @@ -0,0 +1,105 @@ +/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $ + * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $ + * + */ + +#ifndef PSP_IMAGE_VIEWER_H +#define PSP_IMAGE_VIEWER_H + +class InputHandler; + +class ImageViewer : public DisplayClient { +public: + enum Event { + EVENT_NONE = -1, + EVENT_HIDE = 0, + EVENT_SHOW = 1, + EVENT_ZOOM_IN, + EVENT_ZOOM_OUT, + EVENT_MOVE_LEFT, + EVENT_MOVE_UP, + EVENT_MOVE_RIGHT, + EVENT_MOVE_DOWN, + EVENT_MOVE_STOP, + EVENT_NEXT_IMAGE, + EVENT_LAST_IMAGE, + }; + +private: + Buffer *_buffer; + Palette *_palette; + GuRenderer *_renderer; + bool _visible; + bool _dirty; + bool _init; + uint32 _imageNum; // current image number + float _zoomFactor; // how much we're zooming in/out on the image + float _visibleHeight, _visibleWidth; + float _centerX, _centerY; + Event _movement; + + InputHandler *_inputHandler; + DisplayManager *_displayManager; + + void setFullScreenImageParams(); + void loadNextImage(); + void loadLastImage(); + void setViewerButtons(bool active); + void setConstantRendererOptions(); + void moveImageX(float val); + void moveImageY(float val); + bool load(int imageNum); + void unload(); + void runLoop(); // to get total pausing we have to do our own loop + + void setZoom(float value); + void setOffsetParams(); + void modifyZoom(bool up); // up or down + void setVisible(bool visible); + +public: + + ImageViewer() : _buffer(0), _palette(0), _visible(false), + _dirty(false), _init(false), _imageNum(0), + _zoomFactor(0.0f), _visibleHeight(0.0f), _visibleWidth(0.0f), + _centerX(0.0f), _centerY(0.0f), _movement(EVENT_MOVE_STOP), + _inputHandler(0), _displayManager(0) {} + ~ImageViewer() { unload(); } // deallocate images + bool load(); + void render(); + bool isVisible() { return _visible; } + bool isDirty() { return _dirty; } + void setDirty() { _dirty = true; } + void setClean() { if (!_visible) // otherwise we want to keep rendering + _dirty = false; + } + void resetOnEngineDone(); + + void handleEvent(uint32 event); + + // pointer setters + void setInputHandler(InputHandler *inputHandler) { _inputHandler = inputHandler; } + void setDisplayManager(DisplayManager *displayManager) { _displayManager = displayManager; } +}; + +#endif /* PSP_IMAGE_VIEWER_H */
\ No newline at end of file diff --git a/backends/platform/psp/input.cpp b/backends/platform/psp/input.cpp index ed868ef375..0dad31e5ae 100644 --- a/backends/platform/psp/input.cpp +++ b/backends/platform/psp/input.cpp @@ -95,7 +95,7 @@ const uint32 ButtonPad::_buttonMap[] = { }; ButtonPad::ButtonPad() : _prevButtonState(0), _shifted(UNSHIFTED), _padMode(PAD_MODE_NORMAL), - _comboMode(false) { + _comboMode(false), _combosEnabled(true) { for (int i = UNSHIFTED; i < SHIFTED_MODE_LAST; i++) _buttonsChanged[i] = 0; clearButtons(); @@ -154,6 +154,7 @@ void ButtonPad::initButtonsNormalMode() { _button[BTN_START][SHIFTED].setKey(Common::KEYCODE_F5, Common::ASCII_F5); _button[BTN_START][UNSHIFTED].setKey(Common::KEYCODE_F5, Common::ASCII_F5, Common::KBD_CTRL); _button[BTN_SELECT][UNSHIFTED].setPspEvent(PSP_EVENT_SHOW_VIRTUAL_KB, true, PSP_EVENT_NONE, 0); + _button[BTN_SELECT][SHIFTED].setPspEvent(PSP_EVENT_IMAGE_VIEWER, true, PSP_EVENT_NONE, 0); } void ButtonPad::initButtonsLolMode() { @@ -199,7 +200,8 @@ bool ButtonPad::getEvent(Common::Event &event, PspEvent &pspEvent, SceCtrlData & uint32 curButtonState = PSP_ALL_BUTTONS & pad.Buttons; // we only care about these - modifyButtonsForCombos(pad); // change buttons for combos + if (_combosEnabled) + modifyButtonsForCombos(pad); // change buttons for combos return getEventFromButtonState(event, pspEvent, curButtonState); } @@ -369,6 +371,7 @@ void InputHandler::init() { sceCtrlSetSamplingMode(1); // analog _buttonPad.initButtons(); + _nub.init(); } bool InputHandler::getAllInputs(Common::Event &event) { @@ -460,6 +463,12 @@ bool InputHandler::handlePspEvent(Common::Event &event, PspEvent &pspEvent) { /*case PSP_EVENT_CHANGE_SPEED: handleSpeedChange(pspEvent.data); break;*/ + case PSP_EVENT_IMAGE_VIEWER: + _imageViewer->handleEvent(pspEvent.data); + break; + case PSP_EVENT_IMAGE_VIEWER_SET_BUTTONS: + setImageViewerMode(pspEvent.data); + break; default: PSP_ERROR("Unhandled PSP Event[%d]\n", pspEvent.type); break; @@ -509,3 +518,56 @@ void InputHandler::handleSpeedChange(bool up) { GUI::TimedMessageDialog dialog(_padModeText[_padMode], 1500); dialog.runModal(); }*/ + +void InputHandler::setImageViewerMode(bool active) { + if (_buttonPad.isButtonDown() || _nub.isButtonDown()) { // can't switch yet + PSP_DEBUG_PRINT("postponing image viewer on event\n"); + _pendingPspEvent.type = PSP_EVENT_IMAGE_VIEWER_SET_BUTTONS; // queue it to be done later + _pendingPspEvent.data = active; + } else if (active) { + _nub.setDpadMode(true); + _buttonPad.enableCombos(false); // disable combos + setButtonsForImageViewer(); + } else { // deactivate + _nub.setDpadMode(false); + _nub.init(); + _buttonPad.enableCombos(true); // re-enable combos + _buttonPad.initButtons(); + } +} + +void InputHandler::setButtonsForImageViewer() { + DEBUG_ENTER_FUNC(); + + // Dpad + _buttonPad.clearButtons(); + _buttonPad.getButton(ButtonPad::BTN_UP, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_ZOOM_IN, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_DOWN, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_ZOOM_OUT, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_LEFT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_LAST_IMAGE, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_RIGHT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_NEXT_IMAGE, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_LTRIGGER, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_RTRIGGER, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_START, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_SELECT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE, + PSP_EVENT_NONE, false); + + //Nub + _nub.getPad().clearButtons(); + _nub.getPad().getButton(ButtonPad::BTN_UP, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_UP, + PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP); + _nub.getPad().getButton(ButtonPad::BTN_DOWN, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_DOWN, + PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP); + _nub.getPad().getButton(ButtonPad::BTN_LEFT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_LEFT, + PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP); + _nub.getPad().getButton(ButtonPad::BTN_RIGHT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_RIGHT, + PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP); +} + + diff --git a/backends/platform/psp/input.h b/backends/platform/psp/input.h index acca04f376..9a1ab6faab 100644 --- a/backends/platform/psp/input.h +++ b/backends/platform/psp/input.h @@ -30,6 +30,7 @@ #include "common/events.h" #include "backends/platform/psp/pspkeyboard.h" #include "backends/platform/psp/cursor.h" +#include "backends/platform/psp/image_viewer.h" #include <pspctrl.h> enum PspEventType { @@ -40,10 +41,11 @@ enum PspEventType { PSP_EVENT_RBUTTON, PSP_EVENT_MODE_SWITCH, PSP_EVENT_CHANGE_SPEED, + PSP_EVENT_IMAGE_VIEWER, + PSP_EVENT_IMAGE_VIEWER_SET_BUTTONS, PSP_EVENT_LAST }; - struct PspEvent { PspEventType type; uint32 data; @@ -112,59 +114,77 @@ private: ShiftMode _shifted; PspPadMode _padMode; bool _comboMode; // are we in the middle of combos - static const uint32 _buttonMap[]; // maps the buttons to their values + bool _combosEnabled; // can we do combos + static const uint32 _buttonMap[]; // maps the buttons to their values void initButtonsNormalMode(); void initButtonsLolMode(); void modifyButtonsForCombos(SceCtrlData &pad); - void clearButtons(); public: ButtonPad(); + void initButtons(); // set the buttons to the mode that's selected + void clearButtons(); // empty the buttons of all events + bool getEvent(Common::Event &event, PspEvent &pspEvent, SceCtrlData &pad); bool getEventFromButtonState(Common::Event &event, PspEvent &pspEvent, uint32 buttonState); + void setShifted(ShiftMode shifted) { _shifted = shifted; } void setPadMode(PspPadMode mode) { _padMode = mode; } bool isButtonDown() { return _prevButtonState; } - void initButtons(); + + void enableCombos(bool value) { _combosEnabled = value; } + Button &getButton(ButtonType type, ShiftMode mode) { return _button[type][mode]; } }; class Nub { private: Cursor *_cursor; // to enable changing/getting cursor position - ButtonPad _buttonPad; // private buttonpad for dpad mode ShiftMode _shifted; bool _dpadMode; - + + ButtonPad _buttonPad; // private buttonpad for dpad mode + + int32 modifyNubAxisMotion(int32 input); + void translateToDpadState(int dpadX, int dpadY, uint32 &buttonState); // convert nub data to dpad data public: - Nub() : _shifted(UNSHIFTED), _dpadMode(false) { _buttonPad.initButtons(); } + Nub() : _shifted(UNSHIFTED), _dpadMode(false) { } + void init() { _buttonPad.initButtons(); } void setCursor(Cursor *cursor) { _cursor = cursor; } + + // setters void setDpadMode(bool active) { _dpadMode = active; } void setShifted(ShiftMode shifted) { _shifted = shifted; } - bool isButtonDown(); + // getters + bool isButtonDown(); bool getEvent(Common::Event &event, PspEvent &pspEvent, SceCtrlData &pad); - int32 modifyNubAxisMotion(int32 input); - void translateToDpadState(int dpadX, int dpadY, uint32 &buttonState); // convert nub data to dpad data + ButtonPad &getPad() { return _buttonPad; } }; class InputHandler { public: - InputHandler() : _keyboard(0), _cursor(0), _padMode(PAD_MODE_NORMAL), _lastPadCheckTime(0) {} + InputHandler() : _keyboard(0), _cursor(0), _imageViewer(0), _padMode(PAD_MODE_NORMAL), + _lastPadCheckTime(0) {} + // pointer setters void setKeyboard(PSPKeyboard *keyboard) { _keyboard = keyboard; } void setCursor(Cursor *cursor) { _cursor = cursor; _nub.setCursor(cursor); } + void setImageViewer(ImageViewer *imageViewer) { _imageViewer = imageViewer; } void init(); bool getAllInputs(Common::Event &event); + void setImageViewerMode(bool active); private: + Nub _nub; + ButtonPad _buttonPad; + + // Pointers to relevant other classes PSPKeyboard *_keyboard; Cursor *_cursor; - - Nub _nub; - ButtonPad _buttonPad; + ImageViewer *_imageViewer; PspPadMode _padMode; // whice mode we're in PspEvent _pendingPspEvent; // an event that can't be handled yet @@ -176,6 +196,7 @@ private: void handleMouseEvent(Common::Event &event, Common::EventType type, const char *string); void handleShiftEvent(ShiftMode shifted); void handleModeSwitchEvent(); + void setButtonsForImageViewer(); }; #endif /* PSP_INPUT_H */ diff --git a/backends/platform/psp/main_prog.ld b/backends/platform/psp/main_prog.ld deleted file mode 100644 index 4216e7f0ab..0000000000 --- a/backends/platform/psp/main_prog.ld +++ /dev/null @@ -1,253 +0,0 @@ -OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", - "elf32-littlemips") -OUTPUT_ARCH(mips:allegrex) -ENTRY(_start) -/* Do we need any of these for elf? - __DYNAMIC = 0; */ -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - PROVIDE (__executable_start = 0x08900000); . = 0x08900000; - .interp : { *(.interp) } - .reginfo : { *(.reginfo) } - .dynamic : { *(.dynamic) } - .hash : { *(.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - .rel.init : { *(.rel.init) } - .rela.init : { *(.rela.init) } - .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } - .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } - .rel.fini : { *(.rel.fini) } - .rela.fini : { *(.rela.fini) } - /* PSP-specific relocations. */ - .rel.sceStub.text : { *(.rel.sceStub.text) *(SORT(.rel.sceStub.text.*)) } - .rel.lib.ent.top : { *(.rel.lib.ent.top) } - .rel.lib.ent : { *(.rel.lib.ent) } - .rel.lib.ent.btm : { *(.rel.lib.ent.btm) } - .rel.lib.stub.top : { *(.rel.lib.stub.top) } - .rel.lib.stub : { *(.rel.lib.stub) } - .rel.lib.stub.btm : { *(.rel.lib.stub.btm) } - .rel.rodata.sceModuleInfo : { *(.rel.rodata.sceModuleInfo) } - .rel.rodata.sceResident : { *(.rel.rodata.sceResident) } - .rel.rodata.sceNid : { *(.rel.rodata.sceNid) } - .rel.rodata.sceVstub : { *(.rel.rodata.sceVstub) *(SORT(.rel.rodata.sceVstub.*)) } - .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } - .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } - .rel.data.rel.ro : { *(.rel.data.rel.ro*) } - .rela.data.rel.ro : { *(.rel.data.rel.ro*) } - .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } - .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } - .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } - .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } - .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } - .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } - .rel.ctors : { *(.rel.ctors) } - .rela.ctors : { *(.rela.ctors) } - .rel.dtors : { *(.rel.dtors) } - .rela.dtors : { *(.rela.dtors) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } - .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } - .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } - .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } - .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } - .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } - .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } - .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } - .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } - .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .init : - { - KEEP (*(.init)) - } =0 - .plt : { *(.plt) } - .text : - { - _ftext = . ; - *(.text .stub .text.* .gnu.linkonce.t.*) - KEEP (*(.text.*personality*)) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - *(.mips16.fn.*) *(.mips16.call.*) - } =0 - .fini : - { - KEEP (*(.fini)) - } =0 - /* PSP library stub functions. */ - .sceStub.text : { *(.sceStub.text) *(SORT(.sceStub.text.*)) } - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - /* PSP library entry table and library stub table. */ - .lib.ent.top : { *(.lib.ent.top) } - .lib.ent : { *(.lib.ent) } - .lib.ent.btm : { *(.lib.ent.btm) } - .lib.stub.top : { *(.lib.stub.top) } - .lib.stub : { *(.lib.stub) } - .lib.stub.btm : { *(.lib.stub.btm) } - /* PSP read-only data for module info, NIDs, and Vstubs. The - .rodata.sceModuleInfo section must appear before the .rodata section - otherwise it would get absorbed into .rodata and the PSP bootloader - would be unable to locate the module info structure. */ - .rodata.sceModuleInfo : { *(.rodata.sceModuleInfo) } - .rodata.sceResident : { *(.rodata.sceResident) } - .rodata.sceNid : { *(.rodata.sceNid) } - .rodata.sceVstub : { *(.rodata.sceVstub) *(SORT(.rodata.sceVstub.*)) } - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } - .rodata1 : { *(.rodata1) } - .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) } - .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } - .eh_frame_hdr : { *(.eh_frame_hdr) } - .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RO { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. */ - . = ALIGN(256) + (. & (256 - 1)); - /* Exception handling */ - .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RW { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } - /* Thread Local Storage sections */ - .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } - .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } - /* Ensure the __preinit_array_start label is properly aligned. We - could instead move the label definition inside the section, but - the linker would then create the section even if it turns out to - be empty, which isn't pretty. */ - . = ALIGN(32 / 8); - PROVIDE (__preinit_array_start = .); - .preinit_array : { KEEP (*(.preinit_array)) } - PROVIDE (__preinit_array_end = .); - PROVIDE (__init_array_start = .); - .init_array : { KEEP (*(.init_array)) } - PROVIDE (__init_array_end = .); - PROVIDE (__fini_array_start = .); - .fini_array : { KEEP (*(.fini_array)) } - PROVIDE (__fini_array_end = .); - .ctors : - { - /* gcc uses crtbegin.o to find the start of - the constructors, so we make sure it is - first. Because this is a wildcard, it - doesn't matter if the user does not - actually link against crtbegin.o; the - linker won't look for a file to match a - wildcard. The wildcard also means that it - doesn't matter which directory crtbegin.o - is in. */ - KEEP (*crtbegin*.o(.ctors)) - /* We don't want to include the .ctor section from - from the crtend.o file until after the sorted ctors. - The .ctor section from the crtend file contains the - end of ctors marker and it must be last */ - KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - } - .dtors : - { - KEEP (*crtbegin*.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - } - .jcr : { KEEP (*(.jcr)) } - .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) } - .data : - { - _fdata = . ; - *(.data .data.* .gnu.linkonce.d.*) - KEEP (*(.gnu.linkonce.d.*personality*)) - SORT(CONSTRUCTORS) - } - .data1 : { *(.data1) } - . = .; - _gp = ALIGN(16) + 0x7ff0; - .got : { *(.got.plt) *(.got) } - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : - { - *(.sdata .sdata.* .gnu.linkonce.s.*) - } - .lit8 : { *(.lit8) } - .lit4 : { *(.lit4) } - _edata = .; - PROVIDE (edata = .); - __bss_start = .; - _fbss = .; - .sbss : - { - PROVIDE (__sbss_start = .); - PROVIDE (___sbss_start = .); - *(.dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - PROVIDE (__sbss_end = .); - PROVIDE (___sbss_end = .); - } - /* make a gap to put the plugins' short data here */ - __plugin_hole_start = .; - . = _gp + 0x7ff0; - __plugin_hole_end = .; - COMMON : - { - *(COMMON) - } - . = ALIGN(32 / 8); - .bss : - { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - /* Align here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. */ - . = ALIGN(32 / 8); - } - . = ALIGN(32 / 8); - _end = .; - PROVIDE (end = .); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - /DISCARD/ : { *(.comment) *(.pdr) } - /DISCARD/ : { *(.note.GNU-stack) } -} diff --git a/backends/platform/psp/module.mk b/backends/platform/psp/module.mk index f96c4ef583..e3eac153dd 100644 --- a/backends/platform/psp/module.mk +++ b/backends/platform/psp/module.mk @@ -11,14 +11,15 @@ MODULE_OBJS := powerman.o \ input.o \ cursor.o \ trace.o \ - psploader.o \ pspkeyboard.o \ audio.o \ thread.o \ rtc.o \ mp3.o \ png_loader.o \ - tests.o + image_viewer.o \ + tests.o \ + dummy.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/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp index 047ec1957f..40c074ae00 100644 --- a/backends/platform/psp/osys_psp.cpp +++ b/backends/platform/psp/osys_psp.cpp @@ -76,12 +76,18 @@ void OSystem_PSP::initBackend() { _displayManager.setScreen(&_screen); _displayManager.setOverlay(&_overlay); _displayManager.setKeyboard(&_keyboard); + _displayManager.setImageViewer(&_imageViewer); _displayManager.init(); // Set pointers for input handler _inputHandler.setCursor(&_cursor); _inputHandler.setKeyboard(&_keyboard); + _inputHandler.setImageViewer(&_imageViewer); _inputHandler.init(); + + // Set pointers for image viewer + _imageViewer.setInputHandler(&_inputHandler); + _imageViewer.setDisplayManager(&_displayManager); _savefile = new PSPSaveFileManager; @@ -97,6 +103,12 @@ void OSystem_PSP::initBackend() { OSystem::initBackend(); } +// Let's us know an engine +void OSystem_PSP::engineDone() { + // for now, all we need is to reset the image number on the viewer + _imageViewer.resetOnEngineDone(); +} + bool OSystem_PSP::hasFeature(Feature f) { return (f == kFeatureOverlaySupportsAlpha || f == kFeatureCursorHasPalette); } diff --git a/backends/platform/psp/osys_psp.h b/backends/platform/psp/osys_psp.h index 5721296c94..52b8f4e887 100644 --- a/backends/platform/psp/osys_psp.h +++ b/backends/platform/psp/osys_psp.h @@ -32,10 +32,12 @@ #include "sound/mixer_intern.h" #include "backends/base-backend.h" #include "backends/fs/psp/psp-fs-factory.h" + #include "backends/platform/psp/display_client.h" #include "backends/platform/psp/default_display_client.h" #include "backends/platform/psp/cursor.h" #include "backends/platform/psp/pspkeyboard.h" +#include "backends/platform/psp/image_viewer.h" #include "backends/platform/psp/display_manager.h" #include "backends/platform/psp/input.h" #include "backends/platform/psp/audio.h" @@ -60,6 +62,7 @@ private: InputHandler _inputHandler; PspAudio _audio; PspTimer _pspTimer; + ImageViewer _imageViewer; public: OSystem_PSP() : _savefile(0), _mixer(0), _timer(0), _pendingUpdate(false), _pendingUpdateCounter(0) {} @@ -146,6 +149,7 @@ public: Common::SaveFileManager *getSavefileManager() { return _savefile; } FilesystemFactory *getFilesystemFactory() { return &PSPFilesystemFactory::instance(); } void getTimeAndDate(TimeDate &t) const; + virtual void engineDone(); void quit(); diff --git a/backends/platform/psp/plugin.ld b/backends/platform/psp/plugin.ld deleted file mode 100644 index 7534c15290..0000000000 --- a/backends/platform/psp/plugin.ld +++ /dev/null @@ -1,239 +0,0 @@ -OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", - "elf32-littlemips") -OUTPUT_ARCH(mips:allegrex) -PHDRS -{ - plugin PT_LOAD ; - shorts PT_LOAD ; -} -/* Do we need any of these for elf? - __DYNAMIC = 0; */ -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = 0; - .interp : { *(.interp) } : plugin - .reginfo : { *(.reginfo) } : plugin - .dynamic : { *(.dynamic) } - .hash : { *(.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - .rel.init : { *(.rel.init) } - .rela.init : { *(.rela.init) } - .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } - .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } - .rel.fini : { *(.rel.fini) } - .rela.fini : { *(.rela.fini) } - /* PSP-specific relocations. */ - .rel.sceStub.text : { *(.rel.sceStub.text) *(SORT(.rel.sceStub.text.*)) } - .rel.lib.ent.top : { *(.rel.lib.ent.top) } - .rel.lib.ent : { *(.rel.lib.ent) } - .rel.lib.ent.btm : { *(.rel.lib.ent.btm) } - .rel.lib.stub.top : { *(.rel.lib.stub.top) } - .rel.lib.stub : { *(.rel.lib.stub) } - .rel.lib.stub.btm : { *(.rel.lib.stub.btm) } - .rel.rodata.sceModuleInfo : { *(.rel.rodata.sceModuleInfo) } - .rel.rodata.sceResident : { *(.rel.rodata.sceResident) } - .rel.rodata.sceNid : { *(.rel.rodata.sceNid) } - .rel.rodata.sceVstub : { *(.rel.rodata.sceVstub) *(SORT(.rel.rodata.sceVstub.*)) } - .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } - .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } - .rel.data.rel.ro : { *(.rel.data.rel.ro*) } - .rela.data.rel.ro : { *(.rel.data.rel.ro*) } - .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } - .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } - .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } - .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } - .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } - .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } - .rel.ctors : { *(.rel.ctors) } - .rela.ctors : { *(.rela.ctors) } - .rel.dtors : { *(.rel.dtors) } - .rela.dtors : { *(.rela.dtors) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } - .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } - .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } - .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } - .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } - .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } - .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } - .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } - .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } - .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .init : - { - KEEP (*(.init)) - } =0 - .plt : { *(.plt) } - .text : - { - _ftext = . ; - *(.text .stub .text.* .gnu.linkonce.t.*) - KEEP (*(.text.*personality*)) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - *(.mips16.fn.*) *(.mips16.call.*) - } =0 - .fini : - { - KEEP (*(.fini)) - } =0 - /* PSP library stub functions. */ - .sceStub.text : { *(.sceStub.text) *(SORT(.sceStub.text.*)) } - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - /* PSP library entry table and library stub table. */ - .lib.ent.top : { *(.lib.ent.top) } - .lib.ent : { *(.lib.ent) } - .lib.ent.btm : { *(.lib.ent.btm) } - .lib.stub.top : { *(.lib.stub.top) } - .lib.stub : { *(.lib.stub) } - .lib.stub.btm : { *(.lib.stub.btm) } - /* PSP read-only data for module info, NIDs, and Vstubs. The - .rodata.sceModuleInfo section must appear before the .rodata section - otherwise it would get absorbed into .rodata and the PSP bootloader - would be unable to locate the module info structure. */ - .rodata.sceModuleInfo : { *(.rodata.sceModuleInfo) } - .rodata.sceResident : { *(.rodata.sceResident) } - .rodata.sceNid : { *(.rodata.sceNid) } - .rodata.sceVstub : { *(.rodata.sceVstub) *(SORT(.rodata.sceVstub.*)) } - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } - .rodata1 : { *(.rodata1) } - .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) } - .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } - .eh_frame_hdr : { *(.eh_frame_hdr) } - .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RO { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. */ - . = ALIGN(256) + (. & (256 - 1)); - /* Exception handling */ - .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RW { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } - /* Thread Local Storage sections */ - .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } - .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } - /* Ensure the __preinit_array_start label is properly aligned. We - could instead move the label definition inside the section, but - the linker would then create the section even if it turns out to - be empty, which isn't pretty. */ - . = ALIGN(32 / 8); - PROVIDE (__preinit_array_start = .); - .preinit_array : { KEEP (*(.preinit_array)) } - PROVIDE (__preinit_array_end = .); - PROVIDE (__init_array_start = .); - .init_array : { KEEP (*(.init_array)) } - PROVIDE (__init_array_end = .); - PROVIDE (__fini_array_start = .); - .fini_array : { KEEP (*(.fini_array)) } - PROVIDE (__fini_array_end = .); - .ctors : - { - ___plugin_ctors = .; - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - ___plugin_ctors_end = .; - } - .dtors : - { - ___plugin_dtors = .; - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - ___plugin_dtors_end = .; - } - .jcr : { KEEP (*(.jcr)) } - .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) } - .data : - { - _fdata = . ; - *(.data .data.* .gnu.linkonce.d.*) - KEEP (*(.gnu.linkonce.d.*personality*)) - SORT(CONSTRUCTORS) - } - .data1 : { *(.data1) } - . = .; - .bss : - { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - /* Align here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. */ - . = ALIGN(32 / 8); - } - . = ALIGN(32 / 8); - _end = .; - PROVIDE (end = .); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - /DISCARD/ : { *(.comment) *(.pdr) } - /DISCARD/ : { *(.note.GNU-stack) } - - . = __plugin_hole_start; - .got : { *(.got.plt) *(.got) } : shorts - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : - { - *(.sdata .sdata.* .gnu.linkonce.s.*) - } - .lit8 : { *(.lit8) } - .lit4 : { *(.lit4) } - _edata = .; - PROVIDE (edata = .); - __bss_start = .; - _fbss = .; - .sbss : - { - PROVIDE (__sbss_start = .); - PROVIDE (___sbss_start = .); - *(.dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - PROVIDE (__sbss_end = .); - PROVIDE (___sbss_end = .); - } - - -} diff --git a/backends/platform/psp/plugin.syms b/backends/platform/psp/plugin.syms deleted file mode 100644 index 24ee1a19dc..0000000000 --- a/backends/platform/psp/plugin.syms +++ /dev/null @@ -1,8 +0,0 @@ -PLUGIN_getVersion -PLUGIN_getType -PLUGIN_getTypeVersion -PLUGIN_getObject -___plugin_ctors -___plugin_ctors_end -___plugin_dtors -___plugin_dtors_end diff --git a/backends/platform/psp/png_loader.cpp b/backends/platform/psp/png_loader.cpp index 978db3eaf9..08f370f36d 100644 --- a/backends/platform/psp/png_loader.cpp +++ b/backends/platform/psp/png_loader.cpp @@ -23,32 +23,43 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + #include "common/scummsys.h" #include "common/stream.h" #include "backends/platform/psp/psppixelformat.h" #include "backends/platform/psp/display_client.h" #include "backends/platform/psp/png_loader.h" +//#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */ +//#define __PSP_DEBUG_PRINT__ /* For debug printouts */ + +#include "backends/platform/psp/trace.h" + PngLoader::Status PngLoader::allocate() { + DEBUG_ENTER_FUNC(); + if (!findImageDimensions()) { PSP_ERROR("failed to get image dimensions\n"); return BAD_FILE; } - PSP_DEBUG_PRINT("width[%d], height[%d], paletteSize[%d], bitDepth[%d]\n", _width, _height, _paletteSize, _bitDepth); _buffer->setSize(_width, _height, _sizeBy); + uint32 bitsPerPixel = _bitDepth * _channels; + if (_paletteSize) { // 8 or 4-bit image - if (_paletteSize <= 16) { // 4 bit + if (bitsPerPixel == 4) { _buffer->setPixelFormat(PSPPixelFormat::Type_Palette_4bit); _palette->setPixelFormats(PSPPixelFormat::Type_4444, PSPPixelFormat::Type_Palette_4bit); - _paletteSize = 16; - } else if (_paletteSize <= 256) { // 8-bit image - _paletteSize = 256; + _paletteSize = 16; // round up + } else if (bitsPerPixel == 8) { // 8-bit image _buffer->setPixelFormat(PSPPixelFormat::Type_Palette_8bit); _palette->setPixelFormats(PSPPixelFormat::Type_4444, PSPPixelFormat::Type_Palette_8bit); + _paletteSize = 256; // round up } else { - PSP_ERROR("palette of %d too big!\n", _paletteSize); + PSP_ERROR("too many bits per pixel[%d] for a palette\n", bitsPerPixel); return BAD_FILE; } @@ -60,7 +71,7 @@ PngLoader::Status PngLoader::allocate() { PSP_ERROR("failed to allocate buffer\n"); return OUT_OF_MEMORY; } - if (!_palette->allocate()) { + if (_buffer->hasPalette() && !_palette->allocate()) { PSP_ERROR("failed to allocate palette\n"); return OUT_OF_MEMORY; } @@ -68,6 +79,7 @@ PngLoader::Status PngLoader::allocate() { } bool PngLoader::load() { + DEBUG_ENTER_FUNC(); // Try to load the image _file->seek(0); // Go back to start @@ -98,6 +110,7 @@ void PngLoader::libReadFunc(png_structp pngPtr, png_bytep data, png_size_t lengt } bool PngLoader::basicImageLoad() { + DEBUG_ENTER_FUNC(); _pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!_pngPtr) return false; @@ -119,7 +132,8 @@ bool PngLoader::basicImageLoad() { int interlaceType; png_get_IHDR(_pngPtr, _infoPtr, (png_uint_32 *)&_width, (png_uint_32 *)&_height, &_bitDepth, &_colorType, &interlaceType, int_p_NULL, int_p_NULL); - + _channels = png_get_channels(_pngPtr, _infoPtr); + if (_colorType & PNG_COLOR_MASK_PALETTE) _paletteSize = _infoPtr->num_palette; @@ -130,11 +144,11 @@ bool PngLoader::basicImageLoad() { bool PngLoader::findImageDimensions() { DEBUG_ENTER_FUNC(); - if (!basicImageLoad()) - return false; + bool status = basicImageLoad(); + PSP_DEBUG_PRINT("width[%d], height[%d], paletteSize[%d], bitDepth[%d], channels[%d], rowBytes[%d]\n", _width, _height, _paletteSize, _bitDepth, _channels, _infoPtr->rowbytes); png_destroy_read_struct(&_pngPtr, &_infoPtr, png_infopp_NULL); - return true; + return status; } // @@ -143,16 +157,16 @@ bool PngLoader::findImageDimensions() { bool PngLoader::loadImageIntoBuffer() { DEBUG_ENTER_FUNC(); - if (!basicImageLoad()) + if (!basicImageLoad()) { + png_destroy_read_struct(&_pngPtr, &_infoPtr, png_infopp_NULL); return false; - - // Strip off 16 bit channels. Not really needed but whatever - png_set_strip_16(_pngPtr); + } + png_set_strip_16(_pngPtr); // Strip off 16 bit channels in case they occur if (_paletteSize) { // Copy the palette png_colorp srcPal = _infoPtr->palette; - for (int i = 0; i < (int)_paletteSize; i++) { + for (int i = 0; i < _infoPtr->num_palette; i++) { unsigned char alphaVal = (i < _infoPtr->num_trans) ? _infoPtr->trans[i] : 0xFF; // Load alpha if it's there _palette->setSingleColorRGBA(i, srcPal->red, srcPal->green, srcPal->blue, alphaVal); srcPal++; @@ -163,10 +177,21 @@ bool PngLoader::loadImageIntoBuffer() { if (png_get_valid(_pngPtr, _infoPtr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(_pngPtr); // Convert trans channel to alpha for 32 bits - png_set_filler(_pngPtr, 0xff, PNG_FILLER_AFTER); // Filler for alpha? + png_set_add_alpha(_pngPtr, 0xff, PNG_FILLER_AFTER); // Filler for alpha if none exists } - unsigned char *line = (unsigned char*) malloc(_infoPtr->rowbytes); + uint32 rowBytes = png_get_rowbytes(_pngPtr, _infoPtr); + + // there seems to be a bug in libpng where it doesn't increase the rowbytes or the + // channel even after we add the alpha channel + if (_channels == 3 && (rowBytes / _width) == 3) { + _channels = 4; + rowBytes = _width * _channels; + } + + PSP_DEBUG_PRINT("rowBytes[%d], channels[%d]\n", rowBytes, _channels); + + unsigned char *line = (unsigned char*) malloc(rowBytes); if (!line) { png_destroy_read_struct(&_pngPtr, png_infopp_NULL, png_infopp_NULL); PSP_ERROR("Couldn't allocate line\n"); @@ -175,11 +200,9 @@ bool PngLoader::loadImageIntoBuffer() { for (size_t y = 0; y < _height; y++) { png_read_row(_pngPtr, line, png_bytep_NULL); - _buffer->copyFromRect(line, _infoPtr->rowbytes, 0, y, _width, 1); // Copy into buffer + _buffer->copyFromRect(line, rowBytes, 0, y, _width, 1); // Copy into buffer } - free(line); - png_read_end(_pngPtr, _infoPtr); png_destroy_read_struct(&_pngPtr, &_infoPtr, png_infopp_NULL); diff --git a/backends/platform/psp/png_loader.h b/backends/platform/psp/png_loader.h index 6b0282621a..4119bfef2b 100644 --- a/backends/platform/psp/png_loader.h +++ b/backends/platform/psp/png_loader.h @@ -44,11 +44,14 @@ private: uint32 _width; uint32 _height; uint32 _paletteSize; - int _bitDepth; Buffer::HowToSize _sizeBy; + + // PNG lib values + int _bitDepth; png_structp _pngPtr; png_infop _infoPtr; int _colorType; + uint32 _channels; public: enum Status { @@ -61,7 +64,8 @@ public: Buffer::HowToSize sizeBy = Buffer::kSizeByTextureSize) : _file(file), _buffer(&buffer), _palette(&palette), _width(0), _height(0), _paletteSize(0), - _bitDepth(0), _sizeBy(sizeBy), _pngPtr(0), _infoPtr(0), _colorType(0) {} + _bitDepth(0), _sizeBy(sizeBy), _pngPtr(0), + _infoPtr(0), _colorType(0), _channels(0) {} PngLoader::Status allocate(); bool load(); diff --git a/backends/platform/psp/psp.spec b/backends/platform/psp/psp.spec index ac325b7fd6..7177413373 100644 --- a/backends/platform/psp/psp.spec +++ b/backends/platform/psp/psp.spec @@ -1,3 +1,3 @@ %rename lib old_lib *lib: -%(old_lib) -lz -lstdc++ -lc -lm -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk -lpsputility -lpspuser -lpsppower -lpsphprm -lpsprtc -lpspaudio -lpspaudiocodec -lpspkernel +%(old_lib) -lz -lstdc++ -lc -lm -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk -lpsputility -lpspuser -lpsppower -lpsphprm -lpsprtc -lpspaudio -lpspaudiocodec -lpspkernel -lpspnet_inet diff --git a/backends/platform/psp/pspkeyboard.cpp b/backends/platform/psp/pspkeyboard.cpp index 3dd5e9789b..f210726692 100644 --- a/backends/platform/psp/pspkeyboard.cpp +++ b/backends/platform/psp/pspkeyboard.cpp @@ -23,6 +23,9 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + //#define PSP_KB_SHELL /* Need a hack to properly load the keyboard from the PSP shell */ #ifdef PSP_KB_SHELL @@ -78,9 +81,9 @@ short PSPKeyboard::_modeChar[MODE_COUNT][5][6] = { }, { //numbers { K('1'), K('2'), K('3'), K('4'), K(0), K(0) }, - { C(F5), C(F8), C(F7), C(F6), C(F9), C(F10) }, + { C(F5), C(F6), C(F7), C(F8), C(F9), C(F10) }, { K('5'), K('6'), K('7'), K('8'), K(0), K(0) }, - { C(F1), C(F4), C(F3), C(F2), K(0), K(0) }, + { C(F1), C(F2), C(F3), C(F4), K(0), K(0) }, { K('\b'), K('0'), K(' '), K('9'), K(0), K(0) } }, { //symbols diff --git a/backends/platform/psp/psploader.cpp b/backends/platform/psp/psploader.cpp deleted file mode 100644 index 464e20770c..0000000000 --- a/backends/platform/psp/psploader.cpp +++ /dev/null @@ -1,732 +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(DYNAMIC_MODULES) && defined(__PSP__) - -#include <string.h> -#include <stdarg.h> -#include <stdio.h> -#include <malloc.h> -#include <unistd.h> -#include <sys/_default_fcntl.h> - -#include <psputils.h> - -#include "backends/platform/psp/psploader.h" -#include "backends/platform/psp/powerman.h" - -//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */ -//#define __PSP_DEBUG_PRINT__ - -#include "backends/platform/psp/trace.h" - -extern char __plugin_hole_start; // Indicates start of hole in program file for shorts -extern char __plugin_hole_end; // Indicates end of hole in program file -extern char _gp[]; // Value of gp register - -DECLARE_SINGLETON(ShortSegmentManager) // For singleton - -// Get rid of symbol table in memory -void DLObject::discard_symtab() { - DEBUG_ENTER_FUNC(); - free(_symtab); - free(_strtab); - _symtab = NULL; - _strtab = NULL; - _symbol_cnt = 0; -} - -// Unload all objects from memory -void DLObject::unload() { - DEBUG_ENTER_FUNC(); - discard_symtab(); - free(_segment); - _segment = NULL; - - if (_shortsSegment) { - ShortsMan.deleteSegment(_shortsSegment); - _shortsSegment = NULL; - } -} - -/** - * Follow the instruction of a relocation section. - * - * @param fd File Descriptor - * @param offset Offset into the File - * @param size Size of relocation section - * @param relSegment Base address of relocated segment in memory (memory offset) - * - */ -bool DLObject::relocate(int fd, unsigned long offset, unsigned long size, void *relSegment) { - DEBUG_ENTER_FUNC(); - Elf32_Rel *rel = NULL; // relocation entry - - // Allocate memory for relocation table - if (!(rel = (Elf32_Rel *)malloc(size))) { - PSP_ERROR("Out of memory."); - return false; - } - - // Read in our relocation table - if (lseek(fd, offset, SEEK_SET) < 0 || - read(fd, rel, size) != (ssize_t)size) { - PSP_ERROR("Relocation table load failed."); - free(rel); - return false; - } - - // Treat each relocation entry. Loop over all of them - int cnt = size / sizeof(*rel); - - PSP_DEBUG_PRINT("Loaded relocation table. %d entries. base address=%p\n", cnt, relSegment); - - bool seenHi16 = false; // For treating HI/LO16 commands - int firstHi16 = -1; // Mark the point of the first hi16 seen - Elf32_Addr ahl = 0; // Calculated addend - int a = 0; // Addend: taken from the target - - unsigned int *lastTarget = 0; // For processing hi16 when lo16 arrives - unsigned int relocation = 0; - int debugRelocs[10] = {0}; // For debugging - int extendedHi16 = 0; // Count extended hi16 treatments - Elf32_Addr lastHiSymVal = 0; - bool hi16InShorts = false; - -#define DEBUG_NUM 2 - - // Loop over relocation entries - for (int i = 0; i < cnt; i++) { - // Get the symbol this relocation entry is referring to - Elf32_Sym *sym = (Elf32_Sym *)(_symtab) + (REL_INDEX(rel[i].r_info)); - - // Get the target instruction in the code - unsigned int *target = (unsigned int *)((char *)relSegment + rel[i].r_offset); - - PSP_DEBUG_DO(unsigned int origTarget = *target); // Save for debugging - - // Act differently based on the type of relocation - switch (REL_TYPE(rel[i].r_info)) { - - case R_MIPS_HI16: // Absolute addressing. - if (sym->st_shndx < SHN_LOPROC && // Only shift for plugin section (ie. has a real section index) - firstHi16 < 0) { // Only process first in block of HI16s - firstHi16 = i; // Keep the first Hi16 we saw - seenHi16 = true; - ahl = (*target & 0xffff) << 16; // Take lower 16 bits shifted up - - lastHiSymVal = sym->st_value; - hi16InShorts = (ShortsMan.inGeneralSegment((char *)sym->st_value)); // Fix for problem with switching btw segments - if (debugRelocs[0]++ < DEBUG_NUM) // Print only a set number - PSP_DEBUG_PRINT("R_MIPS_HI16: i=%d, offset=%x, ahl = %x, target = %x\n", - i, rel[i].r_offset, ahl, *target); - } - break; - - case R_MIPS_LO16: // Absolute addressing. Needs a HI16 to come before it - if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. (ie. has a real section index) - if (!seenHi16) { // We MUST have seen HI16 first - PSP_ERROR("R_MIPS_LO16 w/o preceding R_MIPS_HI16 at relocation %d!\n", i); - free(rel); - return false; - } - - // Fix: bug in gcc makes LO16s connect to wrong HI16s sometimes (shorts and regular segment) - // Note that we can check the entire shorts segment because the executable's shorts don't belong to this plugin section - // and will be screened out above - bool lo16InShorts = ShortsMan.inGeneralSegment((char *)sym->st_value); - - // Correct the bug by getting the proper value in ahl (taken from the current symbol) - if ((hi16InShorts && !lo16InShorts) || (!hi16InShorts && lo16InShorts)) { - ahl -= (lastHiSymVal & 0xffff0000); // We assume gcc meant the same offset - ahl += (sym->st_value & 0xffff0000); - } - - ahl &= 0xffff0000; // Clean lower 16 bits for repeated LO16s - a = *target & 0xffff; // Take lower 16 bits of the target - a = (a << 16) >> 16; // Sign extend them - ahl += a; // Add lower 16 bits. AHL is now complete - - // Fix: we can have LO16 access to the short segment sometimes - if (lo16InShorts) { - relocation = ahl + _shortsSegment->getOffset(); // Add in the short segment offset - } else // It's in the regular segment - relocation = ahl + (Elf32_Addr)_segment; // Add in the new offset for the segment - - if (firstHi16 >= 0) { // We haven't treated the HI16s yet so do it now - for (int j = firstHi16; j < i; j++) { - if (REL_TYPE(rel[j].r_info) != R_MIPS_HI16) continue; // Skip over non-Hi16s - - lastTarget = (unsigned int *)((char *)relSegment + rel[j].r_offset); // get hi16 target - *lastTarget &= 0xffff0000; // Clear the lower 16 bits of the last target - *lastTarget |= (relocation >> 16) & 0xffff; // Take the upper 16 bits of the relocation - if (relocation & 0x8000)(*lastTarget)++; // Subtle: we need to add 1 to the HI16 in this case - } - firstHi16 = -1; // Reset so we'll know we treated it - } else { - extendedHi16++; - } - - *target &= 0xffff0000; // Clear the lower 16 bits of current target - *target |= relocation & 0xffff; // Take the lower 16 bits of the relocation - - if (debugRelocs[1]++ < DEBUG_NUM) - PSP_DEBUG_PRINT("R_MIPS_LO16: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n", - i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target); - if (lo16InShorts && debugRelocs[2]++ < DEBUG_NUM) - PSP_DEBUG_PRINT("R_MIPS_LO16s: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n", - i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target); - } - break; - - case R_MIPS_26: // Absolute addressing (for jumps and branches only) - if (sym->st_shndx < SHN_LOPROC) { // Only relocate for main segment - a = *target & 0x03ffffff; // Get 26 bits' worth of the addend - a = (a << 6) >> 6; // Sign extend a - relocation = ((a << 2) + (Elf32_Addr)_segment) >> 2; // a already points to the target. Subtract our offset - *target &= 0xfc000000; // Clean lower 26 target bits - *target |= (relocation & 0x03ffffff); - - if (debugRelocs[3]++ < DEBUG_NUM) - PSP_DEBUG_PRINT("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n", - i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target); - } else { - if (debugRelocs[4]++ < DEBUG_NUM) - PSP_DEBUG_PRINT("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n", - i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target); - } - break; - - case R_MIPS_GPREL16: // GP Relative addressing - if (_shortsSegment->getOffset() != 0 && // Only relocate if we shift the shorts section - ShortsMan.inGeneralSegment((char *)sym->st_value)) { // Only relocate things in the plugin hole - a = *target & 0xffff; // Get 16 bits' worth of the addend - a = (a << 16) >> 16; // Sign extend it - - relocation = a + _shortsSegment->getOffset(); - - *target &= 0xffff0000; // Clear the lower 16 bits of the target - *target |= relocation & 0xffff; - - if (debugRelocs[5]++ < DEBUG_NUM) - PSP_DEBUG_PRINT("R_MIPS_GPREL16: i=%d, a=%x, gpVal=%x, origTarget=%x, target=%x, offset=%x\n", - i, a, _gpVal, origTarget, *target, _shortsSegment->getOffset()); - } - - break; - - case R_MIPS_32: // Absolute addressing - if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. - a = *target; // Get full 32 bits of addend - - if (ShortsMan.inGeneralSegment((char *)sym->st_value)) // Check if we're in the shorts segment - relocation = a + _shortsSegment->getOffset(); // Shift by shorts offset - else // We're in the main section - relocation = a + (Elf32_Addr)_segment; // Shift by main offset - *target = relocation; - - if (debugRelocs[6]++ < DEBUG_NUM) - PSP_DEBUG_PRINT("R_MIPS_32: i=%d, a=%x, origTarget=%x, target=%x\n", i, a, origTarget, *target); - } - break; - - default: - PSP_ERROR("Unknown relocation type %x at relocation %d.\n", REL_TYPE(rel[i].r_info), i); - free(rel); - return false; - } - } - - PSP_DEBUG_PRINT("Done with relocation. extendedHi16=%d\n\n", extendedHi16); - - free(rel); - return true; -} - -bool DLObject::readElfHeader(int fd, Elf32_Ehdr *ehdr) { - DEBUG_ENTER_FUNC(); - // Start reading the elf header. Check for errors - if (read(fd, ehdr, sizeof(*ehdr)) != sizeof(*ehdr) || - memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || // Check MAGIC - ehdr->e_type != ET_EXEC || // Check for executable - ehdr->e_machine != EM_MIPS || // Check for MIPS machine type - ehdr->e_phentsize < sizeof(Elf32_Phdr) || // Check for size of program header - ehdr->e_shentsize != sizeof(Elf32_Shdr)) { // Check for size of section header - PSP_ERROR("Invalid file type."); - return false; - } - - PSP_DEBUG_PRINT("phoff = %d, phentsz = %d, phnum = %d\n", - ehdr->e_phoff, ehdr->e_phentsize, ehdr->e_phnum); - - return true; -} - -bool DLObject::readProgramHeaders(int fd, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num) { - DEBUG_ENTER_FUNC(); - // Read program header - if (lseek(fd, ehdr->e_phoff + sizeof(*phdr)*num, SEEK_SET) < 0 || - read(fd, phdr, sizeof(*phdr)) != sizeof(*phdr)) { - PSP_ERROR("Program header load failed."); - return false; - } - - // Check program header values - if (phdr->p_type != PT_LOAD || phdr->p_filesz > phdr->p_memsz) { - PSP_ERROR("Invalid program header."); - return false; - } - - PSP_DEBUG_PRINT("offs = %x, filesz = %x, memsz = %x, align = %x\n", - phdr->p_offset, phdr->p_filesz, phdr->p_memsz, phdr->p_align); - - return true; - -} - -bool DLObject::loadSegment(int fd, Elf32_Phdr *phdr) { - DEBUG_ENTER_FUNC(); - - char *baseAddress = 0; - - // We need to take account of non-allocated segment for shorts - if (phdr->p_flags & PF_X) { // This is a relocated segment - - // Attempt to allocate memory for segment - int extra = phdr->p_vaddr % phdr->p_align; // Get extra length TODO: check logic here - PSP_DEBUG_PRINT("extra mem is %x\n", extra); - - if (phdr->p_align < 0x10000) phdr->p_align = 0x10000; // Fix for wrong alignment on e.g. AGI - - if (!(_segment = (char *)memalign(phdr->p_align, phdr->p_memsz + extra))) { - PSP_ERROR("Out of memory.\n"); - return false; - } - PSP_DEBUG_PRINT("allocated segment @ %p\n", _segment); - - // Get offset to load segment into - baseAddress = (char *)_segment + phdr->p_vaddr; - _segmentSize = phdr->p_memsz + extra; - } else { // This is a shorts section. - _shortsSegment = ShortsMan.newSegment(phdr->p_memsz, (char *)phdr->p_vaddr); - - baseAddress = _shortsSegment->getStart(); - PSP_DEBUG_PRINT("shorts segment @ %p to %p. Segment wants to be at %x. Offset=%x\n", - _shortsSegment->getStart(), _shortsSegment->getEnd(), phdr->p_vaddr, _shortsSegment->getOffset()); - - } - - // Set bss segment to 0 if necessary (assumes bss is at the end) - if (phdr->p_memsz > phdr->p_filesz) { - PSP_DEBUG_PRINT("Setting %p to %p to 0 for bss\n", baseAddress + phdr->p_filesz, baseAddress + phdr->p_memsz); - memset(baseAddress + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); - } - // Read the segment into memory - if (lseek(fd, phdr->p_offset, SEEK_SET) < 0 || - read(fd, baseAddress, phdr->p_filesz) != (ssize_t)phdr->p_filesz) { - PSP_ERROR("Segment load failed."); - return false; - } - - return true; -} - - -Elf32_Shdr * DLObject::loadSectionHeaders(int fd, Elf32_Ehdr *ehdr) { - DEBUG_ENTER_FUNC(); - - Elf32_Shdr *shdr = NULL; - - // Allocate memory for section headers - if (!(shdr = (Elf32_Shdr *)malloc(ehdr->e_shnum * sizeof(*shdr)))) { - PSP_ERROR("Out of memory."); - return NULL; - } - - // Read from file into section headers - if (lseek(fd, ehdr->e_shoff, SEEK_SET) < 0 || - read(fd, shdr, ehdr->e_shnum * sizeof(*shdr)) != - (ssize_t)(ehdr->e_shnum * sizeof(*shdr))) { - PSP_ERROR("Section headers load failed."); - return NULL; - } - - return shdr; -} - -int DLObject::loadSymbolTable(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) { - DEBUG_ENTER_FUNC(); - - // Loop over sections, looking for symbol table linked to a string table - for (int i = 0; i < ehdr->e_shnum; i++) { - PSP_DEBUG_PRINT("Section %d: type = %x, size = %x, entsize = %x, link = %x\n", - i, shdr[i].sh_type, shdr[i].sh_size, shdr[i].sh_entsize, shdr[i].sh_link); - - if (shdr[i].sh_type == SHT_SYMTAB && - shdr[i].sh_entsize == sizeof(Elf32_Sym) && - shdr[i].sh_link < ehdr->e_shnum && - shdr[shdr[i].sh_link].sh_type == SHT_STRTAB && - _symtab_sect < 0) { - _symtab_sect = i; - } - } - - // Check for no symbol table - if (_symtab_sect < 0) { - PSP_ERROR("No symbol table."); - return -1; - } - - PSP_DEBUG_PRINT("Symbol section at section %d, size %x\n", _symtab_sect, shdr[_symtab_sect].sh_size); - - // Allocate memory for symbol table - if (!(_symtab = malloc(shdr[_symtab_sect].sh_size))) { - PSP_ERROR("Out of memory."); - return -1; - } - - // Read symbol table into memory - if (lseek(fd, shdr[_symtab_sect].sh_offset, SEEK_SET) < 0 || - read(fd, _symtab, shdr[_symtab_sect].sh_size) != - (ssize_t)shdr[_symtab_sect].sh_size) { - PSP_ERROR("Symbol table load failed."); - return -1; - } - - // Set number of symbols - _symbol_cnt = shdr[_symtab_sect].sh_size / sizeof(Elf32_Sym); - PSP_DEBUG_PRINT("Loaded %d symbols.\n", _symbol_cnt); - - return _symtab_sect; - -} - -bool DLObject::loadStringTable(int fd, Elf32_Shdr *shdr) { - DEBUG_ENTER_FUNC(); - - int string_sect = shdr[_symtab_sect].sh_link; - - // Allocate memory for string table - if (!(_strtab = (char *)malloc(shdr[string_sect].sh_size))) { - PSP_ERROR("Out of memory."); - return false; - } - - // Read string table into memory - if (lseek(fd, shdr[string_sect].sh_offset, SEEK_SET) < 0 || - read(fd, _strtab, shdr[string_sect].sh_size) != - (ssize_t)shdr[string_sect].sh_size) { - PSP_ERROR("Symbol table strings load failed."); - return false; - } - return true; -} - -void DLObject::relocateSymbols(Elf32_Addr offset, Elf32_Addr shortsOffset) { - DEBUG_ENTER_FUNC(); - - int shortsCount = 0, othersCount = 0; - PSP_DEBUG_PRINT("Relocating symbols by %x. Shorts offset=%x\n", offset, shortsOffset); - - // Loop over symbols, add relocation offset - Elf32_Sym *s = (Elf32_Sym *)_symtab; - for (int c = _symbol_cnt; c--; s++) { - // Make sure we don't relocate special valued symbols - if (s->st_shndx < SHN_LOPROC) { - if (!ShortsMan.inGeneralSegment((char *)s->st_value)) { - othersCount++; - s->st_value += offset; - if (s->st_value < (Elf32_Addr)_segment || s->st_value > (Elf32_Addr)_segment + _segmentSize) - PSP_ERROR("Symbol out of bounds! st_value = %x\n", s->st_value); - } else { // shorts section - shortsCount++; - s->st_value += shortsOffset; - if (!_shortsSegment->inSegment((char *)s->st_value)) - PSP_ERROR("Symbol out of bounds! st_value = %x\n", s->st_value); - } - - } - - } - - PSP_DEBUG_PRINT("Relocated %d short symbols, %d others.\n", shortsCount, othersCount); -} - -bool DLObject::relocateRels(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) { - DEBUG_ENTER_FUNC(); - - // Loop over sections, finding relocation sections - for (int i = 0; i < ehdr->e_shnum; i++) { - - Elf32_Shdr *curShdr = &(shdr[i]); - //Elf32_Shdr *linkShdr = &(shdr[curShdr->sh_info]); - - if (curShdr->sh_type == SHT_REL && // Check for a relocation section - curShdr->sh_entsize == sizeof(Elf32_Rel) && // Check for proper relocation size - (int)curShdr->sh_link == _symtab_sect && // Check that the sh_link connects to our symbol table - curShdr->sh_info < ehdr->e_shnum && // Check that the relocated section exists - (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { // Check if relocated section resides in memory - if (!ShortsMan.inGeneralSegment((char *)shdr[curShdr->sh_info].sh_addr)) { // regular segment - if (!relocate(fd, curShdr->sh_offset, curShdr->sh_size, _segment)) { - return false; - } - } else { // In Shorts segment - if (!relocate(fd, curShdr->sh_offset, curShdr->sh_size, (void *)_shortsSegment->getOffset())) { - return false; - } - } - - } - } - - return true; -} - - -bool DLObject::load(int fd) { - DEBUG_ENTER_FUNC(); - - Elf32_Ehdr ehdr; // ELF header - Elf32_Phdr phdr; // Program header - Elf32_Shdr *shdr; // Section header - bool ret = true; - - if (readElfHeader(fd, &ehdr) == false) { - return false; - } - - for (int i = 0; i < ehdr.e_phnum; i++) { // Load our 2 segments - PSP_DEBUG_PRINT("Loading segment %d\n", i); - - if (readProgramHeaders(fd, &ehdr, &phdr, i) == false) - return false; - - if (!loadSegment(fd, &phdr)) - return false; - } - - if ((shdr = loadSectionHeaders(fd, &ehdr)) == NULL) - ret = false; - - if (ret && ((_symtab_sect = loadSymbolTable(fd, &ehdr, shdr)) < 0)) - ret = false; - - if (ret && (loadStringTable(fd, shdr) == false)) - ret = false; - - if (ret) - relocateSymbols((Elf32_Addr)_segment, _shortsSegment->getOffset()); // Offset by our segment allocated address - - if (ret && (relocateRels(fd, &ehdr, shdr) == false)) - ret = false; - - free(shdr); - - return ret; -} - -bool DLObject::open(const char *path) { - DEBUG_ENTER_FUNC(); - int fd; - void *ctors_start, *ctors_end; - - PSP_DEBUG_PRINT("open(\"%s\")\n", path); - - // Get the address of the global pointer - _gpVal = (unsigned int) & _gp; - PSP_DEBUG_PRINT("_gpVal is %x\n", _gpVal); - - PowerMan.beginCriticalSection(); - - if ((fd = ::open(path, O_RDONLY)) < 0) { - PSP_ERROR("%s not found.", path); - return false; - } - - // Try to load and relocate - if (!load(fd)) { - ::close(fd); - unload(); - return false; - } - - ::close(fd); - - PowerMan.endCriticalSection(); - - // flush data cache - sceKernelDcacheWritebackAll(); - - // Get the symbols for the global constructors and destructors - ctors_start = symbol("___plugin_ctors"); - ctors_end = symbol("___plugin_ctors_end"); - _dtors_start = symbol("___plugin_dtors"); - _dtors_end = symbol("___plugin_dtors_end"); - - if (ctors_start == NULL || ctors_end == NULL || _dtors_start == NULL || - _dtors_end == NULL) { - PSP_ERROR("Missing ctors/dtors."); - _dtors_start = _dtors_end = NULL; - unload(); - return false; - } - - PSP_DEBUG_PRINT("Calling constructors.\n"); - for (void (**f)(void) = (void (**)(void))ctors_start; f != ctors_end; f++) - (**f)(); - - PSP_DEBUG_PRINT("%s opened ok.\n", path); - return true; -} - -bool DLObject::close() { - DEBUG_ENTER_FUNC(); - if (_dtors_start != NULL && _dtors_end != NULL) - for (void (**f)(void) = (void (**)(void))_dtors_start; f != _dtors_end; f++) - (**f)(); - _dtors_start = _dtors_end = NULL; - unload(); - return true; -} - -void *DLObject::symbol(const char *name) { - DEBUG_ENTER_FUNC(); - PSP_DEBUG_PRINT("symbol(\"%s\")\n", name); - - if (_symtab == NULL || _strtab == NULL || _symbol_cnt < 1) { - PSP_ERROR("No symbol table loaded."); - return NULL; - } - - Elf32_Sym *s = (Elf32_Sym *)_symtab; - for (int c = _symbol_cnt; c--; s++) { - - // We can only import symbols that are global or weak in the plugin - if ((SYM_BIND(s->st_info) == STB_GLOBAL || SYM_BIND(s->st_info) == STB_WEAK) && - /*_strtab[s->st_name] == '_' && */ // Try to make this more efficient - !strcmp(name, _strtab + s->st_name)) { - - // We found the symbol - PSP_DEBUG_PRINT("=> %p\n", (void*)s->st_value); - return (void*)s->st_value; - } - } - - PSP_ERROR("Symbol \"%s\" not found.", name); - return NULL; -} - - - -ShortSegmentManager::ShortSegmentManager() { - DEBUG_ENTER_FUNC(); - _shortsStart = &__plugin_hole_start ; - _shortsEnd = &__plugin_hole_end; -} - -ShortSegmentManager::Segment *ShortSegmentManager::newSegment(int size, char *origAddr) { - DEBUG_ENTER_FUNC(); - char *lastAddress = origAddr; - Common::List<Segment *>::iterator i; - - // Find a block that fits, starting from the beginning - for (i = _list.begin(); i != _list.end(); ++i) { - char *currAddress = (*i)->getStart(); - - if ((int)(currAddress - lastAddress) >= size) break; - - lastAddress = (*i)->getEnd(); - } - - if ((Elf32_Addr)lastAddress & 3) - lastAddress += 4 - ((Elf32_Addr)lastAddress & 3); // Round up to multiple of 4 - - if (lastAddress + size > _shortsEnd) { - PSP_ERROR("No space in shorts segment for %x bytes. Last address is %p, max address is %p.\n", - size, lastAddress, _shortsEnd); - return NULL; - } - - Segment *seg = new Segment(lastAddress, size, origAddr); // Create a new segment - - if (lastAddress + size > _highestAddress) _highestAddress = lastAddress + size; // Keep track of maximum - - _list.insert(i, seg); - - PSP_DEBUG_PRINT("Shorts segment size %x allocated. End = %p. Remaining space = %x. Highest so far is %p.\n", - size, lastAddress + size, _shortsEnd - _list.back()->getEnd(), _highestAddress); - - return seg; -} - -void ShortSegmentManager::deleteSegment(ShortSegmentManager::Segment *seg) { - DEBUG_ENTER_FUNC(); - PSP_DEBUG_PRINT("Deleting shorts segment from %p to %p.\n\n", seg->getStart(), seg->getEnd()); - _list.remove(seg); - delete seg; -} - -static char dlerr[MAXDLERRLEN]; - -void *dlopen(const char *filename, int flags) { - DLObject *obj = new DLObject(dlerr); - if (obj->open(filename)) - return (void *)obj; - delete obj; - return NULL; -} - -int dlclose(void *handle) { - DLObject *obj = (DLObject *)handle; - if (obj == NULL) { - strcpy(dlerr, "Handle is NULL."); - return -1; - } - if (obj->close()) { - delete obj; - return 0; - } - return -1; -} - -void *dlsym(void *handle, const char *symbol) { - if (handle == NULL) { - strcpy(dlerr, "Handle is NULL."); - return NULL; - } - return ((DLObject *)handle)->symbol(symbol); -} - -const char *dlerror() { - return dlerr; -} - -void dlforgetsyms(void *handle) { - if (handle != NULL) - ((DLObject *)handle)->discard_symtab(); -} - - -#endif /* DYNAMIC_MODULES && __PSP__ */ diff --git a/backends/platform/psp/psploader.h b/backends/platform/psp/psploader.h deleted file mode 100644 index 13dcf6ef98..0000000000 --- a/backends/platform/psp/psploader.h +++ /dev/null @@ -1,137 +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$ - * - */ - -#ifndef PSPLOADER_H -#define PSPLOADER_H - -#include "elf32.h" -#include "common/list.h" -#include "common/singleton.h" - -#define MAXDLERRLEN 80 - -#define ShortsMan ShortSegmentManager::instance() - -class ShortSegmentManager : public Common::Singleton<ShortSegmentManager> { -private: - char *_shortsStart; - char *_shortsEnd; - -public: - char *getShortsStart() { - return _shortsStart; - } - bool inGeneralSegment(char *addr) { - return ((char *)addr >= _shortsStart && (char *)addr < _shortsEnd); - } - - class Segment { - private: - friend class ShortSegmentManager; - Segment(char *start, int size, char *origAddr) : _startAddress(start), _size(size), _origAddress(origAddr) {} - ~Segment() {} - char *_startAddress; // Start of shorts segment in memory - int _size; // Size of shorts segment - char *_origAddress; // Original address this segment was supposed to be at - public: - char *getStart() { - return _startAddress; - } - char *getEnd() { - return (_startAddress + _size); - } - Elf32_Addr getOffset() { - return (Elf32_Addr)(_startAddress - _origAddress); - } - bool inSegment(char *addr) { - return ((char *)addr >= _startAddress && (char *)addr <= _startAddress + _size); - } - }; - - Segment *newSegment(int size, char *origAddr); - void deleteSegment(Segment *); - -private: - ShortSegmentManager(); - friend class Common::Singleton<ShortSegmentManager>; - Common::List<Segment *> _list; - char *_highestAddress; -}; - - - - -class DLObject { -protected: - char *_errbuf; /* For error messages, at least MAXDLERRLEN in size */ - - ShortSegmentManager::Segment *_shortsSegment; // For assigning shorts ranges - void *_segment, *_symtab; - char *_strtab; - int _symbol_cnt; - int _symtab_sect; - void *_dtors_start, *_dtors_end; - - unsigned int _gpVal; // Value of Global Pointer - int _segmentSize; - - void seterror(const char *fmt, ...); - void unload(); - bool relocate(int fd, unsigned long offset, unsigned long size, void *); - bool load(int fd); - - bool readElfHeader(int fd, Elf32_Ehdr *ehdr); - bool readProgramHeaders(int fd, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num); - bool loadSegment(int fd, Elf32_Phdr *phdr); - Elf32_Shdr *loadSectionHeaders(int fd, Elf32_Ehdr *ehdr); - int loadSymbolTable(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); - bool loadStringTable(int fd, Elf32_Shdr *shdr); - void relocateSymbols(Elf32_Addr offset, Elf32_Addr shortsOffset); - bool relocateRels(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); - -public: - bool open(const char *path); - bool close(); - void *symbol(const char *name); - void discard_symtab(); - - DLObject(char *errbuf = NULL) : _errbuf(_errbuf), _shortsSegment(NULL), _segment(NULL), _symtab(NULL), - _strtab(NULL), _symbol_cnt(0), _symtab_sect(-1), _dtors_start(NULL), _dtors_end(NULL), _gpVal(0) , - _segmentSize(0) {} -}; - - - -#define RTLD_LAZY 0 - -extern "C" { - void *dlopen(const char *filename, int flags); - int dlclose(void *handle); - void *dlsym(void *handle, const char *symbol); - const char *dlerror(); - void dlforgetsyms(void *handle); -} - -#endif /* PSPLOADER_H */ diff --git a/backends/platform/samsungtv/events.cpp b/backends/platform/samsungtv/events.cpp new file mode 100644 index 0000000000..af39e67fe5 --- /dev/null +++ b/backends/platform/samsungtv/events.cpp @@ -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$ + * + */ + +#include "backends/platform/samsungtv/samsungtv.h" +#include "common/util.h" +#include "common/events.h" + +#if defined(SAMSUNGTV) + +bool OSystem_SDL_SamsungTV::remapKey(SDL_Event &ev, Common::Event &event) { + switch (ev.type) { + case SDL_KEYDOWN:{ + if (ev.key.keysym.sym == SDLK_POWER) { + event.type = Common::EVENT_QUIT; + return true; + } else if (ev.key.keysym.sym == SDLK_F1 && ev.key.keysym.scancode == 20) { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_F5; + event.kbd.ascii = Common::ASCII_F5; + return true; + } else if (ev.key.keysym.sym == SDLK_F2 && ev.key.keysym.scancode == 21) { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_F7; + event.kbd.ascii = Common::ASCII_F7; + return true; + } + break; + } + case SDL_KEYUP: { + if (ev.key.keysym.sym == SDLK_POWER) { + event.type = Common::EVENT_QUIT; + return true; + } else if (ev.key.keysym.sym == SDLK_F1 && ev.key.keysym.scancode == 20) { + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = Common::KEYCODE_F5; + event.kbd.ascii = Common::ASCII_F5; + return true; + } else if (ev.key.keysym.sym == SDLK_F2 && ev.key.keysym.scancode == 21) { + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = Common::KEYCODE_F7; + event.kbd.ascii = Common::ASCII_F7; + return true; + } + break; + } + } + + return false; +} + +#endif diff --git a/backends/platform/samsungtv/main.cpp b/backends/platform/samsungtv/main.cpp index f3d868641b..2c025b750c 100644 --- a/backends/platform/samsungtv/main.cpp +++ b/backends/platform/samsungtv/main.cpp @@ -34,23 +34,16 @@ extern "C" int Game_Main(char *path, char *) { chdir(path); - // Create OSystem instance g_system = new OSystem_SDL_SamsungTV(); assert(g_system); - // Pre initialize the backend - ((OSystem_SDL_SamsungTV *)g_system)->init(); - #ifdef DYNAMIC_MODULES PluginManager::instance().addPluginProvider(new SDLPluginProvider()); #endif // Invoke the actual ScummVM main entry point: int res = scummvm_main(0, 0); - - // Free OSystem - delete (OSystem_SDL_SamsungTV *)g_system; - + ((OSystem_SDL *)g_system)->deinit(); return res; } diff --git a/backends/platform/samsungtv/module.mk b/backends/platform/samsungtv/module.mk index 36ad75da6d..d7ebe75080 100644 --- a/backends/platform/samsungtv/module.mk +++ b/backends/platform/samsungtv/module.mk @@ -1,6 +1,7 @@ MODULE := backends/platform/samsungtv MODULE_OBJS := \ + events.o \ main.o \ samsungtv.o diff --git a/backends/platform/samsungtv/samsungtv.cpp b/backends/platform/samsungtv/samsungtv.cpp index 1e316aa840..aa79b92558 100644 --- a/backends/platform/samsungtv/samsungtv.cpp +++ b/backends/platform/samsungtv/samsungtv.cpp @@ -24,32 +24,19 @@ */ #include "backends/platform/samsungtv/samsungtv.h" -#include "backends/events/samsungtvsdl/samsungtvsdl-events.h" -OSystem_SDL_SamsungTV::OSystem_SDL_SamsungTV() - : - OSystem_POSIX("/dtv/usb/sda1/.scummvmrc") { -} +#if defined(SAMSUNGTV) bool OSystem_SDL_SamsungTV::hasFeature(Feature f) { return - (f == OSystem::kFeatureAspectRatioCorrection) || - (f == OSystem::kFeatureCursorHasPalette); -} - -void OSystem_SDL_SamsungTV::initBackend() { - // Create the events manager - if (_eventManager == 0) - _eventManager = new SamsungTVSdlEventManager(this); - - // Call parent implementation of this method - OSystem_SDL::initBackend(); + (f == kFeatureAspectRatioCorrection) || + (f == kFeatureCursorHasPalette); } void OSystem_SDL_SamsungTV::setFeatureState(Feature f, bool enable) { switch (f) { - case OSystem::kFeatureAspectRatioCorrection: - _graphicsManager->setFeatureState(f, enable); + case kFeatureAspectRatioCorrection: + setAspectRatioCorrection(enable); break; default: break; @@ -57,14 +44,14 @@ void OSystem_SDL_SamsungTV::setFeatureState(Feature f, bool enable) { } bool OSystem_SDL_SamsungTV::getFeatureState(Feature f) { + assert (_transactionMode == kTransactionNone); + switch (f) { - case OSystem::kFeatureAspectRatioCorrection: - return _graphicsManager->getFeatureState(f); + case kFeatureAspectRatioCorrection: + return _videoMode.aspectRatioCorrection; default: return false; } } -void OSystem_SDL_SamsungTV::quit() { - deinit(); -} +#endif diff --git a/backends/platform/samsungtv/samsungtv.h b/backends/platform/samsungtv/samsungtv.h index 49460a9ddc..b3344385aa 100644 --- a/backends/platform/samsungtv/samsungtv.h +++ b/backends/platform/samsungtv/samsungtv.h @@ -23,22 +23,31 @@ * */ -#ifndef PLATFORM_SDL_SAMSUNGTV_H -#define PLATFORM_SDL_SAMSUNGTV_H +#ifndef SDL_SAMSUNGTV_COMMON_H +#define SDL_SAMSUNGTV_COMMON_H -#include "backends/platform/sdl/posix/posix.h" +#include <SDL.h> -class OSystem_SDL_SamsungTV : public OSystem_POSIX { -public: - OSystem_SDL_SamsungTV(); +#include "backends/base-backend.h" +#include "backends/platform/sdl/sdl.h" + +#if defined(SAMSUNGTV) - virtual void initBackend(); +namespace Audio { + class MixerImpl; +} +class OSystem_SDL_SamsungTV : public OSystem_SDL { +public: virtual bool hasFeature(Feature f); virtual void setFeatureState(Feature f, bool enable); virtual bool getFeatureState(Feature f); - virtual void quit(); +protected: + + virtual bool remapKey(SDL_Event &ev, Common::Event &event); }; #endif + +#endif diff --git a/backends/platform/sdl/amigaos/amigaos-main.cpp b/backends/platform/sdl/amigaos/amigaos-main.cpp deleted file mode 100644 index db4598e879..0000000000 --- a/backends/platform/sdl/amigaos/amigaos-main.cpp +++ /dev/null @@ -1,54 +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(__amigaos4__) - -#include "backends/platform/sdl/amigaos/amigaos.h" -#include "backends/plugins/sdl/sdl-provider.h" -#include "base/main.h" - -int main(int argc, char *argv[]) { - - // Create our OSystem instance - g_system = new OSystem_AmigaOS(); - assert(g_system); - - // Pre initialize the backend - ((OSystem_AmigaOS *)g_system)->init(); - -#ifdef DYNAMIC_MODULES - PluginManager::instance().addPluginProvider(new SDLPluginProvider()); -#endif - - // Invoke the actual ScummVM main entry point: - int res = scummvm_main(argc, argv); - - // Free OSystem - delete (OSystem_AmigaOS *)g_system; - - return res; -} - -#endif diff --git a/backends/platform/sdl/amigaos/amigaos.cpp b/backends/platform/sdl/amigaos/amigaos.cpp deleted file mode 100644 index d2924445a3..0000000000 --- a/backends/platform/sdl/amigaos/amigaos.cpp +++ /dev/null @@ -1,39 +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$ - * - */ - -#ifdef __amigaos4__ - -#include "backends/platform/sdl/amigaos/amigaos.h" -#include "backends/fs/amigaos4/amigaos4-fs-factory.h" - -void OSystem_AmigaOS::init() { - // Initialze File System Factory - _fsFactory = new AmigaOSFilesystemFactory(); - - // Invoke parent implementation of this method - OSystem_SDL::init(); -} - -#endif diff --git a/backends/platform/sdl/amigaos/amigaos.h b/backends/platform/sdl/amigaos/amigaos.h deleted file mode 100644 index 92232ec98a..0000000000 --- a/backends/platform/sdl/amigaos/amigaos.h +++ /dev/null @@ -1,39 +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$ - * - */ - -#ifndef PLATFORM_SDL_AMIGAOS_H -#define PLATFORM_SDL_AMIGAOS_H - -#include "backends/platform/sdl/sdl.h" - -class OSystem_AmigaOS : public OSystem_SDL { -public: - OSystem_AmigaOS() {} - virtual ~OSystem_AmigaOS() {} - - virtual void init(); -}; - -#endif diff --git a/backends/platform/sdl/events.cpp b/backends/platform/sdl/events.cpp new file mode 100644 index 0000000000..1c1d82730f --- /dev/null +++ b/backends/platform/sdl/events.cpp @@ -0,0 +1,573 @@ +/* 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 "backends/platform/sdl/sdl.h" +#include "common/util.h" +#include "common/events.h" +#include "graphics/scaler/aspect.h" // for aspect2Real + +// FIXME move joystick defines out and replace with confile file options +// we should really allow users to map any key to a joystick button +#define JOY_DEADZONE 3200 + +#ifndef __SYMBIAN32__ // Symbian wants dialog joystick i.e cursor for movement/selection + #define JOY_ANALOG +#endif + +// #define JOY_INVERT_Y +#define JOY_XAXIS 0 +#define JOY_YAXIS 1 +// buttons +#define JOY_BUT_LMOUSE 0 +#define JOY_BUT_RMOUSE 2 +#define JOY_BUT_ESCAPE 3 +#define JOY_BUT_PERIOD 1 +#define JOY_BUT_SPACE 4 +#define JOY_BUT_F5 5 + + + + +static int mapKey(SDLKey key, SDLMod mod, Uint16 unicode) { + if (key >= SDLK_F1 && key <= SDLK_F9) { + return key - SDLK_F1 + Common::ASCII_F1; + } else if (key >= SDLK_KP0 && key <= SDLK_KP9) { + return key - SDLK_KP0 + '0'; + } else if (key >= SDLK_UP && key <= SDLK_PAGEDOWN) { + return key; + } else if (unicode) { + return unicode; + } else if (key >= 'a' && key <= 'z' && (mod & KMOD_SHIFT)) { + return key & ~0x20; + } else if (key >= SDLK_NUMLOCK && key <= SDLK_EURO) { + return 0; + } + return key; +} + +void OSystem_SDL::fillMouseEvent(Common::Event &event, int x, int y) { + event.mouse.x = x; + event.mouse.y = y; + + // Update the "keyboard mouse" coords + _km.x = x; + _km.y = y; + + // Adjust for the screen scaling + if (!_overlayVisible) { + event.mouse.x /= _videoMode.scaleFactor; + event.mouse.y /= _videoMode.scaleFactor; + if (_videoMode.aspectRatioCorrection) + event.mouse.y = aspect2Real(event.mouse.y); + } +} + +void OSystem_SDL::handleKbdMouse() { + uint32 curTime = getMillis(); + if (curTime >= _km.last_time + _km.delay_time) { + _km.last_time = curTime; + if (_km.x_down_count == 1) { + _km.x_down_time = curTime; + _km.x_down_count = 2; + } + if (_km.y_down_count == 1) { + _km.y_down_time = curTime; + _km.y_down_count = 2; + } + + if (_km.x_vel || _km.y_vel) { + if (_km.x_down_count) { + if (curTime > _km.x_down_time + _km.delay_time * 12) { + if (_km.x_vel > 0) + _km.x_vel++; + else + _km.x_vel--; + } else if (curTime > _km.x_down_time + _km.delay_time * 8) { + if (_km.x_vel > 0) + _km.x_vel = 5; + else + _km.x_vel = -5; + } + } + if (_km.y_down_count) { + if (curTime > _km.y_down_time + _km.delay_time * 12) { + if (_km.y_vel > 0) + _km.y_vel++; + else + _km.y_vel--; + } else if (curTime > _km.y_down_time + _km.delay_time * 8) { + if (_km.y_vel > 0) + _km.y_vel = 5; + else + _km.y_vel = -5; + } + } + + _km.x += _km.x_vel; + _km.y += _km.y_vel; + + if (_km.x < 0) { + _km.x = 0; + _km.x_vel = -1; + _km.x_down_count = 1; + } else if (_km.x > _km.x_max) { + _km.x = _km.x_max; + _km.x_vel = 1; + _km.x_down_count = 1; + } + + if (_km.y < 0) { + _km.y = 0; + _km.y_vel = -1; + _km.y_down_count = 1; + } else if (_km.y > _km.y_max) { + _km.y = _km.y_max; + _km.y_vel = 1; + _km.y_down_count = 1; + } + + SDL_WarpMouse((Uint16)_km.x, (Uint16)_km.y); + } + } +} + +static void SDLModToOSystemKeyFlags(SDLMod mod, Common::Event &event) { + + event.kbd.flags = 0; + +#ifdef LINUPY + // Yopy has no ALT key, steal the SHIFT key + // (which isn't used much anyway) + if (mod & KMOD_SHIFT) + event.kbd.flags |= Common::KBD_ALT; +#else + if (mod & KMOD_SHIFT) + event.kbd.flags |= Common::KBD_SHIFT; + if (mod & KMOD_ALT) + event.kbd.flags |= Common::KBD_ALT; +#endif + if (mod & KMOD_CTRL) + event.kbd.flags |= Common::KBD_CTRL; + + // Sticky flags + if (mod & KMOD_NUM) + event.kbd.flags |= Common::KBD_NUM; + if (mod & KMOD_CAPS) + event.kbd.flags |= Common::KBD_CAPS; +} + +bool OSystem_SDL::pollEvent(Common::Event &event) { + SDL_Event ev; + ev.type = SDL_NOEVENT; + + handleKbdMouse(); + + // If the screen mode changed, send an Common::EVENT_SCREEN_CHANGED + if (_modeChanged) { + _modeChanged = false; + event.type = Common::EVENT_SCREEN_CHANGED; + return true; + } + + while (SDL_PollEvent(&ev)) { + preprocessEvents(&ev); + if (dispatchSDLEvent(ev, event)) + return true; + } + return false; +} + +bool OSystem_SDL::dispatchSDLEvent(SDL_Event &ev, Common::Event &event) { + switch (ev.type) { + case SDL_KEYDOWN: + return handleKeyDown(ev, event); + case SDL_KEYUP: + return handleKeyUp(ev, event); + case SDL_MOUSEMOTION: + return handleMouseMotion(ev, event); + case SDL_MOUSEBUTTONDOWN: + return handleMouseButtonDown(ev, event); + case SDL_MOUSEBUTTONUP: + return handleMouseButtonUp(ev, event); + case SDL_JOYBUTTONDOWN: + return handleJoyButtonDown(ev, event); + case SDL_JOYBUTTONUP: + return handleJoyButtonUp(ev, event); + case SDL_JOYAXISMOTION: + return handleJoyAxisMotion(ev, event); + + case SDL_VIDEOEXPOSE: + _forceFull = true; + break; + + case SDL_QUIT: + event.type = Common::EVENT_QUIT; + return true; + + } + + return false; +} + + +bool OSystem_SDL::handleKeyDown(SDL_Event &ev, Common::Event &event) { + + SDLModToOSystemKeyFlags(SDL_GetModState(), event); + + // Handle scroll lock as a key modifier + if (ev.key.keysym.sym == SDLK_SCROLLOCK) + _scrollLock = !_scrollLock; + + if (_scrollLock) + event.kbd.flags |= Common::KBD_SCRL; + + // Alt-Return and Alt-Enter toggle full screen mode + if (event.kbd.hasFlags(Common::KBD_ALT) && (ev.key.keysym.sym == SDLK_RETURN || ev.key.keysym.sym == SDLK_KP_ENTER)) { + beginGFXTransaction(); + setFullscreenMode(!_videoMode.fullscreen); + endGFXTransaction(); +#ifdef USE_OSD + if (_videoMode.fullscreen) + displayMessageOnOSD("Fullscreen mode"); + else + displayMessageOnOSD("Windowed mode"); +#endif + + return false; + } + + // Alt-S: Create a screenshot + if (event.kbd.hasFlags(Common::KBD_ALT) && ev.key.keysym.sym == 's') { + char filename[20]; + + for (int n = 0;; n++) { + SDL_RWops *file; + + sprintf(filename, "scummvm%05d.bmp", n); + file = SDL_RWFromFile(filename, "r"); + if (!file) + break; + SDL_RWclose(file); + } + if (saveScreenshot(filename)) + printf("Saved '%s'\n", filename); + else + printf("Could not save screenshot!\n"); + return false; + } + + // Ctrl-m toggles mouse capture + if (event.kbd.hasFlags(Common::KBD_CTRL) && ev.key.keysym.sym == 'm') { + toggleMouseGrab(); + return false; + } + +#if defined(MACOSX) + // On Macintosh', Cmd-Q quits + if ((ev.key.keysym.mod & KMOD_META) && ev.key.keysym.sym == 'q') { + event.type = Common::EVENT_QUIT; + return true; + } +#elif defined(UNIX) + // On other unices, Control-Q quits + if ((ev.key.keysym.mod & KMOD_CTRL) && ev.key.keysym.sym == 'q') { + event.type = Common::EVENT_QUIT; + return true; + } +#else + // Ctrl-z and Alt-X quit + if ((event.kbd.hasFlags(Common::KBD_CTRL) && ev.key.keysym.sym == 'z') || (event.kbd.hasFlags(Common::KBD_ALT) && ev.key.keysym.sym == 'x')) { + event.type = Common::EVENT_QUIT; + return true; + } +#endif + + if ((ev.key.keysym.mod & KMOD_CTRL) && ev.key.keysym.sym == 'u') { + event.type = Common::EVENT_MUTE; + return true; + } + + // Ctrl-Alt-<key> will change the GFX mode + if ((event.kbd.flags & (Common::KBD_CTRL|Common::KBD_ALT)) == (Common::KBD_CTRL|Common::KBD_ALT)) { + if (handleScalerHotkeys(ev.key)) + return false; + } + + if (remapKey(ev, event)) + return true; + + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym; + event.kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode); + + return true; +} + +bool OSystem_SDL::handleKeyUp(SDL_Event &ev, Common::Event &event) { + if (remapKey(ev, event)) + return true; + + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym; + event.kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode); + + // Ctrl-Alt-<key> will change the GFX mode + SDLModToOSystemKeyFlags(SDL_GetModState(), event); + + // Set the scroll lock sticky flag + if (_scrollLock) + event.kbd.flags |= Common::KBD_SCRL; + + if (isScalerHotkey(event)) + // Swallow these key up events + return false; + + return true; +} + +bool OSystem_SDL::handleMouseMotion(SDL_Event &ev, Common::Event &event) { + event.type = Common::EVENT_MOUSEMOVE; + fillMouseEvent(event, ev.motion.x, ev.motion.y); + + setMousePos(event.mouse.x, event.mouse.y); + return true; +} + +bool OSystem_SDL::handleMouseButtonDown(SDL_Event &ev, Common::Event &event) { + 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; +#if defined(SDL_BUTTON_WHEELUP) && defined(SDL_BUTTON_WHEELDOWN) + else if (ev.button.button == SDL_BUTTON_WHEELUP) + event.type = Common::EVENT_WHEELUP; + else if (ev.button.button == SDL_BUTTON_WHEELDOWN) + event.type = Common::EVENT_WHEELDOWN; +#endif +#if defined(SDL_BUTTON_MIDDLE) + else if (ev.button.button == SDL_BUTTON_MIDDLE) + event.type = Common::EVENT_MBUTTONDOWN; +#endif + else + return false; + + fillMouseEvent(event, ev.button.x, ev.button.y); + + return true; +} + +bool OSystem_SDL::handleMouseButtonUp(SDL_Event &ev, Common::Event &event) { + 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; +#if defined(SDL_BUTTON_MIDDLE) + else if (ev.button.button == SDL_BUTTON_MIDDLE) + event.type = Common::EVENT_MBUTTONUP; +#endif + else + return false; + fillMouseEvent(event, ev.button.x, ev.button.y); + + return true; +} + +bool OSystem_SDL::handleJoyButtonDown(SDL_Event &ev, Common::Event &event) { + if (ev.jbutton.button == JOY_BUT_LMOUSE) { + event.type = Common::EVENT_LBUTTONDOWN; + fillMouseEvent(event, _km.x, _km.y); + } else if (ev.jbutton.button == JOY_BUT_RMOUSE) { + event.type = Common::EVENT_RBUTTONDOWN; + fillMouseEvent(event, _km.x, _km.y); + } else { + event.type = Common::EVENT_KEYDOWN; + switch (ev.jbutton.button) { + case JOY_BUT_ESCAPE: + event.kbd.keycode = Common::KEYCODE_ESCAPE; + event.kbd.ascii = mapKey(SDLK_ESCAPE, ev.key.keysym.mod, 0); + break; + case JOY_BUT_PERIOD: + event.kbd.keycode = Common::KEYCODE_PERIOD; + event.kbd.ascii = mapKey(SDLK_PERIOD, ev.key.keysym.mod, 0); + break; + case JOY_BUT_SPACE: + event.kbd.keycode = Common::KEYCODE_SPACE; + event.kbd.ascii = mapKey(SDLK_SPACE, ev.key.keysym.mod, 0); + break; + case JOY_BUT_F5: + event.kbd.keycode = Common::KEYCODE_F5; + event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0); + break; + } + } + return true; +} + +bool OSystem_SDL::handleJoyButtonUp(SDL_Event &ev, Common::Event &event) { + if (ev.jbutton.button == JOY_BUT_LMOUSE) { + event.type = Common::EVENT_LBUTTONUP; + fillMouseEvent(event, _km.x, _km.y); + } else if (ev.jbutton.button == JOY_BUT_RMOUSE) { + event.type = Common::EVENT_RBUTTONUP; + fillMouseEvent(event, _km.x, _km.y); + } else { + event.type = Common::EVENT_KEYUP; + switch (ev.jbutton.button) { + case JOY_BUT_ESCAPE: + event.kbd.keycode = Common::KEYCODE_ESCAPE; + event.kbd.ascii = mapKey(SDLK_ESCAPE, ev.key.keysym.mod, 0); + break; + case JOY_BUT_PERIOD: + event.kbd.keycode = Common::KEYCODE_PERIOD; + event.kbd.ascii = mapKey(SDLK_PERIOD, ev.key.keysym.mod, 0); + break; + case JOY_BUT_SPACE: + event.kbd.keycode = Common::KEYCODE_SPACE; + event.kbd.ascii = mapKey(SDLK_SPACE, ev.key.keysym.mod, 0); + break; + case JOY_BUT_F5: + event.kbd.keycode = Common::KEYCODE_F5; + event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0); + break; + } + } + return true; +} + +bool OSystem_SDL::handleJoyAxisMotion(SDL_Event &ev, Common::Event &event) { + int axis = ev.jaxis.value; + if ( axis > JOY_DEADZONE) { + axis -= JOY_DEADZONE; + event.type = Common::EVENT_MOUSEMOVE; + } else if ( axis < -JOY_DEADZONE ) { + axis += JOY_DEADZONE; + event.type = Common::EVENT_MOUSEMOVE; + } else + axis = 0; + + if ( ev.jaxis.axis == JOY_XAXIS) { +#ifdef JOY_ANALOG + _km.x_vel = axis/2000; + _km.x_down_count = 0; +#else + if (axis != 0) { + _km.x_vel = (axis > 0) ? 1:-1; + _km.x_down_count = 1; + } else { + _km.x_vel = 0; + _km.x_down_count = 0; + } +#endif + + } else if (ev.jaxis.axis == JOY_YAXIS) { +#ifndef JOY_INVERT_Y + axis = -axis; +#endif +#ifdef JOY_ANALOG + _km.y_vel = -axis / 2000; + _km.y_down_count = 0; +#else + if (axis != 0) { + _km.y_vel = (-axis > 0) ? 1: -1; + _km.y_down_count = 1; + } else { + _km.y_vel = 0; + _km.y_down_count = 0; + } +#endif + } + + fillMouseEvent(event, _km.x, _km.y); + + return true; +} + +bool OSystem_SDL::remapKey(SDL_Event &ev, Common::Event &event) { +#ifdef LINUPY + // On Yopy map the End button to quit + if ((ev.key.keysym.sym == 293)) { + event.type = Common::EVENT_QUIT; + return true; + } + // Map menu key to f5 (scumm menu) + if (ev.key.keysym.sym == 306) { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_F5; + event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0); + return true; + } + // Map action key to action + if (ev.key.keysym.sym == 291) { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_TAB; + event.kbd.ascii = mapKey(SDLK_TAB, ev.key.keysym.mod, 0); + return true; + } + // Map OK key to skip cinematic + if (ev.key.keysym.sym == 292) { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_ESCAPE; + event.kbd.ascii = mapKey(SDLK_ESCAPE, ev.key.keysym.mod, 0); + return true; + } +#endif + +#ifdef QTOPIA + // Quit on fn+backspace on zaurus + if (ev.key.keysym.sym == 127) { + event.type = Common::EVENT_QUIT; + return true; + } + + // Map menu key (f11) to f5 (scumm menu) + if (ev.key.keysym.sym == SDLK_F11) { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_F5; + event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0); + } + // Nap center (space) to tab (default action ) + // I wanted to map the calendar button but the calendar comes up + // + else if (ev.key.keysym.sym == SDLK_SPACE) { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_TAB; + event.kbd.ascii = mapKey(SDLK_TAB, ev.key.keysym.mod, 0); + } + // Since we stole space (pause) above we'll rebind it to the tab key on the keyboard + else if (ev.key.keysym.sym == SDLK_TAB) { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_SPACE; + event.kbd.ascii = mapKey(SDLK_SPACE, ev.key.keysym.mod, 0); + } else { + // Let the events fall through if we didn't change them, this may not be the best way to + // set it up, but i'm not sure how sdl would like it if we let if fall through then redid it though. + // and yes i have an huge terminal size so i dont wrap soon enough. + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = ev.key.keysym.sym; + event.kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode); + } +#endif + return false; +} diff --git a/backends/platform/sdl/graphics.cpp b/backends/platform/sdl/graphics.cpp new file mode 100644 index 0000000000..df63c3a7d6 --- /dev/null +++ b/backends/platform/sdl/graphics.cpp @@ -0,0 +1,1946 @@ +/* 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 "backends/platform/sdl/sdl.h" +#include "common/mutex.h" +#include "common/translation.h" +#include "common/util.h" +#ifdef USE_RGB_COLOR +#include "common/list.h" +#endif +#include "graphics/font.h" +#include "graphics/fontman.h" +#include "graphics/scaler.h" +#include "graphics/scaler/aspect.h" +#include "graphics/surface.h" + +static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { + {"1x", _s("Normal (no scaling)"), GFX_NORMAL}, +#ifdef USE_SCALERS + {"2x", "2x", GFX_DOUBLESIZE}, + {"3x", "3x", GFX_TRIPLESIZE}, + {"2xsai", "2xSAI", GFX_2XSAI}, + {"super2xsai", "Super2xSAI", GFX_SUPER2XSAI}, + {"supereagle", "SuperEagle", GFX_SUPEREAGLE}, + {"advmame2x", "AdvMAME2x", GFX_ADVMAME2X}, + {"advmame3x", "AdvMAME3x", GFX_ADVMAME3X}, +#ifdef USE_HQ_SCALERS + {"hq2x", "HQ2x", GFX_HQ2X}, + {"hq3x", "HQ3x", GFX_HQ3X}, +#endif + {"tv2x", "TV2x", GFX_TV2X}, + {"dotmatrix", "DotMatrix", GFX_DOTMATRIX}, +#endif + {0, 0, 0} +}; + +DECLARE_TRANSLATION_ADDITIONAL_CONTEXT("Normal (no scaling)", "lowres") + +// Table of relative scalers magnitudes +// [definedScale - 1][scaleFactor - 1] +static ScalerProc *scalersMagn[3][3] = { +#ifdef USE_SCALERS + { Normal1x, AdvMame2x, AdvMame3x }, + { Normal1x, Normal1x, Normal1o5x }, + { Normal1x, Normal1x, Normal1x } +#else // remove dependencies on other scalers + { Normal1x, Normal1x, Normal1x }, + { Normal1x, Normal1x, Normal1x }, + { Normal1x, Normal1x, Normal1x } +#endif +}; + +static const int s_gfxModeSwitchTable[][4] = { + { GFX_NORMAL, GFX_DOUBLESIZE, GFX_TRIPLESIZE, -1 }, + { GFX_NORMAL, GFX_ADVMAME2X, GFX_ADVMAME3X, -1 }, + { GFX_NORMAL, GFX_HQ2X, GFX_HQ3X, -1 }, + { GFX_NORMAL, GFX_2XSAI, -1, -1 }, + { GFX_NORMAL, GFX_SUPER2XSAI, -1, -1 }, + { GFX_NORMAL, GFX_SUPEREAGLE, -1, -1 }, + { GFX_NORMAL, GFX_TV2X, -1, -1 }, + { GFX_NORMAL, GFX_DOTMATRIX, -1, -1 } + }; + +#ifdef USE_SCALERS +static int cursorStretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY); +#endif + +const OSystem::GraphicsMode *OSystem_SDL::getSupportedGraphicsModes() const { + return s_supportedGraphicsModes; +} + +int OSystem_SDL::getDefaultGraphicsMode() const { + return GFX_DOUBLESIZE; +} + +void OSystem_SDL::beginGFXTransaction() { + assert(_transactionMode == kTransactionNone); + + _transactionMode = kTransactionActive; + + _transactionDetails.sizeChanged = false; + + _transactionDetails.needHotswap = false; + _transactionDetails.needUpdatescreen = false; + + _transactionDetails.normal1xScaler = false; +#ifdef USE_RGB_COLOR + _transactionDetails.formatChanged = false; +#endif + + _oldVideoMode = _videoMode; +} + +OSystem::TransactionError OSystem_SDL::endGFXTransaction() { + int errors = kTransactionSuccess; + + assert(_transactionMode != kTransactionNone); + + if (_transactionMode == kTransactionRollback) { + if (_videoMode.fullscreen != _oldVideoMode.fullscreen) { + errors |= kTransactionFullscreenFailed; + + _videoMode.fullscreen = _oldVideoMode.fullscreen; + } else if (_videoMode.aspectRatioCorrection != _oldVideoMode.aspectRatioCorrection) { + errors |= kTransactionAspectRatioFailed; + + _videoMode.aspectRatioCorrection = _oldVideoMode.aspectRatioCorrection; + } else if (_videoMode.mode != _oldVideoMode.mode) { + errors |= kTransactionModeSwitchFailed; + + _videoMode.mode = _oldVideoMode.mode; + _videoMode.scaleFactor = _oldVideoMode.scaleFactor; +#ifdef USE_RGB_COLOR + } else if (_videoMode.format != _oldVideoMode.format) { + errors |= kTransactionFormatNotSupported; + + _videoMode.format = _oldVideoMode.format; + _screenFormat = _videoMode.format; +#endif + } else if (_videoMode.screenWidth != _oldVideoMode.screenWidth || _videoMode.screenHeight != _oldVideoMode.screenHeight) { + errors |= kTransactionSizeChangeFailed; + + _videoMode.screenWidth = _oldVideoMode.screenWidth; + _videoMode.screenHeight = _oldVideoMode.screenHeight; + _videoMode.overlayWidth = _oldVideoMode.overlayWidth; + _videoMode.overlayHeight = _oldVideoMode.overlayHeight; + } + + if (_videoMode.fullscreen == _oldVideoMode.fullscreen && + _videoMode.aspectRatioCorrection == _oldVideoMode.aspectRatioCorrection && + _videoMode.mode == _oldVideoMode.mode && + _videoMode.screenWidth == _oldVideoMode.screenWidth && + _videoMode.screenHeight == _oldVideoMode.screenHeight) { + + // Our new video mode would now be exactly the same as the + // old one. Since we still can not assume SDL_SetVideoMode + // to be working fine, we need to invalidate the old video + // mode, so loadGFXMode would error out properly. + _oldVideoMode.setup = false; + } + } + +#ifdef USE_RGB_COLOR + if (_transactionDetails.sizeChanged || _transactionDetails.formatChanged) { +#else + if (_transactionDetails.sizeChanged) { +#endif + unloadGFXMode(); + if (!loadGFXMode()) { + if (_oldVideoMode.setup) { + _transactionMode = kTransactionRollback; + errors |= endGFXTransaction(); + } + } else { + setGraphicsModeIntern(); + clearOverlay(); + + _videoMode.setup = true; + _modeChanged = true; + // OSystem_SDL::pollEvent used to update the screen change count, + // but actually it gives problems when a video mode was changed + // but OSystem_SDL::pollEvent was not called. This for example + // caused a crash under certain circumstances when doing an RTL. + // To fix this issue we update the screen change count right here. + _screenChangeCount++; + } + } else if (_transactionDetails.needHotswap) { + setGraphicsModeIntern(); + if (!hotswapGFXMode()) { + if (_oldVideoMode.setup) { + _transactionMode = kTransactionRollback; + errors |= endGFXTransaction(); + } + } else { + _videoMode.setup = true; + _modeChanged = true; + // OSystem_SDL::pollEvent used to update the screen change count, + // but actually it gives problems when a video mode was changed + // but OSystem_SDL::pollEvent was not called. This for example + // caused a crash under certain circumstances when doing an RTL. + // To fix this issue we update the screen change count right here. + _screenChangeCount++; + + if (_transactionDetails.needUpdatescreen) + internUpdateScreen(); + } + } else if (_transactionDetails.needUpdatescreen) { + setGraphicsModeIntern(); + internUpdateScreen(); + } + + _transactionMode = kTransactionNone; + return (TransactionError)errors; +} + +#ifdef USE_RGB_COLOR + +Common::List<Graphics::PixelFormat> OSystem_SDL::getSupportedFormats() const { + assert(!_supportedFormats.empty()); + return _supportedFormats; +} + +void OSystem_SDL::detectSupportedFormats() { + + // Clear old list + _supportedFormats.clear(); + + // Some tables with standard formats that we always list + // as "supported". If frontend code tries to use one of + // these, we will perform the necessary format + // conversion in the background. Of course this incurs a + // performance hit, but on desktop ports this should not + // matter. We still push the currently active format to + // the front, so if frontend code just uses the first + // available format, it will get one that is "cheap" to + // use. + const Graphics::PixelFormat RGBList[] = { +#ifdef USE_RGB_COLOR + // RGBA8888, ARGB8888, RGB888 + Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0), + Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24), + Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0), +#endif + // RGB565, XRGB1555, RGB555, RGBA4444, ARGB4444 + Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), + Graphics::PixelFormat(2, 5, 5, 5, 1, 10, 5, 0, 15), + Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0), + Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0), + Graphics::PixelFormat(2, 4, 4, 4, 4, 8, 4, 0, 12) + }; + const Graphics::PixelFormat BGRList[] = { +#ifdef USE_RGB_COLOR + // ABGR8888, BGRA8888, BGR888 + Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), + Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0), + Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 8, 16, 0), +#endif + // BGR565, XBGR1555, BGR555, ABGR4444, BGRA4444 + Graphics::PixelFormat(2, 5, 6, 5, 0, 0, 5, 11, 0), + Graphics::PixelFormat(2, 5, 5, 5, 1, 0, 5, 10, 15), + Graphics::PixelFormat(2, 5, 5, 5, 0, 0, 5, 10, 0), + Graphics::PixelFormat(2, 4, 4, 4, 4, 0, 4, 8, 12), + Graphics::PixelFormat(2, 4, 4, 4, 4, 4, 8, 12, 0) + }; + + Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8(); + if (_hwscreen) { + // Get our currently set hardware format + format = Graphics::PixelFormat(_hwscreen->format->BytesPerPixel, + 8 - _hwscreen->format->Rloss, 8 - _hwscreen->format->Gloss, + 8 - _hwscreen->format->Bloss, 8 - _hwscreen->format->Aloss, + _hwscreen->format->Rshift, _hwscreen->format->Gshift, + _hwscreen->format->Bshift, _hwscreen->format->Ashift); + + // Workaround to MacOSX SDL not providing an accurate Aloss value. + if (_hwscreen->format->Amask == 0) + format.aLoss = 8; + + // Push it first, as the prefered format. + _supportedFormats.push_back(format); + } + + // TODO: prioritize matching alpha masks + int i; + + // Push some RGB formats + for (i = 0; i < ARRAYSIZE(RGBList); i++) { + if (_hwscreen && (RGBList[i].bytesPerPixel > format.bytesPerPixel)) + continue; + if (RGBList[i] != format) + _supportedFormats.push_back(RGBList[i]); + } + + // Push some BGR formats + for (i = 0; i < ARRAYSIZE(BGRList); i++) { + if (_hwscreen && (BGRList[i].bytesPerPixel > format.bytesPerPixel)) + continue; + if (BGRList[i] != format) + _supportedFormats.push_back(BGRList[i]); + } + + // Finally, we always supposed 8 bit palette graphics + _supportedFormats.push_back(Graphics::PixelFormat::createFormatCLUT8()); +} + +#endif + +bool OSystem_SDL::setGraphicsMode(int mode) { + Common::StackLock lock(_graphicsMutex); + + assert(_transactionMode == kTransactionActive); + + if (_oldVideoMode.setup && _oldVideoMode.mode == mode) + return true; + + int newScaleFactor = 1; + + switch (mode) { + case GFX_NORMAL: + newScaleFactor = 1; + break; +#ifdef USE_SCALERS + case GFX_DOUBLESIZE: + newScaleFactor = 2; + break; + case GFX_TRIPLESIZE: + newScaleFactor = 3; + break; + + case GFX_2XSAI: + newScaleFactor = 2; + break; + case GFX_SUPER2XSAI: + newScaleFactor = 2; + break; + case GFX_SUPEREAGLE: + newScaleFactor = 2; + break; + case GFX_ADVMAME2X: + newScaleFactor = 2; + break; + case GFX_ADVMAME3X: + newScaleFactor = 3; + break; +#ifdef USE_HQ_SCALERS + case GFX_HQ2X: + newScaleFactor = 2; + break; + case GFX_HQ3X: + newScaleFactor = 3; + break; +#endif + case GFX_TV2X: + newScaleFactor = 2; + break; + case GFX_DOTMATRIX: + newScaleFactor = 2; + break; +#endif // USE_SCALERS + + default: + warning("unknown gfx mode %d", mode); + return false; + } + + _transactionDetails.normal1xScaler = (mode == GFX_NORMAL); + if (_oldVideoMode.setup && _oldVideoMode.scaleFactor != newScaleFactor) + _transactionDetails.needHotswap = true; + + _transactionDetails.needUpdatescreen = true; + + _videoMode.mode = mode; + _videoMode.scaleFactor = newScaleFactor; + + return true; +} + +void OSystem_SDL::setGraphicsModeIntern() { + Common::StackLock lock(_graphicsMutex); + ScalerProc *newScalerProc = 0; + + switch (_videoMode.mode) { + case GFX_NORMAL: + newScalerProc = Normal1x; + break; +#ifdef USE_SCALERS + case GFX_DOUBLESIZE: + newScalerProc = Normal2x; + break; + case GFX_TRIPLESIZE: + newScalerProc = Normal3x; + break; + + case GFX_2XSAI: + newScalerProc = _2xSaI; + break; + case GFX_SUPER2XSAI: + newScalerProc = Super2xSaI; + break; + case GFX_SUPEREAGLE: + newScalerProc = SuperEagle; + break; + case GFX_ADVMAME2X: + newScalerProc = AdvMame2x; + break; + case GFX_ADVMAME3X: + newScalerProc = AdvMame3x; + break; +#ifdef USE_HQ_SCALERS + case GFX_HQ2X: + newScalerProc = HQ2x; + break; + case GFX_HQ3X: + newScalerProc = HQ3x; + break; +#endif + case GFX_TV2X: + newScalerProc = TV2x; + break; + case GFX_DOTMATRIX: + newScalerProc = DotMatrix; + break; +#endif // USE_SCALERS + + default: + error("Unknown gfx mode %d", _videoMode.mode); + } + + _scalerProc = newScalerProc; + + if (_videoMode.mode != GFX_NORMAL) { + for (int i = 0; i < ARRAYSIZE(s_gfxModeSwitchTable); i++) { + if (s_gfxModeSwitchTable[i][1] == _videoMode.mode || s_gfxModeSwitchTable[i][2] == _videoMode.mode) { + _scalerType = i; + break; + } + } + } + + if (!_screen || !_hwscreen) + return; + + // Blit everything to the screen + _forceFull = true; + + // Even if the old and new scale factors are the same, we may have a + // different scaler for the cursor now. + blitCursor(); +} + +int OSystem_SDL::getGraphicsMode() const { + assert (_transactionMode == kTransactionNone); + return _videoMode.mode; +} + +void OSystem_SDL::initSize(uint w, uint h, const Graphics::PixelFormat *format) { + assert(_transactionMode == kTransactionActive); + +#ifdef USE_RGB_COLOR + //avoid redundant format changes + Graphics::PixelFormat newFormat; + if (!format) + newFormat = Graphics::PixelFormat::createFormatCLUT8(); + else + newFormat = *format; + + assert(newFormat.bytesPerPixel > 0); + + if (newFormat != _videoMode.format) { + _videoMode.format = newFormat; + _transactionDetails.formatChanged = true; + _screenFormat = newFormat; + } +#endif + + // Avoid redundant res changes + if ((int)w == _videoMode.screenWidth && (int)h == _videoMode.screenHeight) + return; + + _videoMode.screenWidth = w; + _videoMode.screenHeight = h; + + _transactionDetails.sizeChanged = true; +} + +int OSystem_SDL::effectiveScreenHeight() const { + return _videoMode.scaleFactor * + (_videoMode.aspectRatioCorrection + ? real2Aspect(_videoMode.screenHeight) + : _videoMode.screenHeight); +} + +static void fixupResolutionForAspectRatio(AspectRatio desiredAspectRatio, int &width, int &height) { + assert(&width != &height); + + if (desiredAspectRatio.isAuto()) + return; + + int kw = desiredAspectRatio.kw(); + int kh = desiredAspectRatio.kh(); + + const int w = width; + const int h = height; + + SDL_Rect const* const*availableModes = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_SWSURFACE); //TODO : Maybe specify a pixel format + assert(availableModes); + + const SDL_Rect *bestMode = NULL; + uint bestMetric = (uint)-1; // Metric is wasted space + while (const SDL_Rect *mode = *availableModes++) { + if (mode->w < w) + continue; + if (mode->h < h) + continue; + if (mode->h * kw != mode->w * kh) + continue; + //printf("%d %d\n", mode->w, mode->h); + + uint metric = mode->w * mode->h - w * h; + if (metric > bestMetric) + continue; + + bestMetric = metric; + bestMode = mode; + } + + if (!bestMode) { + warning("Unable to enforce the desired aspect ratio"); + return; + } + //printf("%d %d\n", bestMode->w, bestMode->h); + width = bestMode->w; + height = bestMode->h; +} + +bool OSystem_SDL::loadGFXMode() { + assert(_inited); + _forceFull = true; + +#if !defined(__MAEMO__) && !defined(DINGUX) && !defined(GPH_DEVICE) && !defined(LINUXMOTO) && !defined(OPENPANDORA) + _videoMode.overlayWidth = _videoMode.screenWidth * _videoMode.scaleFactor; + _videoMode.overlayHeight = _videoMode.screenHeight * _videoMode.scaleFactor; + + if (_videoMode.screenHeight != 200 && _videoMode.screenHeight != 400) + _videoMode.aspectRatioCorrection = false; + + if (_videoMode.aspectRatioCorrection) + _videoMode.overlayHeight = real2Aspect(_videoMode.overlayHeight); + + _videoMode.hardwareWidth = _videoMode.screenWidth * _videoMode.scaleFactor; + _videoMode.hardwareHeight = effectiveScreenHeight(); +#else + _videoMode.hardwareWidth = _videoMode.overlayWidth; + _videoMode.hardwareHeight = _videoMode.overlayHeight; +#endif + + // + // Create the surface that contains the 8 bit game data + // +#ifdef USE_RGB_COLOR + _screen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth, _videoMode.screenHeight, + _screenFormat.bytesPerPixel << 3, + ((1 << _screenFormat.rBits()) - 1) << _screenFormat.rShift , + ((1 << _screenFormat.gBits()) - 1) << _screenFormat.gShift , + ((1 << _screenFormat.bBits()) - 1) << _screenFormat.bShift , + ((1 << _screenFormat.aBits()) - 1) << _screenFormat.aShift ); + if (_screen == NULL) + error("allocating _screen failed"); + +#else + _screen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth, _videoMode.screenHeight, 8, 0, 0, 0, 0); + if (_screen == NULL) + error("allocating _screen failed"); +#endif + + // + // Create the surface that contains the scaled graphics in 16 bit mode + // + + if (_videoMode.fullscreen) { + fixupResolutionForAspectRatio(_videoMode.desiredAspectRatio, _videoMode.hardwareWidth, _videoMode.hardwareHeight); + } + + _hwscreen = SDL_SetVideoMode(_videoMode.hardwareWidth, _videoMode.hardwareHeight, 16, + _videoMode.fullscreen ? (SDL_FULLSCREEN|SDL_SWSURFACE) : SDL_SWSURFACE + ); +#ifdef USE_RGB_COLOR + detectSupportedFormats(); +#endif + + if (_hwscreen == NULL) { + // DON'T use error(), as this tries to bring up the debug + // console, which WON'T WORK now that _hwscreen is hosed. + + if (!_oldVideoMode.setup) { + warning("SDL_SetVideoMode says we can't switch to that mode (%s)", SDL_GetError()); + quit(); + } else { + return false; + } + } + + // + // Create the surface used for the graphics in 16 bit before scaling, and also the overlay + // + + // 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("allocating _tmpscreen failed"); + + _overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth, _videoMode.overlayHeight, + 16, + _hwscreen->format->Rmask, + _hwscreen->format->Gmask, + _hwscreen->format->Bmask, + _hwscreen->format->Amask); + + if (_overlayscreen == NULL) + error("allocating _overlayscreen failed"); + + _overlayFormat.bytesPerPixel = _overlayscreen->format->BytesPerPixel; + + _overlayFormat.rLoss = _overlayscreen->format->Rloss; + _overlayFormat.gLoss = _overlayscreen->format->Gloss; + _overlayFormat.bLoss = _overlayscreen->format->Bloss; + _overlayFormat.aLoss = _overlayscreen->format->Aloss; + + _overlayFormat.rShift = _overlayscreen->format->Rshift; + _overlayFormat.gShift = _overlayscreen->format->Gshift; + _overlayFormat.bShift = _overlayscreen->format->Bshift; + _overlayFormat.aShift = _overlayscreen->format->Ashift; + + _tmpscreen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth + 3, _videoMode.overlayHeight + 3, + 16, + _hwscreen->format->Rmask, + _hwscreen->format->Gmask, + _hwscreen->format->Bmask, + _hwscreen->format->Amask); + + if (_tmpscreen2 == NULL) + error("allocating _tmpscreen2 failed"); + +#ifdef USE_OSD + _osdSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, + _hwscreen->w, + _hwscreen->h, + 16, + _hwscreen->format->Rmask, + _hwscreen->format->Gmask, + _hwscreen->format->Bmask, + _hwscreen->format->Amask); + if (_osdSurface == NULL) + error("allocating _osdSurface failed"); + SDL_SetColorKey(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kOSDColorKey); +#endif + + // keyboard cursor control, some other better place for it? + _km.x_max = _videoMode.screenWidth * _videoMode.scaleFactor - 1; + _km.y_max = effectiveScreenHeight() - 1; + _km.delay_time = 25; + _km.last_time = 0; + + // Distinguish 555 and 565 mode + if (_hwscreen->format->Rmask == 0x7C00) + InitScalers(555); + else + InitScalers(565); + + return true; +} + +void OSystem_SDL::unloadGFXMode() { + if (_screen) { + SDL_FreeSurface(_screen); + _screen = NULL; + } + + if (_hwscreen) { + SDL_FreeSurface(_hwscreen); + _hwscreen = NULL; + } + + if (_tmpscreen) { + SDL_FreeSurface(_tmpscreen); + _tmpscreen = NULL; + } + + if (_tmpscreen2) { + SDL_FreeSurface(_tmpscreen2); + _tmpscreen2 = NULL; + } + + if (_overlayscreen) { + SDL_FreeSurface(_overlayscreen); + _overlayscreen = NULL; + } + +#ifdef USE_OSD + if (_osdSurface) { + SDL_FreeSurface(_osdSurface); + _osdSurface = NULL; + } +#endif + DestroyScalers(); +} + +bool OSystem_SDL::hotswapGFXMode() { + if (!_screen) + return false; + + // Keep around the old _screen & _overlayscreen so we can restore the screen data + // after the mode switch. + SDL_Surface *old_screen = _screen; + _screen = NULL; + SDL_Surface *old_overlayscreen = _overlayscreen; + _overlayscreen = NULL; + + // Release the HW screen surface + SDL_FreeSurface(_hwscreen); _hwscreen = NULL; + + SDL_FreeSurface(_tmpscreen); _tmpscreen = NULL; + SDL_FreeSurface(_tmpscreen2); _tmpscreen2 = NULL; + +#ifdef USE_OSD + // Release the OSD surface + SDL_FreeSurface(_osdSurface); _osdSurface = NULL; +#endif + + // 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_overlayscreen, NULL, _overlayscreen, NULL); + + // Free the old surfaces + SDL_FreeSurface(old_screen); + SDL_FreeSurface(old_overlayscreen); + + // Update cursor to new scale + blitCursor(); + + // Blit everything to the screen + internUpdateScreen(); + + return true; +} + +void OSystem_SDL::updateScreen() { + assert (_transactionMode == kTransactionNone); + + Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends + + internUpdateScreen(); +} + +void OSystem_SDL::internUpdateScreen() { + SDL_Surface *srcSurf, *origSurf; + int height, width; + ScalerProc *scalerProc; + int scale1; + +#if defined (DEBUG) && ! defined(_WIN32_WCE) // definitions not available for non-DEBUG here. (needed this to compile in SYMBIAN32 & linux?) + assert(_hwscreen != NULL); + assert(_hwscreen->map->sw_data != NULL); +#endif + + // If the shake position changed, fill the dirty area with blackness + if (_currentShakePos != _newShakePos || + (_mouseNeedsRedraw && _mouseBackup.y <= _currentShakePos)) { + SDL_Rect blackrect = {0, 0, _videoMode.screenWidth * _videoMode.scaleFactor, _newShakePos * _videoMode.scaleFactor}; + + if (_videoMode.aspectRatioCorrection && !_overlayVisible) + blackrect.h = real2Aspect(blackrect.h - 1) + 1; + + SDL_FillRect(_hwscreen, &blackrect, 0); + + _currentShakePos = _newShakePos; + + _forceFull = true; + } + + // Check whether the palette was changed in the meantime and update the + // screen surface accordingly. + if (_screen && _paletteDirtyEnd != 0) { + SDL_SetColors(_screen, _currentPalette + _paletteDirtyStart, + _paletteDirtyStart, + _paletteDirtyEnd - _paletteDirtyStart); + + _paletteDirtyEnd = 0; + + _forceFull = true; + } + +#ifdef USE_OSD + // OSD visible (i.e. non-transparent)? + if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + // Updated alpha value + const int diff = SDL_GetTicks() - _osdFadeStartTime; + if (diff > 0) { + if (diff >= kOSDFadeOutDuration) { + // Back to full transparency + _osdAlpha = SDL_ALPHA_TRANSPARENT; + } else { + // Do a linear fade out... + const int startAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100; + _osdAlpha = startAlpha + diff * (SDL_ALPHA_TRANSPARENT - startAlpha) / kOSDFadeOutDuration; + } + SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha); + _forceFull = true; + } + } +#endif + + if (!_overlayVisible) { + origSurf = _screen; + srcSurf = _tmpscreen; + width = _videoMode.screenWidth; + height = _videoMode.screenHeight; + scalerProc = _scalerProc; + scale1 = _videoMode.scaleFactor; + } else { + origSurf = _overlayscreen; + srcSurf = _tmpscreen2; + width = _videoMode.overlayWidth; + height = _videoMode.overlayHeight; + scalerProc = Normal1x; + + scale1 = 1; + } + + // Add the area covered by the mouse cursor to the list of dirty rects if + // we have to redraw the mouse. + if (_mouseNeedsRedraw) + undrawMouse(); + + // Force a full redraw if requested + if (_forceFull) { + _numDirtyRects = 1; + _dirtyRectList[0].x = 0; + _dirtyRectList[0].y = 0; + _dirtyRectList[0].w = width; + _dirtyRectList[0].h = height; + } + + // Only draw anything if necessary + if (_numDirtyRects > 0 || _mouseNeedsRedraw) { + SDL_Rect *r; + SDL_Rect dst; + uint32 srcPitch, dstPitch; + SDL_Rect *lastRect = _dirtyRectList + _numDirtyRects; + + for (r = _dirtyRectList; r != lastRect; ++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. + + 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; r != lastRect; ++r) { + register int dst_y = r->y + _currentShakePos; + register int dst_h = 0; + register int orig_dst_y = 0; + register int rx1 = r->x * scale1; + + if (dst_y < height) { + dst_h = r->h; + if (dst_h > height - dst_y) + dst_h = height - dst_y; + + orig_dst_y = dst_y; + dst_y = dst_y * scale1; + + if (_videoMode.aspectRatioCorrection && !_overlayVisible) + dst_y = real2Aspect(dst_y); + + assert(scalerProc != NULL); + scalerProc((byte *)srcSurf->pixels + (r->x * 2 + 2) + (r->y + 1) * srcPitch, srcPitch, + (byte *)_hwscreen->pixels + rx1 * 2 + dst_y * dstPitch, dstPitch, r->w, dst_h); + } + + r->x = rx1; + r->y = dst_y; + r->w = r->w * scale1; + r->h = dst_h * scale1; + +#ifdef USE_SCALERS + if (_videoMode.aspectRatioCorrection && orig_dst_y < height && !_overlayVisible) + r->h = stretch200To240((uint8 *) _hwscreen->pixels, dstPitch, r->w, r->h, r->x, r->y, orig_dst_y * scale1); +#endif + } + SDL_UnlockSurface(srcSurf); + SDL_UnlockSurface(_hwscreen); + + // Readjust the dirty rect list in case we are doing a full update. + // This is necessary if shaking is active. + if (_forceFull) { + _dirtyRectList[0].y = 0; + _dirtyRectList[0].h = effectiveScreenHeight(); + } + + drawMouse(); + +#ifdef USE_OSD + if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + SDL_BlitSurface(_osdSurface, 0, _hwscreen, 0); + } +#endif + // Finally, blit all our changes to the screen + SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList); + } + + _numDirtyRects = 0; + _forceFull = false; + _mouseNeedsRedraw = false; +} + +bool OSystem_SDL::saveScreenshot(const char *filename) { + assert(_hwscreen != NULL); + + Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends + return SDL_SaveBMP(_hwscreen, filename) == 0; +} + +void OSystem_SDL::setFullscreenMode(bool enable) { + Common::StackLock lock(_graphicsMutex); + + if (_oldVideoMode.setup && _oldVideoMode.fullscreen == enable) + return; + + if (_transactionMode == kTransactionActive) { + _videoMode.fullscreen = enable; + _transactionDetails.needHotswap = true; + } +} + +void OSystem_SDL::setAspectRatioCorrection(bool enable) { + Common::StackLock lock(_graphicsMutex); + + if (_oldVideoMode.setup && _oldVideoMode.aspectRatioCorrection == enable) + return; + + if (_transactionMode == kTransactionActive) { + _videoMode.aspectRatioCorrection = enable; + _transactionDetails.needHotswap = true; + } +} + +void OSystem_SDL::copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h) { + assert (_transactionMode == kTransactionNone); + assert(src); + + if (_screen == NULL) { + warning("OSystem_SDL::copyRectToScreen: _screen == NULL"); + return; + } + + Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends + + assert(x >= 0 && x < _videoMode.screenWidth); + assert(y >= 0 && y < _videoMode.screenHeight); + assert(h > 0 && y + h <= _videoMode.screenHeight); + assert(w > 0 && x + w <= _videoMode.screenWidth); + + addDirtyRect(x, y, w, h); + + // Try to lock the screen surface + if (SDL_LockSurface(_screen) == -1) + 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); + } else { + do { + memcpy(dst, src, w * _screenFormat.bytesPerPixel); + src += pitch; + dst += _videoMode.screenWidth * _screenFormat.bytesPerPixel; + } while (--h); + } +#else + 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); + } +#endif + + // Unlock the screen surface + SDL_UnlockSurface(_screen); +} + +Graphics::Surface *OSystem_SDL::lockScreen() { + assert (_transactionMode == kTransactionNone); + + // Lock the graphics mutex + lockMutex(_graphicsMutex); + + // paranoia check + assert(!_screenIsLocked); + _screenIsLocked = true; + + // Try to lock the screen surface + if (SDL_LockSurface(_screen) == -1) + error("SDL_LockSurface failed: %s", SDL_GetError()); + + _framebuffer.pixels = _screen->pixels; + _framebuffer.w = _screen->w; + _framebuffer.h = _screen->h; + _framebuffer.pitch = _screen->pitch; +#ifdef USE_RGB_COLOR + _framebuffer.bytesPerPixel = _screenFormat.bytesPerPixel; +#else + _framebuffer.bytesPerPixel = 1; +#endif + + return &_framebuffer; +} + +void OSystem_SDL::unlockScreen() { + assert (_transactionMode == kTransactionNone); + + // paranoia check + assert(_screenIsLocked); + _screenIsLocked = false; + + // Unlock the screen surface + SDL_UnlockSurface(_screen); + + // Trigger a full screen update + _forceFull = true; + + // Finally unlock the graphics mutex + unlockMutex(_graphicsMutex); +} + +void OSystem_SDL::addDirtyRect(int x, int y, int w, int h, bool realCoordinates) { + if (_forceFull) + return; + + if (_numDirtyRects == NUM_DIRTY_RECT) { + _forceFull = true; + return; + } + + int height, width; + + if (!_overlayVisible && !realCoordinates) { + width = _videoMode.screenWidth; + height = _videoMode.screenHeight; + } else { + width = _videoMode.overlayWidth; + height = _videoMode.overlayHeight; + } + + // Extend the dirty region by 1 pixel for scalers + // that "smear" the screen, e.g. 2xSAI + if (!realCoordinates) { + x--; + y--; + w+=2; + h+=2; + } + + // clip + if (x < 0) { + w += x; + x = 0; + } + + if (y < 0) { + h += y; + y=0; + } + + if (w > width - x) { + w = width - x; + } + + if (h > height - y) { + h = height - y; + } + +#ifdef USE_SCALERS + if (_videoMode.aspectRatioCorrection && !_overlayVisible && !realCoordinates) { + makeRectStretchable(x, y, w, h); + } +#endif + + if (w == width && h == height) { + _forceFull = true; + return; + } + + if (w > 0 && h > 0) { + SDL_Rect *r = &_dirtyRectList[_numDirtyRects++]; + + r->x = x; + r->y = y; + r->w = w; + r->h = h; + } +} + +int16 OSystem_SDL::getHeight() { + return _videoMode.screenHeight; +} + +int16 OSystem_SDL::getWidth() { + return _videoMode.screenWidth; +} + +void OSystem_SDL::setPalette(const byte *colors, uint start, uint num) { + assert(colors); + +#ifdef USE_RGB_COLOR + assert(_screenFormat.bytesPerPixel == 1); +#endif + + // Setting the palette before _screen is created is allowed - for now - + // since we don't actually set the palette until the screen is updated. + // But it could indicate a programming error, so let's warn about it. + + if (!_screen) + warning("OSystem_SDL::setPalette: _screen == NULL"); + + const byte *b = colors; + uint i; + SDL_Color *base = _currentPalette + start; + for (i = 0; i < num; i++) { + base[i].r = b[0]; + base[i].g = b[1]; + base[i].b = b[2]; + b += 4; + } + + if (start < _paletteDirtyStart) + _paletteDirtyStart = start; + + if (start + num > _paletteDirtyEnd) + _paletteDirtyEnd = start + num; + + // Some games blink cursors with palette + if (_cursorPaletteDisabled) + blitCursor(); +} + +void OSystem_SDL::grabPalette(byte *colors, uint start, uint num) { + assert(colors); + +#ifdef USE_RGB_COLOR + assert(_screenFormat.bytesPerPixel == 1); +#endif + + const SDL_Color *base = _currentPalette + start; + + for (uint i = 0; i < num; ++i) { + colors[i * 4] = base[i].r; + colors[i * 4 + 1] = base[i].g; + colors[i * 4 + 2] = base[i].b; + colors[i * 4 + 3] = 0xFF; + } +} + +void OSystem_SDL::setCursorPalette(const byte *colors, uint start, uint num) { + assert(colors); + const byte *b = colors; + uint i; + SDL_Color *base = _cursorPalette + start; + for (i = 0; i < num; i++) { + base[i].r = b[0]; + base[i].g = b[1]; + base[i].b = b[2]; + b += 4; + } + + _cursorPaletteDisabled = false; + blitCursor(); +} + + +void OSystem_SDL::setShakePos(int shake_pos) { + assert (_transactionMode == kTransactionNone); + + _newShakePos = shake_pos; +} + + +#pragma mark - +#pragma mark --- Overlays --- +#pragma mark - + +void OSystem_SDL::showOverlay() { + assert (_transactionMode == kTransactionNone); + + int x, y; + + if (_overlayVisible) + return; + + _overlayVisible = true; + + // Since resolution could change, put mouse to adjusted position + // Fixes bug #1349059 + x = _mouseCurState.x * _videoMode.scaleFactor; + if (_videoMode.aspectRatioCorrection) + y = real2Aspect(_mouseCurState.y) * _videoMode.scaleFactor; + else + y = _mouseCurState.y * _videoMode.scaleFactor; + + warpMouse(x, y); + + clearOverlay(); +} + +void OSystem_SDL::hideOverlay() { + assert (_transactionMode == kTransactionNone); + + if (!_overlayVisible) + return; + + int x, y; + + _overlayVisible = false; + + // Since resolution could change, put mouse to adjusted position + // Fixes bug #1349059 + x = _mouseCurState.x / _videoMode.scaleFactor; + y = _mouseCurState.y / _videoMode.scaleFactor; + if (_videoMode.aspectRatioCorrection) + y = aspect2Real(y); + + warpMouse(x, y); + + clearOverlay(); + + _forceFull = true; +} + +void OSystem_SDL::clearOverlay() { + //assert (_transactionMode == kTransactionNone); + + Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends + + if (!_overlayVisible) + return; + + // Clear the overlay by making the game screen "look through" everywhere. + SDL_Rect src, dst; + src.x = src.y = 0; + dst.x = dst.y = 1; + src.w = dst.w = _videoMode.screenWidth; + src.h = dst.h = _videoMode.screenHeight; + if (SDL_BlitSurface(_screen, &src, _tmpscreen, &dst) != 0) + error("SDL_BlitSurface failed: %s", SDL_GetError()); + + SDL_LockSurface(_tmpscreen); + SDL_LockSurface(_overlayscreen); + _scalerProc((byte *)(_tmpscreen->pixels) + _tmpscreen->pitch + 2, _tmpscreen->pitch, + (byte *)_overlayscreen->pixels, _overlayscreen->pitch, _videoMode.screenWidth, _videoMode.screenHeight); + +#ifdef USE_SCALERS + if (_videoMode.aspectRatioCorrection) + stretch200To240((uint8 *)_overlayscreen->pixels, _overlayscreen->pitch, + _videoMode.overlayWidth, _videoMode.screenHeight * _videoMode.scaleFactor, 0, 0, 0); +#endif + SDL_UnlockSurface(_tmpscreen); + SDL_UnlockSurface(_overlayscreen); + + _forceFull = true; +} + +void OSystem_SDL::grabOverlay(OverlayColor *buf, int pitch) { + assert (_transactionMode == kTransactionNone); + + if (_overlayscreen == NULL) + return; + + if (SDL_LockSurface(_overlayscreen) == -1) + error("SDL_LockSurface failed: %s", SDL_GetError()); + + byte *src = (byte *)_overlayscreen->pixels; + int h = _videoMode.overlayHeight; + do { + memcpy(buf, src, _videoMode.overlayWidth * 2); + src += _overlayscreen->pitch; + buf += pitch; + } while (--h); + + SDL_UnlockSurface(_overlayscreen); +} + +void OSystem_SDL::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); + + 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); +} + + +#pragma mark - +#pragma mark --- Mouse --- +#pragma mark - + +bool OSystem_SDL::showMouse(bool visible) { + if (_mouseVisible == visible) + return visible; + + bool last = _mouseVisible; + _mouseVisible = visible; + _mouseNeedsRedraw = true; + + return last; +} + +void OSystem_SDL::setMousePos(int x, int y) { + if (x != _mouseCurState.x || y != _mouseCurState.y) { + _mouseNeedsRedraw = true; + _mouseCurState.x = x; + _mouseCurState.y = y; + } +} + +void OSystem_SDL::warpMouse(int x, int y) { + int y1 = y; + + // Don't change actual mouse position, when mouse is outside of our window (in case of windowed mode) + if (!(SDL_GetAppState( ) & SDL_APPMOUSEFOCUS)) { + setMousePos(x, y); // but change game cursor position + return; + } + + if (_videoMode.aspectRatioCorrection && !_overlayVisible) + y1 = real2Aspect(y); + + if (_mouseCurState.x != x || _mouseCurState.y != y) { + if (!_overlayVisible) + SDL_WarpMouse(x * _videoMode.scaleFactor, y1 * _videoMode.scaleFactor); + else + SDL_WarpMouse(x, y1); + + // SDL_WarpMouse() generates a mouse movement event, so + // setMousePos() 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_SDL::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) { +#ifdef USE_RGB_COLOR + if (!format) + _cursorFormat = Graphics::PixelFormat::createFormatCLUT8(); + else if (format->bytesPerPixel <= _screenFormat.bytesPerPixel) + _cursorFormat = *format; + + if (_cursorFormat.bytesPerPixel < 4) + assert(keycolor < (uint)(1 << (_cursorFormat.bytesPerPixel << 3))); +#else + assert(keycolor <= 0xFF); +#endif + + if (w == 0 || h == 0) + return; + + _mouseCurState.hotX = hotspot_x; + _mouseCurState.hotY = hotspot_y; + + _mouseKeyColor = keycolor; + + _cursorTargetScale = cursorTargetScale; + + if (_mouseCurState.w != (int)w || _mouseCurState.h != (int)h) { + _mouseCurState.w = w; + _mouseCurState.h = h; + + if (_mouseOrigSurface) + SDL_FreeSurface(_mouseOrigSurface); + + // Allocate bigger surface because AdvMame2x adds black pixel at [0,0] + _mouseOrigSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, + _mouseCurState.w + 2, + _mouseCurState.h + 2, + 16, + _hwscreen->format->Rmask, + _hwscreen->format->Gmask, + _hwscreen->format->Bmask, + _hwscreen->format->Amask); + + if (_mouseOrigSurface == NULL) + error("allocating _mouseOrigSurface failed"); + SDL_SetColorKey(_mouseOrigSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kMouseColorKey); + } + + free(_mouseData); +#ifdef USE_RGB_COLOR + _mouseData = (byte *)malloc(w * h * _cursorFormat.bytesPerPixel); + memcpy(_mouseData, buf, w * h * _cursorFormat.bytesPerPixel); +#else + _mouseData = (byte *)malloc(w * h); + memcpy(_mouseData, buf, w * h); +#endif + + blitCursor(); +} + +void OSystem_SDL::blitCursor() { + byte *dstPtr; + const byte *srcPtr = _mouseData; +#ifdef USE_RGB_COLOR + uint32 color; +#else + byte color; +#endif + int w, h, i, j; + + if (!_mouseOrigSurface || !_mouseData) + return; + + _mouseNeedsRedraw = true; + + w = _mouseCurState.w; + h = _mouseCurState.h; + + SDL_LockSurface(_mouseOrigSurface); + + // Make whole surface transparent + for (i = 0; i < h + 2; i++) { + dstPtr = (byte *)_mouseOrigSurface->pixels + _mouseOrigSurface->pitch * i; + for (j = 0; j < w + 2; j++) { + *(uint16 *)dstPtr = kMouseColorKey; + dstPtr += 2; + } + } + + // Draw from [1,1] since AdvMame2x adds artefact at 0,0 + dstPtr = (byte *)_mouseOrigSurface->pixels + _mouseOrigSurface->pitch + 2; + + SDL_Color *palette; + + if (_cursorPaletteDisabled) + palette = _currentPalette; + else + palette = _cursorPalette; + + for (i = 0; i < h; i++) { + for (j = 0; j < w; j++) { +#ifdef USE_RGB_COLOR + if (_cursorFormat.bytesPerPixel > 1) { + if (_cursorFormat.bytesPerPixel == 2) + color = *(const uint16 *)srcPtr; + else + color = *(const uint32 *)srcPtr; + if (color != _mouseKeyColor) { // transparent, don't draw + uint8 r, g, b; + _cursorFormat.colorToRGB(color, r, g, b); + *(uint16 *)dstPtr = SDL_MapRGB(_mouseOrigSurface->format, + r, g, b); + } + dstPtr += 2; + srcPtr += _cursorFormat.bytesPerPixel; + } else { +#endif + color = *srcPtr; + if (color != _mouseKeyColor) { // transparent, don't draw + *(uint16 *)dstPtr = SDL_MapRGB(_mouseOrigSurface->format, + palette[color].r, palette[color].g, palette[color].b); + } + dstPtr += 2; + srcPtr++; +#ifdef USE_RGB_COLOR + } +#endif + } + dstPtr += _mouseOrigSurface->pitch - w * 2; + } + + int rW, rH; + + if (_cursorTargetScale >= _videoMode.scaleFactor) { + // The cursor target scale is greater or equal to the scale at + // which the rest of the screen is drawn. We do not downscale + // the cursor image, we draw it at its original size. It will + // appear too large on screen. + + rW = w; + rH = h; + _mouseCurState.rHotX = _mouseCurState.hotX; + _mouseCurState.rHotY = _mouseCurState.hotY; + + // The virtual dimensions may be larger than the original. + + _mouseCurState.vW = w * _cursorTargetScale / _videoMode.scaleFactor; + _mouseCurState.vH = h * _cursorTargetScale / _videoMode.scaleFactor; + _mouseCurState.vHotX = _mouseCurState.hotX * _cursorTargetScale / + _videoMode.scaleFactor; + _mouseCurState.vHotY = _mouseCurState.hotY * _cursorTargetScale / + _videoMode.scaleFactor; + } else { + // The cursor target scale is smaller than the scale at which + // the rest of the screen is drawn. We scale up the cursor + // image to make it appear correct. + + rW = w * _videoMode.scaleFactor / _cursorTargetScale; + rH = h * _videoMode.scaleFactor / _cursorTargetScale; + _mouseCurState.rHotX = _mouseCurState.hotX * _videoMode.scaleFactor / + _cursorTargetScale; + _mouseCurState.rHotY = _mouseCurState.hotY * _videoMode.scaleFactor / + _cursorTargetScale; + + // The virtual dimensions will be the same as the original. + + _mouseCurState.vW = w; + _mouseCurState.vH = h; + _mouseCurState.vHotX = _mouseCurState.hotX; + _mouseCurState.vHotY = _mouseCurState.hotY; + } + +#ifdef USE_SCALERS + int rH1 = rH; // store original to pass to aspect-correction function later +#endif + + if (_videoMode.aspectRatioCorrection && _cursorTargetScale == 1) { + rH = real2Aspect(rH - 1) + 1; + _mouseCurState.rHotY = real2Aspect(_mouseCurState.rHotY); + } + + if (_mouseCurState.rW != rW || _mouseCurState.rH != rH) { + _mouseCurState.rW = rW; + _mouseCurState.rH = rH; + + if (_mouseSurface) + SDL_FreeSurface(_mouseSurface); + + _mouseSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, + _mouseCurState.rW, + _mouseCurState.rH, + 16, + _hwscreen->format->Rmask, + _hwscreen->format->Gmask, + _hwscreen->format->Bmask, + _hwscreen->format->Amask); + + if (_mouseSurface == NULL) + error("allocating _mouseSurface failed"); + + SDL_SetColorKey(_mouseSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kMouseColorKey); + } + + SDL_LockSurface(_mouseSurface); + + ScalerProc *scalerProc; + + // If possible, use the same scaler for the cursor as for the rest of + // the game. This only works well with the non-blurring scalers so we + // actually only use the 1x, 1.5x, 2x and AdvMame scalers. + + if (_cursorTargetScale == 1 && (_videoMode.mode == GFX_DOUBLESIZE || _videoMode.mode == GFX_TRIPLESIZE)) + scalerProc = _scalerProc; + else + scalerProc = scalersMagn[_cursorTargetScale - 1][_videoMode.scaleFactor - 1]; + + scalerProc((byte *)_mouseOrigSurface->pixels + _mouseOrigSurface->pitch + 2, + _mouseOrigSurface->pitch, (byte *)_mouseSurface->pixels, _mouseSurface->pitch, + _mouseCurState.w, _mouseCurState.h); + +#ifdef USE_SCALERS + if (_videoMode.aspectRatioCorrection && _cursorTargetScale == 1) + cursorStretch200To240((uint8 *)_mouseSurface->pixels, _mouseSurface->pitch, rW, rH1, 0, 0, 0); +#endif + + SDL_UnlockSurface(_mouseSurface); + SDL_UnlockSurface(_mouseOrigSurface); +} + +#ifdef USE_SCALERS +// Basically it is kVeryFastAndUglyAspectMode of stretch200To240 from +// common/scale/aspect.cpp +static int cursorStretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY) { + int maxDstY = real2Aspect(origSrcY + height - 1); + int y; + const uint8 *startSrcPtr = buf + srcX * 2 + (srcY - origSrcY) * pitch; + uint8 *dstPtr = buf + srcX * 2 + maxDstY * pitch; + + for (y = maxDstY; y >= srcY; y--) { + const uint8 *srcPtr = startSrcPtr + aspect2Real(y) * pitch; + + if (srcPtr == dstPtr) + break; + memcpy(dstPtr, srcPtr, width * 2); + dstPtr -= pitch; + } + + return 1 + maxDstY - srcY; +} +#endif + +void OSystem_SDL::toggleMouseGrab() { + if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF) + SDL_WM_GrabInput(SDL_GRAB_ON); + else + SDL_WM_GrabInput(SDL_GRAB_OFF); +} + +void OSystem_SDL::undrawMouse() { + const int x = _mouseBackup.x; + const int y = _mouseBackup.y; + + // When we switch bigger overlay off mouse jumps. Argh! + // This is intended to prevent undrawing offscreen mouse + if (!_overlayVisible && (x >= _videoMode.screenWidth || y >= _videoMode.screenHeight)) + return; + + if (_mouseBackup.w != 0 && _mouseBackup.h != 0) + addDirtyRect(x, y - _currentShakePos, _mouseBackup.w, _mouseBackup.h); +} + +void OSystem_SDL::drawMouse() { + if (!_mouseVisible || !_mouseSurface) { + _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0; + return; + } + + SDL_Rect dst; + int scale; + int hotX, hotY; + + dst.x = _mouseCurState.x; + dst.y = _mouseCurState.y; + + if (!_overlayVisible) { + scale = _videoMode.scaleFactor; + dst.w = _mouseCurState.vW; + dst.h = _mouseCurState.vH; + hotX = _mouseCurState.vHotX; + hotY = _mouseCurState.vHotY; + } else { + scale = 1; + dst.w = _mouseCurState.rW; + dst.h = _mouseCurState.rH; + hotX = _mouseCurState.rHotX; + hotY = _mouseCurState.rHotY; + } + + // The mouse is undrawn using virtual coordinates, i.e. they may be + // scaled and aspect-ratio corrected. + + _mouseBackup.x = dst.x - hotX; + _mouseBackup.y = dst.y - hotY; + _mouseBackup.w = dst.w; + _mouseBackup.h = dst.h; + + // We draw the pre-scaled cursor image, so now we need to adjust for + // scaling, shake position and aspect ratio correction manually. + + if (!_overlayVisible) { + dst.y += _currentShakePos; + } + + if (_videoMode.aspectRatioCorrection && !_overlayVisible) + dst.y = real2Aspect(dst.y); + + dst.x = scale * dst.x - _mouseCurState.rHotX; + dst.y = scale * dst.y - _mouseCurState.rHotY; + dst.w = _mouseCurState.rW; + dst.h = _mouseCurState.rH; + + // Note that SDL_BlitSurface() and addDirtyRect() will both perform any + // clipping necessary + + if (SDL_BlitSurface(_mouseSurface, NULL, _hwscreen, &dst) != 0) + error("SDL_BlitSurface failed: %s", SDL_GetError()); + + // The screen will be updated using real surface coordinates, i.e. + // they will not be scaled or aspect-ratio corrected. + + addDirtyRect(dst.x, dst.y, dst.w, dst.h, true); +} + +#pragma mark - +#pragma mark --- On Screen Display --- +#pragma mark - + +#ifdef USE_OSD +void OSystem_SDL::displayMessageOnOSD(const char *msg) { + assert (_transactionMode == kTransactionNone); + assert(msg); + + Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends + + uint i; + + // Lock the OSD surface for drawing + if (SDL_LockSurface(_osdSurface)) + error("displayMessageOnOSD: SDL_LockSurface failed: %s", SDL_GetError()); + + Graphics::Surface dst; + dst.pixels = _osdSurface->pixels; + dst.w = _osdSurface->w; + dst.h = _osdSurface->h; + dst.pitch = _osdSurface->pitch; + dst.bytesPerPixel = _osdSurface->format->BytesPerPixel; + + // The font we are going to use: + const Graphics::Font *font = FontMan.getFontByUsage(Graphics::FontManager::kOSDFont); + + // Clear everything with the "transparent" color, i.e. the colorkey + SDL_FillRect(_osdSurface, 0, kOSDColorKey); + + // Split the message into separate lines. + Common::Array<Common::String> lines; + const char *ptr; + for (ptr = msg; *ptr; ++ptr) { + if (*ptr == '\n') { + lines.push_back(Common::String(msg, ptr - msg)); + msg = ptr + 1; + } + } + lines.push_back(Common::String(msg, ptr - msg)); + + // Determine a rect which would contain the message string (clipped to the + // screen dimensions). + const int vOffset = 6; + const int lineSpacing = 1; + const int lineHeight = font->getFontHeight() + 2 * lineSpacing; + int width = 0; + int height = lineHeight * lines.size() + 2 * vOffset; + for (i = 0; i < lines.size(); i++) { + width = MAX(width, font->getStringWidth(lines[i]) + 14); + } + + // Clip the rect + if (width > dst.w) + width = dst.w; + if (height > dst.h) + height = dst.h; + + // Draw a dark gray rect + // TODO: Rounded corners ? Border? + SDL_Rect osdRect; + osdRect.x = (dst.w - width) / 2; + osdRect.y = (dst.h - height) / 2; + osdRect.w = width; + osdRect.h = height; + SDL_FillRect(_osdSurface, &osdRect, SDL_MapRGB(_osdSurface->format, 64, 64, 64)); + + // Render the message, centered, and in white + for (i = 0; i < lines.size(); i++) { + font->drawString(&dst, lines[i], + osdRect.x, osdRect.y + i * lineHeight + vOffset + lineSpacing, osdRect.w, + SDL_MapRGB(_osdSurface->format, 255, 255, 255), + Graphics::kTextAlignCenter); + } + + // Finished drawing, so unlock the OSD surface again + SDL_UnlockSurface(_osdSurface); + + // Init the OSD display parameters, and the fade out + _osdAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100; + _osdFadeStartTime = SDL_GetTicks() + kOSDFadeOutDelay; + SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha); + + // Ensure a full redraw takes place next time the screen is updated + _forceFull = true; +} +#endif + + +#pragma mark - +#pragma mark --- Misc --- +#pragma mark - + +bool OSystem_SDL::handleScalerHotkeys(const SDL_KeyboardEvent &key) { + // Ctrl-Alt-a toggles aspect ratio correction + if (key.keysym.sym == 'a') { + beginGFXTransaction(); + setFeatureState(kFeatureAspectRatioCorrection, !_videoMode.aspectRatioCorrection); + endGFXTransaction(); +#ifdef USE_OSD + char buffer[128]; + if (_videoMode.aspectRatioCorrection) + sprintf(buffer, "Enabled aspect ratio correction\n%d x %d -> %d x %d", + _videoMode.screenWidth, _videoMode.screenHeight, + _hwscreen->w, _hwscreen->h + ); + else + sprintf(buffer, "Disabled aspect ratio correction\n%d x %d -> %d x %d", + _videoMode.screenWidth, _videoMode.screenHeight, + _hwscreen->w, _hwscreen->h + ); + displayMessageOnOSD(buffer); +#endif + internUpdateScreen(); + return true; + } + + int newMode = -1; + int factor = _videoMode.scaleFactor - 1; + + // Increase/decrease the scale factor + if (key.keysym.sym == SDLK_EQUALS || key.keysym.sym == SDLK_PLUS || key.keysym.sym == SDLK_MINUS || + key.keysym.sym == SDLK_KP_PLUS || key.keysym.sym == SDLK_KP_MINUS) { + factor += (key.keysym.sym == SDLK_MINUS || key.keysym.sym == SDLK_KP_MINUS) ? -1 : +1; + if (0 <= factor && factor <= 3) { + newMode = s_gfxModeSwitchTable[_scalerType][factor]; + } + } + + const bool isNormalNumber = (SDLK_1 <= key.keysym.sym && key.keysym.sym <= SDLK_9); + const bool isKeypadNumber = (SDLK_KP1 <= key.keysym.sym && key.keysym.sym <= SDLK_KP9); + if (isNormalNumber || isKeypadNumber) { + _scalerType = key.keysym.sym - (isNormalNumber ? SDLK_1 : SDLK_KP1); + if (_scalerType >= ARRAYSIZE(s_gfxModeSwitchTable)) + return false; + + while (s_gfxModeSwitchTable[_scalerType][factor] < 0) { + assert(factor > 0); + factor--; + } + newMode = s_gfxModeSwitchTable[_scalerType][factor]; + } + + if (newMode >= 0) { + beginGFXTransaction(); + setGraphicsMode(newMode); + endGFXTransaction(); +#ifdef USE_OSD + if (_osdSurface) { + const char *newScalerName = 0; + const GraphicsMode *g = getSupportedGraphicsModes(); + while (g->name) { + if (g->id == _videoMode.mode) { + newScalerName = g->description; + break; + } + g++; + } + if (newScalerName) { + char buffer[128]; + sprintf(buffer, "Active graphics filter: %s\n%d x %d -> %d x %d", + newScalerName, + _videoMode.screenWidth, _videoMode.screenHeight, + _hwscreen->w, _hwscreen->h + ); + displayMessageOnOSD(buffer); + } + } +#endif + internUpdateScreen(); + + return true; + } else { + return false; + } +} + +bool OSystem_SDL::isScalerHotkey(const Common::Event &event) { + if ((event.kbd.flags & (Common::KBD_CTRL|Common::KBD_ALT)) == (Common::KBD_CTRL|Common::KBD_ALT)) { + const bool isNormalNumber = (Common::KEYCODE_1 <= event.kbd.keycode && event.kbd.keycode <= Common::KEYCODE_9); + const bool isKeypadNumber = (Common::KEYCODE_KP1 <= event.kbd.keycode && event.kbd.keycode <= Common::KEYCODE_KP9); + const bool isScaleKey = (event.kbd.keycode == Common::KEYCODE_EQUALS || event.kbd.keycode == Common::KEYCODE_PLUS || event.kbd.keycode == Common::KEYCODE_MINUS || + event.kbd.keycode == Common::KEYCODE_KP_PLUS || event.kbd.keycode == Common::KEYCODE_KP_MINUS); + + if (isNormalNumber || isKeypadNumber) { + int keyValue = event.kbd.keycode - (isNormalNumber ? Common::KEYCODE_1 : Common::KEYCODE_KP1); + if (keyValue >= ARRAYSIZE(s_gfxModeSwitchTable)) + return false; + } + return (isScaleKey || event.kbd.keycode == 'a'); + } + return false; +} diff --git a/backends/platform/sdl/macosx/macosx-main.cpp b/backends/platform/sdl/macosx/macosx-main.cpp deleted file mode 100644 index 023860b19f..0000000000 --- a/backends/platform/sdl/macosx/macosx-main.cpp +++ /dev/null @@ -1,54 +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$ - * - */ - -#ifdef MACOSX - -#include "backends/platform/sdl/macosx/macosx.h" -#include "backends/plugins/sdl/sdl-provider.h" -#include "base/main.h" - -int main(int argc, char *argv[]) { - - // Create our OSystem instance - g_system = new OSystem_MacOSX(); - assert(g_system); - - // Pre initialize the backend - ((OSystem_MacOSX *)g_system)->init(); - -#ifdef DYNAMIC_MODULES - PluginManager::instance().addPluginProvider(new SDLPluginProvider()); -#endif - - // Invoke the actual ScummVM main entry point: - int res = scummvm_main(argc, argv); - - // Free OSystem - delete (OSystem_MacOSX *)g_system; - - return res; -} - -#endif diff --git a/backends/platform/sdl/macosx/macosx.cpp b/backends/platform/sdl/macosx/macosx.cpp deleted file mode 100644 index a36769b417..0000000000 --- a/backends/platform/sdl/macosx/macosx.cpp +++ /dev/null @@ -1,76 +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$ - * - */ - -#ifdef MACOSX - -#include "backends/platform/sdl/macosx/macosx.h" -#include "backends/mixer/doublebuffersdl/doublebuffersdl-mixer.h" - -#include "common/archive.h" -#include "common/fs.h" - -#include "CoreFoundation/CoreFoundation.h" - -OSystem_MacOSX::OSystem_MacOSX() - : - OSystem_POSIX("Library/Preferences/ScummVM Preferences") { -} - -void OSystem_MacOSX::initBackend() { - // Create the mixer manager - if (_mixer == 0) { - _mixerManager = new DoubleBufferSDLMixerManager(); - - // Setup and start mixer - _mixerManager->init(); - } - - // Invoke parent implementation of this method - OSystem_POSIX::initBackend(); -} - -void OSystem_MacOSX::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { - // Invoke parent implementation of this method - OSystem_POSIX::addSysArchivesToSearchSet(s, priority); - - // Get URL of the Resource directory of the .app bundle - CFURLRef fileUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); - if (fileUrl) { - // Try to convert the URL to an absolute path - UInt8 buf[MAXPATHLEN]; - if (CFURLGetFileSystemRepresentation(fileUrl, true, buf, sizeof(buf))) { - // Success: Add it to the search path - Common::String bundlePath((const char *)buf); - s.add("__OSX_BUNDLE__", new Common::FSDirectory(bundlePath), priority); - } - CFRelease(fileUrl); - } -} - -void OSystem_MacOSX::setupIcon() { - // Don't set icon on OS X, as we use a nicer external icon there. -} - -#endif diff --git a/backends/platform/sdl/macosx/macosx.h b/backends/platform/sdl/macosx/macosx.h deleted file mode 100644 index 3c583a0ac0..0000000000 --- a/backends/platform/sdl/macosx/macosx.h +++ /dev/null @@ -1,41 +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$ - * - */ - -#ifndef PLATFORM_SDL_MACOSX_H -#define PLATFORM_SDL_MACOSX_H - -#include "backends/platform/sdl/posix/posix.h" - -class OSystem_MacOSX : public OSystem_POSIX { -public: - OSystem_MacOSX(); - virtual ~OSystem_MacOSX() {} - - virtual void initBackend(); - virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0); - virtual void setupIcon(); -}; - -#endif diff --git a/backends/platform/sdl/main.cpp b/backends/platform/sdl/main.cpp index 00ec0b8185..a9e1f5cf4b 100644 --- a/backends/platform/sdl/main.cpp +++ b/backends/platform/sdl/main.cpp @@ -23,33 +23,50 @@ * */ +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +// Fix for bug #2895217 "MSVC compilation broken with r47595": +// We need to keep this on top of the "common/scummsys.h" include, +// otherwise we will get errors about the windows headers redefining +// "ARRAYSIZE" for example. +#if defined(WIN32) && !defined(__SYMBIAN32__) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +// winnt.h defines ARRAYSIZE, but we want our own one... +#undef ARRAYSIZE +#endif + +#include "common/scummsys.h" + // Several SDL based ports use a custom main, and hence do not want to compile // of this file. The following "#if" ensures that. -#if !defined(UNIX) && !defined(WIN32) && !defined(__MAEMO__) && !defined(__SYMBIAN32__) && !defined(__amigaos4__) && !defined(DINGUX) && !defined(CAANOO) && !defined(OPENPANDORA) +#if !defined(__MAEMO__) && !defined(__SYMBIAN32__) && !defined(_WIN32_WCE) && !defined(DINGUX) && !defined(GPH_DEVICE) && !defined(LINUXMOTO) && !defined(OPENPANDORA) + #include "backends/platform/sdl/sdl.h" #include "backends/plugins/sdl/sdl-provider.h" #include "base/main.h" +#ifdef WIN32 +int __stdcall WinMain(HINSTANCE /*hInst*/, HINSTANCE /*hPrevInst*/, LPSTR /*lpCmdLine*/, int /*iShowCmd*/) { + SDL_SetModuleHandle(GetModuleHandle(NULL)); + return main(__argc, __argv); +} +#endif + int main(int argc, char *argv[]) { // Create our OSystem instance g_system = new OSystem_SDL(); assert(g_system); - // Pre initialize the backend - ((OSystem_SDL *)g_system)->init(); - #ifdef DYNAMIC_MODULES PluginManager::instance().addPluginProvider(new SDLPluginProvider()); #endif // Invoke the actual ScummVM main entry point: int res = scummvm_main(argc, argv); - - // Free OSystem - delete (OSystem_SDL *)g_system; - + ((OSystem_SDL *)g_system)->deinit(); return res; } diff --git a/backends/platform/sdl/module.mk b/backends/platform/sdl/module.mk index b00bb64718..43751a57b2 100644 --- a/backends/platform/sdl/module.mk +++ b/backends/platform/sdl/module.mk @@ -1,31 +1,13 @@ MODULE := backends/platform/sdl MODULE_OBJS := \ - posix/posix-main.o \ - posix/posix.o \ + events.o \ + graphics.o \ hardwarekeys.o \ main.o \ sdl.o -ifdef MACOSX -MODULE_OBJS += \ - macosx/macosx-main.o \ - macosx/macosx.o -endif - -ifdef WIN32 -MODULE_OBJS += \ - win32/win32-main.o \ - win32/win32.o -endif - -ifdef AMIGAOS -MODULE_OBJS += \ - amigaos/amigaos-main.o \ - amigaos/amigaos.o -endif - -# We don't use the rules.mk here on purpose +# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS. MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) OBJS := $(MODULE_OBJS) $(OBJS) -MODULE_DIRS += $(sort $(dir $(MODULE_OBJS)))
\ No newline at end of file +MODULE_DIRS += $(sort $(dir $(MODULE_OBJS))) diff --git a/backends/platform/sdl/posix/posix-main.cpp b/backends/platform/sdl/posix/posix-main.cpp deleted file mode 100644 index de9eb2b7ef..0000000000 --- a/backends/platform/sdl/posix/posix-main.cpp +++ /dev/null @@ -1,54 +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(UNIX) && !defined(MACOSX) && !defined(SAMSUNGTV) && !defined(LINUXMOTO) && !defined(GP2XWIZ) && !defined(GP2X) && !defined(DINGUX) - -#include "backends/platform/sdl/posix/posix.h" -#include "backends/plugins/sdl/sdl-provider.h" -#include "base/main.h" - -int main(int argc, char *argv[]) { - - // Create our OSystem instance - g_system = new OSystem_POSIX(); - assert(g_system); - - // Pre initialize the backend - ((OSystem_POSIX *)g_system)->init(); - -#ifdef DYNAMIC_MODULES - PluginManager::instance().addPluginProvider(new SDLPluginProvider()); -#endif - - // Invoke the actual ScummVM main entry point: - int res = scummvm_main(argc, argv); - - // Free OSystem - delete (OSystem_POSIX *)g_system; - - return res; -} - -#endif diff --git a/backends/platform/sdl/posix/posix.cpp b/backends/platform/sdl/posix/posix.cpp deleted file mode 100644 index c9c7304c0f..0000000000 --- a/backends/platform/sdl/posix/posix.cpp +++ /dev/null @@ -1,68 +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$ - * - */ - -#ifdef UNIX - -#include "backends/platform/sdl/posix/posix.h" -#include "backends/saves/posix/posix-saves.h" -#include "backends/fs/posix/posix-fs-factory.h" - -OSystem_POSIX::OSystem_POSIX(Common::String baseConfigName) - : - _baseConfigName(baseConfigName) { -} - -void OSystem_POSIX::init() { - // Initialze File System Factory - _fsFactory = new POSIXFilesystemFactory(); - - // Invoke parent implementation of this method - OSystem_SDL::init(); -} - -void OSystem_POSIX::initBackend() { - // Create the savefile manager - if (_savefileManager == 0) - _savefileManager = new POSIXSaveFileManager(); - - // Invoke parent implementation of this method - OSystem_SDL::initBackend(); -} - -Common::String OSystem_POSIX::getDefaultConfigFileName() { - char configFile[MAXPATHLEN]; - - // On UNIX type systems, by default we store the config file inside - // to the HOME directory of the user. - const char *home = getenv("HOME"); - if (home != NULL && strlen(home) < MAXPATHLEN) - snprintf(configFile, MAXPATHLEN, "%s/%s", home, _baseConfigName.c_str()); - else - strcpy(configFile, _baseConfigName.c_str()); - - return configFile; -} - -#endif diff --git a/backends/platform/sdl/posix/posix.h b/backends/platform/sdl/posix/posix.h deleted file mode 100644 index 13f9304f1e..0000000000 --- a/backends/platform/sdl/posix/posix.h +++ /dev/null @@ -1,48 +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$ - * - */ - -#ifndef PLATFORM_SDL_POSIX_H -#define PLATFORM_SDL_POSIX_H - -#include "backends/platform/sdl/sdl.h" - -class OSystem_POSIX : public OSystem_SDL { -public: - // Let the subclasses be able to change _baseConfigName in the constructor - OSystem_POSIX(Common::String baseConfigName = ".scummvmrc"); - virtual ~OSystem_POSIX() {} - - virtual void init(); - virtual void initBackend(); - -protected: - // Base string for creating the default path and filename - // for the configuration file - Common::String _baseConfigName; - - virtual Common::String getDefaultConfigFileName(); -}; - -#endif diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index fbfb83fa1d..2e3819f6f5 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -23,149 +23,346 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#if defined(WIN32) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +// winnt.h defines ARRAYSIZE, but we want our own one... - this is needed before including util.h +#undef ARRAYSIZE +#endif + #include "backends/platform/sdl/sdl.h" +#include "common/archive.h" #include "common/config-manager.h" +#include "common/debug.h" #include "common/EventRecorder.h" +#include "common/util.h" -#include "backends/saves/default/default-saves.h" -#include "backends/audiocd/sdl/sdl-audiocd.h" -#include "backends/events/sdl/sdl-events.h" -#include "backends/mutex/sdl/sdl-mutex.h" -#include "backends/timer/sdl/sdl-timer.h" -#include "backends/graphics/sdl/sdl-graphics.h" -#ifdef USE_OPENGL -#include "backends/graphics/openglsdl/openglsdl-graphics.h" +#ifdef UNIX + #include "backends/saves/posix/posix-saves.h" +#else + #include "backends/saves/default/default-saves.h" #endif +#include "backends/audiocd/sdl/sdl-audiocd.h" +#include "backends/timer/default/default-timer.h" +#include "sound/mixer_intern.h" #include "icons/scummvm.xpm" -#include <time.h> +#include <time.h> // for getTimeAndDate() -OSystem_SDL::OSystem_SDL() - : -#ifdef USE_OPENGL - _graphicsModes(0), - _graphicsMode(0), - _sdlModesCount(0), - _glModesCount(0), +//#define SAMPLES_PER_SEC 11025 +#define SAMPLES_PER_SEC 22050 +//#define SAMPLES_PER_SEC 44100 + + +/* + * Include header files needed for the getFilesystemFactory() method. + */ +#if defined(__amigaos4__) + #include "backends/fs/amigaos4/amigaos4-fs-factory.h" +#elif defined(UNIX) + #include "backends/fs/posix/posix-fs-factory.h" +#elif defined(WIN32) + #include "backends/fs/windows/windows-fs-factory.h" +#endif + + +#if defined(UNIX) +#ifdef MACOSX +#define DEFAULT_CONFIG_FILE "Library/Preferences/ScummVM Preferences" +#elif defined(SAMSUNGTV) +#define DEFAULT_CONFIG_FILE "/dtv/usb/sda1/.scummvmrc" +#else +#define DEFAULT_CONFIG_FILE ".scummvmrc" +#endif +#else +#define DEFAULT_CONFIG_FILE "scummvm.ini" +#endif + +#if defined(MACOSX) || defined(IPHONE) +#include <CoreFoundation/CoreFoundation.h> #endif - _inited(false), - _initedSDL(false), - _mixerManager(0), - _eventSource(0) { + +static Uint32 timer_handler(Uint32 interval, void *param) { + ((DefaultTimerManager *)param)->handler(); + return interval; } -OSystem_SDL::~OSystem_SDL() { - deinit(); +AspectRatio::AspectRatio(int w, int h) { + // TODO : Validation and so on... + // Currently, we just ensure the program don't instantiate non-supported aspect ratios + _kw = w; + _kh = h; } -void OSystem_SDL::init() { - // Initialize SDL - initSDL(); +#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) && defined(USE_SCALERS) +static AspectRatio getDesiredAspectRatio() { + const size_t AR_COUNT = 4; + const char* desiredAspectRatioAsStrings[AR_COUNT] = { "auto", "4/3", "16/9", "16/10" }; + const AspectRatio desiredAspectRatios[AR_COUNT] = { AspectRatio(0, 0), AspectRatio(4,3), AspectRatio(16,9), AspectRatio(16,10) }; - // Creates the early needed managers, if they don't exist yet - // (we check for this to allow subclasses to provide their own). - if (_mutexManager == 0) - _mutexManager = new SdlMutexManager(); + //TODO : We could parse an arbitrary string, if we code enough proper validation + Common::String desiredAspectRatio = ConfMan.get("desired_screen_aspect_ratio"); - if (_timerManager == 0) - _timerManager = new SdlTimerManager(); + for (size_t i = 0; i < AR_COUNT; i++) { + assert(desiredAspectRatioAsStrings[i] != NULL); - #ifdef USE_OPENGL - // Setup a list with both SDL and OpenGL graphics modes - setupGraphicsModes(); - #endif + if (!scumm_stricmp(desiredAspectRatio.c_str(), desiredAspectRatioAsStrings[i])) { + return desiredAspectRatios[i]; + } + } + // TODO : Report a warning + return AspectRatio(0, 0); } +#endif + +#if defined(WIN32) + struct SdlConsoleHidingWin32 { + DWORD myPid; + DWORD myTid; + HWND consoleHandle; + }; + + // console hiding for win32 + static BOOL CALLBACK initBackendFindConsoleWin32Proc(HWND hWnd, LPARAM lParam) { + DWORD pid, tid; + SdlConsoleHidingWin32 *variables = (SdlConsoleHidingWin32 *)lParam; + tid = GetWindowThreadProcessId(hWnd, &pid); + if ((tid == variables->myTid) && (pid == variables->myPid)) { + variables->consoleHandle = hWnd; + return FALSE; + } + return TRUE; + } +#endif void OSystem_SDL::initBackend() { - // Check if backend has not been initialized assert(!_inited); - // Create the default event source, in case a custom backend - // manager didn't provide one yet. - if (_eventSource == 0) - _eventSource = new SdlEventSource(); - - int graphicsManagerType = 0; + int joystick_num = ConfMan.getInt("joystick_num"); + uint32 sdlFlags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER; - if (_graphicsManager == 0) { -#ifdef USE_OPENGL - if (ConfMan.hasKey("gfx_mode")) { - Common::String gfxMode(ConfMan.get("gfx_mode")); - bool use_opengl = false; - const OSystem::GraphicsMode *mode = OpenGLSdlGraphicsManager::supportedGraphicsModes(); - while (mode->name) { - if (scumm_stricmp(mode->name, gfxMode.c_str()) == 0) - use_opengl = true; + if (ConfMan.hasKey("disable_sdl_parachute")) + sdlFlags |= SDL_INIT_NOPARACHUTE; - mode++; - } +#ifdef _WIN32_WCE + if (ConfMan.hasKey("use_GDI") && ConfMan.getBool("use_GDI")) { + SDL_VideoInit("windib", 0); + sdlFlags ^= SDL_INIT_VIDEO; + } +#endif - // If the gfx_mode is from OpenGL, create the OpenGL graphics manager - if (use_opengl) { - _graphicsManager = new OpenGLSdlGraphicsManager(); - graphicsManagerType = 1; - } + if (joystick_num > -1) + sdlFlags |= SDL_INIT_JOYSTICK; + +#if 0 + // NEW CODE TO HIDE CONSOLE FOR WIN32 +#if defined(WIN32) + // console hiding for win32 + SdlConsoleHidingWin32 consoleHidingWin32; + consoleHidingWin32.consoleHandle = 0; + consoleHidingWin32.myPid = GetCurrentProcessId(); + consoleHidingWin32.myTid = GetCurrentThreadId(); + EnumWindows (initBackendFindConsoleWin32Proc, (LPARAM)&consoleHidingWin32); + + if (!ConfMan.getBool("show_console")) { + if (consoleHidingWin32.consoleHandle) { + // We won't find a window with our TID/PID in case we were started from command-line + ShowWindow(consoleHidingWin32.consoleHandle, SW_HIDE); } + } #endif - if (_graphicsManager == 0) { - _graphicsManager = new SdlGraphicsManager(_eventSource); - graphicsManagerType = 0; - } +#endif + + if (SDL_Init(sdlFlags) == -1) { + error("Could not initialize SDL: %s", SDL_GetError()); } - // Creates the backend managers, if they don't exist yet (we check - // for this to allow subclasses to provide their own). - if (_eventManager == 0) - _eventManager = new DefaultEventManager(_eventSource); - - // We have to initialize the graphics manager before the event manager - // so the virtual keyboard can be initialized, but we have to add the - // graphics manager as an event observer after initializing the event - // manager. - if (graphicsManagerType == 0) - ((SdlGraphicsManager *)_graphicsManager)->initEventObserver(); -#ifdef USE_OPENGL - else if (graphicsManagerType == 1) - ((OpenGLSdlGraphicsManager *)_graphicsManager)->initEventObserver(); -#endif + _graphicsMutex = createMutex(); - if (_savefileManager == 0) - _savefileManager = new DefaultSaveFileManager(); + SDL_ShowCursor(SDL_DISABLE); - if (_mixerManager == 0) { - _mixerManager = new SdlMixerManager(); + // Enable unicode support if possible + SDL_EnableUNICODE(1); - // Setup and start mixer - _mixerManager->init(); - } + memset(&_oldVideoMode, 0, sizeof(_oldVideoMode)); + memset(&_videoMode, 0, sizeof(_videoMode)); + memset(&_transactionDetails, 0, sizeof(_transactionDetails)); - if (_audiocdManager == 0) - _audiocdManager = new SdlAudioCDManager(); +#if !defined(_WIN32_WCE) && !defined(DINGUX) && !defined(__SYMBIAN32__) && defined(USE_SCALERS) + _videoMode.mode = GFX_DOUBLESIZE; + _videoMode.scaleFactor = 2; + _videoMode.aspectRatioCorrection = ConfMan.getBool("aspect_ratio"); + _videoMode.desiredAspectRatio = getDesiredAspectRatio(); + _scalerProc = Normal2x; +#else // for small screen platforms + _videoMode.mode = GFX_NORMAL; + _videoMode.scaleFactor = 1; + _videoMode.aspectRatioCorrection = false; + _scalerProc = Normal1x; +#endif + _scalerType = 0; +#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) + _videoMode.fullscreen = ConfMan.getBool("fullscreen"); +#else + _videoMode.fullscreen = true; +#endif + +#if !defined(MACOSX) && !defined(__SYMBIAN32__) // Setup a custom program icon. + // Don't set icon on OS X, as we use a nicer external icon there. + // Don't for Symbian: it uses the EScummVM.aif file for the icon. setupIcon(); +#endif + + // enable joystick + if (joystick_num > -1 && SDL_NumJoysticks() > 0) { + printf("Using joystick: %s\n", SDL_JoystickName(0)); + _joystick = SDL_JoystickOpen(joystick_num); + } + + + // Create the savefile manager, if none exists yet (we check for this to + // allow subclasses to provide their own). + if (_savefile == 0) { +#ifdef UNIX + _savefile = new POSIXSaveFileManager(); +#else + _savefile = new DefaultSaveFileManager(); +#endif + } + + // Create and hook up the mixer, if none exists yet (we check for this to + // allow subclasses to provide their own). + if (_mixer == 0) { + setupMixer(); + } + + // Create and hook up the timer manager, if none exists yet (we check for + // this to allow subclasses to provide their own). + if (_timer == 0) { + // Note: We could implement a custom SDLTimerManager by using + // SDL_AddTimer. That might yield better timer resolution, but it would + // also change the semantics of a timer: Right now, ScummVM timers + // *never* run in parallel, due to the way they are implemented. If we + // switched to SDL_AddTimer, each timer might run in a separate thread. + // However, not all our code is prepared for that, so we can't just + // switch. Still, it's a potential future change to keep in mind. + _timer = new DefaultTimerManager(); + _timerID = SDL_AddTimer(10, &timer_handler, _timer); + } + + // Invoke parent implementation of this method + OSystem::initBackend(); _inited = true; } -void OSystem_SDL::initSDL() { - // Check if SDL has not been initialized - if (!_initedSDL) { - uint32 sdlFlags = 0; - if (ConfMan.hasKey("disable_sdl_parachute")) - sdlFlags |= SDL_INIT_NOPARACHUTE; +OSystem_SDL::OSystem_SDL() + : +#ifdef USE_OSD + _osdSurface(0), _osdAlpha(SDL_ALPHA_TRANSPARENT), _osdFadeStartTime(0), +#endif + _hwscreen(0), _screen(0), _tmpscreen(0), +#ifdef USE_RGB_COLOR + _screenFormat(Graphics::PixelFormat::createFormatCLUT8()), + _cursorFormat(Graphics::PixelFormat::createFormatCLUT8()), +#endif + _overlayVisible(false), + _overlayscreen(0), _tmpscreen2(0), + _cdrom(0), _scalerProc(0), _modeChanged(false), _screenChangeCount(0), + _scrollLock(false), + _mouseVisible(false), _mouseNeedsRedraw(false), _mouseData(0), _mouseSurface(0), + _mouseOrigSurface(0), _cursorTargetScale(1), _cursorPaletteDisabled(true), + _joystick(0), + _currentShakePos(0), _newShakePos(0), + _paletteDirtyStart(0), _paletteDirtyEnd(0), +#if MIXER_DOUBLE_BUFFERING + _soundMutex(0), _soundCond(0), _soundThread(0), + _soundThreadIsRunning(false), _soundThreadShouldQuit(false), +#endif + _fsFactory(0), + _savefile(0), + _mixer(0), + _timer(0), + _screenIsLocked(false), + _graphicsMutex(0), _transactionMode(kTransactionNone) { + + // clear palette storage + memset(_currentPalette, 0, sizeof(_currentPalette)); + memset(_cursorPalette, 0, sizeof(_cursorPalette)); + + _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0; + + // reset mouse state + memset(&_km, 0, sizeof(_km)); + memset(&_mouseCurState, 0, sizeof(_mouseCurState)); + + _inited = false; + + + #if defined(__amigaos4__) + _fsFactory = new AmigaOSFilesystemFactory(); + #elif defined(UNIX) + _fsFactory = new POSIXFilesystemFactory(); + #elif defined(WIN32) + _fsFactory = new WindowsFilesystemFactory(); + #elif defined(__SYMBIAN32__) + // Do nothing since its handled by the Symbian SDL inheritance + #else + #error Unknown and unsupported FS backend + #endif +} + +OSystem_SDL::~OSystem_SDL() { + SDL_RemoveTimer(_timerID); + closeMixer(); - // Initialize SDL (SDL Subsystems are initiliazed in the corresponding sdl managers) - if (SDL_Init(sdlFlags) == -1) - error("Could not initialize SDL: %s", SDL_GetError()); + free(_mouseData); - // Enable unicode support if possible - SDL_EnableUNICODE(1); + delete _savefile; + delete _timer; +} - _initedSDL = true; - } +uint32 OSystem_SDL::getMillis() { + uint32 millis = SDL_GetTicks(); + g_eventRec.processMillis(millis); + return millis; +} + +void OSystem_SDL::delayMillis(uint msecs) { + SDL_Delay(msecs); +} + +void OSystem_SDL::getTimeAndDate(TimeDate &td) const { + time_t curTime = time(0); + struct tm t = *localtime(&curTime); + td.tm_sec = t.tm_sec; + td.tm_min = t.tm_min; + td.tm_hour = t.tm_hour; + td.tm_mday = t.tm_mday; + td.tm_mon = t.tm_mon; + td.tm_year = t.tm_year; +} + +Common::TimerManager *OSystem_SDL::getTimerManager() { + assert(_timer); + return _timer; +} + +Common::SaveFileManager *OSystem_SDL::getSavefileManager() { + assert(_savefile); + return _savefile; +} + +FilesystemFactory *OSystem_SDL::getFilesystemFactory() { + assert(_fsFactory); + return _fsFactory; } void OSystem_SDL::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { @@ -179,10 +376,88 @@ void OSystem_SDL::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) } #endif +#ifdef MACOSX + // Get URL of the Resource directory of the .app bundle + CFURLRef fileUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); + if (fileUrl) { + // Try to convert the URL to an absolute path + UInt8 buf[MAXPATHLEN]; + if (CFURLGetFileSystemRepresentation(fileUrl, true, buf, sizeof(buf))) { + // Success: Add it to the search path + Common::String bundlePath((const char *)buf); + s.add("__OSX_BUNDLE__", new Common::FSDirectory(bundlePath), priority); + } + CFRelease(fileUrl); + } + +#endif + } -Common::String OSystem_SDL::getDefaultConfigFileName() { - return "scummvm.ini"; + +static Common::String getDefaultConfigFileName() { + char configFile[MAXPATHLEN]; +#if defined (WIN32) && !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) + OSVERSIONINFO win32OsVersion; + ZeroMemory(&win32OsVersion, sizeof(OSVERSIONINFO)); + win32OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&win32OsVersion); + // Check for non-9X version of Windows. + if (win32OsVersion.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) { + // Use the Application Data directory of the user profile. + if (win32OsVersion.dwMajorVersion >= 5) { + if (!GetEnvironmentVariable("APPDATA", configFile, sizeof(configFile))) + error("Unable to access application data directory"); + } else { + if (!GetEnvironmentVariable("USERPROFILE", configFile, sizeof(configFile))) + error("Unable to access user profile directory"); + + strcat(configFile, "\\Application Data"); + CreateDirectory(configFile, NULL); + } + + strcat(configFile, "\\ScummVM"); + CreateDirectory(configFile, NULL); + strcat(configFile, "\\" DEFAULT_CONFIG_FILE); + + FILE *tmp = NULL; + if ((tmp = fopen(configFile, "r")) == NULL) { + // Check windows directory + char oldConfigFile[MAXPATHLEN]; + GetWindowsDirectory(oldConfigFile, MAXPATHLEN); + strcat(oldConfigFile, "\\" DEFAULT_CONFIG_FILE); + if ((tmp = fopen(oldConfigFile, "r"))) { + strcpy(configFile, oldConfigFile); + + fclose(tmp); + } + } else { + fclose(tmp); + } + } else { + // Check windows directory + GetWindowsDirectory(configFile, MAXPATHLEN); + strcat(configFile, "\\" DEFAULT_CONFIG_FILE); + } +#elif defined(UNIX) + // On UNIX type systems, by default we store the config file inside + // to the HOME directory of the user. + // + // GP2X is Linux based but Home dir can be read only so do not use + // it and put the config in the executable dir. + // + // On the iPhone, the home dir of the user when you launch the app + // from the Springboard, is /. Which we don't want. + const char *home = getenv("HOME"); + if (home != NULL && strlen(home) < MAXPATHLEN) + snprintf(configFile, MAXPATHLEN, "%s/%s", home, DEFAULT_CONFIG_FILE); + else + strcpy(configFile, DEFAULT_CONFIG_FILE); +#else + strcpy(configFile, DEFAULT_CONFIG_FILE); +#endif + + return configFile; } Common::SeekableReadStream *OSystem_SDL::createConfigReadStream() { @@ -213,36 +488,78 @@ void OSystem_SDL::setWindowCaption(const char *caption) { SDL_WM_SetCaption(cap.c_str(), cap.c_str()); } +bool OSystem_SDL::hasFeature(Feature f) { + return + (f == kFeatureFullscreenMode) || + (f == kFeatureAspectRatioCorrection) || + (f == kFeatureCursorHasPalette) || + (f == kFeatureIconifyWindow); +} + +void OSystem_SDL::setFeatureState(Feature f, bool enable) { + switch (f) { + case kFeatureFullscreenMode: + setFullscreenMode(enable); + break; + case kFeatureAspectRatioCorrection: + setAspectRatioCorrection(enable); + break; + case kFeatureIconifyWindow: + if (enable) + SDL_WM_IconifyWindow(); + break; + default: + break; + } +} + +bool OSystem_SDL::getFeatureState(Feature f) { + assert (_transactionMode == kTransactionNone); + + switch (f) { + case kFeatureFullscreenMode: + return _videoMode.fullscreen; + case kFeatureAspectRatioCorrection: + return _videoMode.aspectRatioCorrection; + default: + return false; + } +} + void OSystem_SDL::deinit() { + if (_cdrom) { + SDL_CDStop(_cdrom); + SDL_CDClose(_cdrom); + } + unloadGFXMode(); + deleteMutex(_graphicsMutex); + + if (_joystick) + SDL_JoystickClose(_joystick); + SDL_ShowCursor(SDL_ENABLE); - delete _savefileManager; - _savefileManager = 0; - delete _graphicsManager; - _graphicsManager = 0; - delete _eventManager; - _eventManager = 0; - delete _eventSource; - _eventSource = 0; - delete _audiocdManager; - _audiocdManager = 0; - delete _mixerManager; - _mixerManager = 0; - delete _timerManager; - _timerManager = 0; - delete _mutexManager; - _mutexManager = 0; - -#ifdef USE_OPENGL - delete[] _graphicsModes; -#endif + SDL_RemoveTimer(_timerID); + closeMixer(); + + free(_mouseData); + + delete _timer; SDL_Quit(); + + // Event Manager requires save manager for storing + // recorded events + delete getEventManager(); + delete _savefile; } void OSystem_SDL::quit() { deinit(); + +#if !defined(SAMSUNGTV) exit(0); +#endif } void OSystem_SDL::setupIcon() { @@ -297,128 +614,209 @@ void OSystem_SDL::setupIcon() { free(icon); } -uint32 OSystem_SDL::getMillis() { - uint32 millis = SDL_GetTicks(); - g_eventRec.processMillis(millis); - return millis; +OSystem::MutexRef OSystem_SDL::createMutex() { + return (MutexRef) SDL_CreateMutex(); } -void OSystem_SDL::delayMillis(uint msecs) { - SDL_Delay(msecs); +void OSystem_SDL::lockMutex(MutexRef mutex) { + SDL_mutexP((SDL_mutex *) mutex); } -void OSystem_SDL::getTimeAndDate(TimeDate &td) const { - time_t curTime = time(0); - struct tm t = *localtime(&curTime); - td.tm_sec = t.tm_sec; - td.tm_min = t.tm_min; - td.tm_hour = t.tm_hour; - td.tm_mday = t.tm_mday; - td.tm_mon = t.tm_mon; - td.tm_year = t.tm_year; +void OSystem_SDL::unlockMutex(MutexRef mutex) { + SDL_mutexV((SDL_mutex *) mutex); } -Audio::Mixer *OSystem_SDL::getMixer() { - assert(_mixerManager); - return _mixerManager->getMixer(); +void OSystem_SDL::deleteMutex(MutexRef mutex) { + SDL_DestroyMutex((SDL_mutex *) mutex); } -SdlMixerManager *OSystem_SDL::getMixerManager() { - assert(_mixerManager); - return _mixerManager; -} +#pragma mark - +#pragma mark --- Audio --- +#pragma mark - -#ifdef USE_OPENGL +#if MIXER_DOUBLE_BUFFERING -const OSystem::GraphicsMode *OSystem_SDL::getSupportedGraphicsModes() const { - return _graphicsModes; -} +void OSystem_SDL::mixerProducerThread() { + byte nextSoundBuffer; -int OSystem_SDL::getDefaultGraphicsMode() const { - // Return the default graphics mode from the current graphics manager - if (_graphicsMode < _sdlModesCount) - return _graphicsManager->getDefaultGraphicsMode(); - else - return _graphicsManager->getDefaultGraphicsMode() + _sdlModesCount; -} + SDL_LockMutex(_soundMutex); + while (true) { + // Wait till we are allowed to produce data + SDL_CondWait(_soundCond, _soundMutex); -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(); - i = 0; - } else { - 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) { - delete _graphicsManager; - _graphicsManager = new SdlGraphicsManager(_eventSource); - ((SdlGraphicsManager *)_graphicsManager)->initEventObserver(); - _graphicsManager->beginGFXTransaction(); - } else if (_graphicsMode < _sdlModesCount && mode >= _sdlModesCount) { - delete _graphicsManager; - _graphicsManager = new OpenGLSdlGraphicsManager(); - ((OpenGLSdlGraphicsManager *)_graphicsManager)->initEventObserver(); - _graphicsManager->beginGFXTransaction(); - } - _graphicsMode = mode; - return _graphicsManager->setGraphicsMode(srcMode->id); - } - i++; - srcMode++; + if (_soundThreadShouldQuit) + break; + + // Generate samples and put them into the next buffer + nextSoundBuffer = _activeSoundBuf ^ 1; + _mixer->mixCallback(_soundBuffers[nextSoundBuffer], _soundBufSize); + + // Swap buffers + _activeSoundBuf = nextSoundBuffer; } - return false; + SDL_UnlockMutex(_soundMutex); } -int OSystem_SDL::getGraphicsMode() const { - return _graphicsMode; +int SDLCALL OSystem_SDL::mixerProducerThreadEntry(void *arg) { + OSystem_SDL *this_ = (OSystem_SDL *)arg; + assert(this_); + this_->mixerProducerThread(); + return 0; } -void OSystem_SDL::setupGraphicsModes() { - const OSystem::GraphicsMode *sdlGraphicsModes = SdlGraphicsManager::supportedGraphicsModes(); - const OSystem::GraphicsMode *openglGraphicsModes = OpenGLSdlGraphicsManager::supportedGraphicsModes(); - _sdlModesCount = 0; - _glModesCount = 0; - // Count the number of graphics modes - const OSystem::GraphicsMode *srcMode = sdlGraphicsModes; - while (srcMode->name) { - _sdlModesCount++; - srcMode++; - } - srcMode = openglGraphicsModes; - while (srcMode->name) { - _glModesCount++; - srcMode++; +void OSystem_SDL::initThreadedMixer(Audio::MixerImpl *mixer, uint bufSize) { + _soundThreadIsRunning = false; + _soundThreadShouldQuit = false; + + // Create mutex and condition variable + _soundMutex = SDL_CreateMutex(); + _soundCond = SDL_CreateCond(); + + // Create two sound buffers + _activeSoundBuf = 0; + _soundBufSize = bufSize; + _soundBuffers[0] = (byte *)calloc(1, bufSize); + _soundBuffers[1] = (byte *)calloc(1, bufSize); + + _soundThreadIsRunning = true; + + // Finally start the thread + _soundThread = SDL_CreateThread(mixerProducerThreadEntry, this); +} + +void OSystem_SDL::deinitThreadedMixer() { + // Kill thread?? _soundThread + + if (_soundThreadIsRunning) { + // Signal the producer thread to end, and wait for it to actually finish. + _soundThreadShouldQuit = true; + SDL_CondBroadcast(_soundCond); + SDL_WaitThread(_soundThread, NULL); + + // Kill the mutex & cond variables. + // Attention: AT this point, the mixer callback must not be running + // anymore, else we will crash! + SDL_DestroyMutex(_soundMutex); + SDL_DestroyCond(_soundCond); + + _soundThreadIsRunning = false; + + free(_soundBuffers[0]); + free(_soundBuffers[1]); } +} + - // Allocate enough space for merged array of modes - _graphicsModes = new OSystem::GraphicsMode[_glModesCount + _sdlModesCount + 1]; +void OSystem_SDL::mixCallback(void *arg, byte *samples, int len) { + OSystem_SDL *this_ = (OSystem_SDL *)arg; + assert(this_); + assert(this_->_mixer); - // Copy SDL graphics modes - memcpy((void *)_graphicsModes, sdlGraphicsModes, _sdlModesCount * sizeof(OSystem::GraphicsMode)); + assert((int)this_->_soundBufSize == len); - // Copy OpenGL graphics modes - memcpy((void *)(_graphicsModes + _sdlModesCount), openglGraphicsModes, _glModesCount * sizeof(OSystem::GraphicsMode)); + // Lock mutex, to ensure our data is not overwritten by the producer thread + SDL_LockMutex(this_->_soundMutex); - // Set a null mode at the end - memset((void *)(_graphicsModes + _sdlModesCount + _glModesCount), 0, sizeof(OSystem::GraphicsMode)); + // Copy data from the current sound buffer + memcpy(samples, this_->_soundBuffers[this_->_activeSoundBuf], len); - // Set new internal ids for all modes - int i = 0; - OSystem::GraphicsMode *mode = _graphicsModes; - while (mode->name) { - mode->id = i++; - mode++; + // Unlock mutex and wake up the produced thread + SDL_UnlockMutex(this_->_soundMutex); + SDL_CondSignal(this_->_soundCond); +} + +#else + +void OSystem_SDL::mixCallback(void *sys, byte *samples, int len) { + OSystem_SDL *this_ = (OSystem_SDL *)sys; + assert(this_); + assert(this_->_mixer); + + this_->_mixer->mixCallback(samples, len); +} + +#endif + +void OSystem_SDL::setupMixer() { + SDL_AudioSpec desired; + + // Determine the desired output sampling frequency. + uint32 samplesPerSec = 0; + if (ConfMan.hasKey("output_rate")) + samplesPerSec = ConfMan.getInt("output_rate"); + if (samplesPerSec <= 0) + samplesPerSec = SAMPLES_PER_SEC; + + // Determine the sample buffer size. We want it to store enough data for + // at least 1/16th of a second (though at most 8192 samples). Note + // that it must be a power of two. So e.g. at 22050 Hz, we request a + // sample buffer size of 2048. + uint32 samples = 8192; + while (samples * 16 > samplesPerSec * 2) + samples >>= 1; + + memset(&desired, 0, sizeof(desired)); + desired.freq = samplesPerSec; + desired.format = AUDIO_S16SYS; + desired.channels = 2; + desired.samples = (uint16)samples; + desired.callback = mixCallback; + desired.userdata = this; + + assert(!_mixer); + if (SDL_OpenAudio(&desired, &_obtainedRate) != 0) { + warning("Could not open audio device: %s", SDL_GetError()); + _mixer = new Audio::MixerImpl(this, samplesPerSec); + assert(_mixer); + _mixer->setReady(false); + } else { + // Note: This should be the obtained output rate, but it seems that at + // least on some platforms SDL will lie and claim it did get the rate + // even if it didn't. Probably only happens for "weird" rates, though. + samplesPerSec = _obtainedRate.freq; + debug(1, "Output sample rate: %d Hz", samplesPerSec); + + // Create the mixer instance and start the sound processing + _mixer = new Audio::MixerImpl(this, samplesPerSec); + assert(_mixer); + _mixer->setReady(true); + +#if MIXER_DOUBLE_BUFFERING + initThreadedMixer(_mixer, _obtainedRate.samples * 4); +#endif + + // start the sound system + SDL_PauseAudio(0); } } +void OSystem_SDL::closeMixer() { + if (_mixer) + _mixer->setReady(false); + + SDL_CloseAudio(); + + delete _mixer; + _mixer = 0; + +#if MIXER_DOUBLE_BUFFERING + deinitThreadedMixer(); #endif + +} + +Audio::Mixer *OSystem_SDL::getMixer() { + assert(_mixer); + return _mixer; +} + +#pragma mark - +#pragma mark --- CD Audio --- +#pragma mark - + +AudioCDManager *OSystem_SDL::getAudioCDManager() { + if (!_audiocdManager) + _audiocdManager = new SdlAudioCDManager(); + return _audiocdManager; +} diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h index 5b1ce8f803..b701824517 100644 --- a/backends/platform/sdl/sdl.h +++ b/backends/platform/sdl/sdl.h @@ -23,8 +23,8 @@ * */ -#ifndef PLATFORM_SDL_H -#define PLATFORM_SDL_H +#ifndef SDL_COMMON_H +#define SDL_COMMON_H #if defined(__SYMBIAN32__) #include <esdl\SDL.h> @@ -32,99 +32,451 @@ #include <SDL.h> #endif -#include "backends/modular-backend.h" -#include "backends/mixer/sdl/sdl-mixer.h" -#include "backends/events/sdl/sdl-events.h" +#include "backends/base-backend.h" +#include "graphics/scaler.h" -/** - * Base OSystem class for all SDL ports. - */ -class OSystem_SDL : public ModularBackend { + +namespace Audio { + class MixerImpl; +} + +#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) +// Uncomment this to enable the 'on screen display' code. +#define USE_OSD 1 +#endif + +#if defined(MACOSX) +// On Mac OS X, we need to double buffer the audio buffer, else anything +// which produces sampled data with high latency (like the MT-32 emulator) +// will sound terribly. +// This could be enabled for more / most ports in the future, but needs some +// testing. +#define MIXER_DOUBLE_BUFFERING 1 +#endif + + +enum { + GFX_NORMAL = 0, + GFX_DOUBLESIZE = 1, + GFX_TRIPLESIZE = 2, + GFX_2XSAI = 3, + GFX_SUPER2XSAI = 4, + GFX_SUPEREAGLE = 5, + GFX_ADVMAME2X = 6, + GFX_ADVMAME3X = 7, + GFX_HQ2X = 8, + GFX_HQ3X = 9, + GFX_TV2X = 10, + GFX_DOTMATRIX = 11 +}; + +class AspectRatio { + int _kw, _kh; +public: + AspectRatio() { _kw = _kh = 0; } + AspectRatio(int w, int h); + + bool isAuto() const { return (_kw | _kh) == 0; } + + int kw() const { return _kw; } + int kh() const { return _kh; } +}; + + +class OSystem_SDL : public BaseBackend { public: OSystem_SDL(); virtual ~OSystem_SDL(); - /** - * Pre-initialize backend. It should be called after - * instantiating the backend. Early needed managers are - * created here. - */ - virtual void init(); + virtual void initBackend(); - /** - * Get the Mixer Manager instance. Not to confuse with getMixer(), - * that returns Audio::Mixer. The Mixer Manager is a SDL wrapper class - * for the Audio::Mixer. Used by other managers. - */ - virtual SdlMixerManager *getMixerManager(); + void beginGFXTransaction(); + TransactionError endGFXTransaction(); - // Override functions from ModularBackend and OSystem - virtual void initBackend(); +#ifdef USE_RGB_COLOR + // Game screen + virtual Graphics::PixelFormat getScreenFormat() const { return _screenFormat; } + + // Highest supported + virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const; +#endif + + // Set the size and format of the video bitmap. + // Typically, 320x200 CLUT8 + virtual void initSize(uint w, uint h, const Graphics::PixelFormat *format); // overloaded by CE backend + + virtual int getScreenChangeID() const { return _screenChangeCount; } + + // Set colors of the palette + void setPalette(const byte *colors, uint start, uint num); + + // Get colors of the palette + void grabPalette(byte *colors, uint start, uint num); + + // Draw a bitmap to screen. + // The screen will not be updated to reflect the new bitmap + virtual void copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h); // overloaded by CE backend (FIXME) + + virtual Graphics::Surface *lockScreen(); + virtual void unlockScreen(); + + // Update the dirty areas of the screen + void updateScreen(); + + // Either show or hide the mouse cursor + bool showMouse(bool visible); + + // Warp the mouse cursor. Where set_mouse_pos() only informs the + // backend of the mouse cursor's current position, this function + // actually moves the cursor to the specified position. + virtual void warpMouse(int x, int y); // overloaded by CE backend (FIXME) + + // Set the bitmap that's used when drawing the cursor. + virtual 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 (FIXME) + + // Set colors of cursor palette + void setCursorPalette(const byte *colors, uint start, uint num); + + // Disables or enables cursor palette + void disableCursorPalette(bool disable) { + _cursorPaletteDisabled = disable; + blitCursor(); + } + + // Shaking is used in SCUMM. Set current shake position. + void setShakePos(int shake_pos); + + // Get the number of milliseconds since the program was started. + uint32 getMillis(); + + // Delay for a specified amount of milliseconds + void delayMillis(uint msecs); + + // Get the next event. + // Returns true if an event was retrieved. + virtual bool pollEvent(Common::Event &event); // overloaded by CE backend + +protected: + virtual bool dispatchSDLEvent(SDL_Event &ev, Common::Event &event); + + // Handlers for specific SDL events, called by pollEvent. + // This way, if a backend inherits fromt the SDL backend, it can + // change the behavior of only a single event, without having to override all + // of pollEvent. + virtual bool handleKeyDown(SDL_Event &ev, Common::Event &event); + virtual bool handleKeyUp(SDL_Event &ev, Common::Event &event); + virtual bool handleMouseMotion(SDL_Event &ev, Common::Event &event); + virtual bool handleMouseButtonDown(SDL_Event &ev, Common::Event &event); + virtual bool handleMouseButtonUp(SDL_Event &ev, Common::Event &event); + virtual bool handleJoyButtonDown(SDL_Event &ev, Common::Event &event); + virtual bool handleJoyButtonUp(SDL_Event &ev, Common::Event &event); + virtual bool handleJoyAxisMotion(SDL_Event &ev, Common::Event &event); + +public: + + + // Define all hardware keys for keymapper virtual Common::HardwareKeySet *getHardwareKeySet(); - virtual void quit(); - virtual void deinit(); + + // Set function that generates samples + virtual void setupMixer(); + static void mixCallback(void *s, byte *samples, int len); + + virtual void closeMixer(); + + virtual Audio::Mixer *getMixer(); + + virtual AudioCDManager *getAudioCDManager(); + + // Quit + virtual void quit(); // overloaded by CE backend + + void deinit(); + + virtual void getTimeAndDate(TimeDate &t) const; + virtual Common::TimerManager *getTimerManager(); + + // Mutex handling + MutexRef createMutex(); + void lockMutex(MutexRef mutex); + void unlockMutex(MutexRef mutex); + void deleteMutex(MutexRef mutex); + + // Overlay + virtual Graphics::PixelFormat getOverlayFormat() const { return _overlayFormat; } + + 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 getHeight(); + virtual int16 getWidth(); + virtual int16 getOverlayHeight() { return _videoMode.overlayHeight; } + virtual int16 getOverlayWidth() { return _videoMode.overlayWidth; } + + virtual const GraphicsMode *getSupportedGraphicsModes() const; + virtual int getDefaultGraphicsMode() const; + virtual bool setGraphicsMode(int mode); + virtual int getGraphicsMode() const; + virtual void setWindowCaption(const char *caption); + + virtual bool hasFeature(Feature f); + virtual void setFeatureState(Feature f, bool enable); + virtual bool getFeatureState(Feature f); + virtual void preprocessEvents(SDL_Event *event) {} + +#ifdef USE_OSD + void displayMessageOnOSD(const char *msg); +#endif + + virtual Common::SaveFileManager *getSavefileManager(); + virtual FilesystemFactory *getFilesystemFactory(); virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0); + virtual Common::SeekableReadStream *createConfigReadStream(); virtual Common::WriteStream *createConfigWriteStream(); - virtual uint32 getMillis(); - virtual void delayMillis(uint msecs); - virtual void getTimeAndDate(TimeDate &td) const; - virtual Audio::Mixer *getMixer(); - - // HACK: Special SDL events types - enum SdlEvent { - kSdlEventExpose = 100, - kSdlEventResize = 101 - }; protected: bool _inited; - bool _initedSDL; + SDL_AudioSpec _obtainedRate; - /** - * Mixer manager that configures and setups SDL for - * the wrapped Audio::Mixer, the true mixer. - */ - SdlMixerManager *_mixerManager; +#ifdef USE_OSD + SDL_Surface *_osdSurface; + Uint8 _osdAlpha; // Transparency level of the OSD + uint32 _osdFadeStartTime; // When to start the fade out + enum { + kOSDFadeOutDelay = 2 * 1000, // Delay before the OSD is faded out (in milliseconds) + kOSDFadeOutDuration = 500, // Duration of the OSD fade out (in milliseconds) + kOSDColorKey = 1, + kOSDInitialAlpha = 80 // Initial alpha level, in percent + }; +#endif - /** - * The event source we use for obtaining SDL events. - */ - SdlEventSource *_eventSource; + // hardware screen + SDL_Surface *_hwscreen; - /** - * Initialze the SDL library. - */ - virtual void initSDL(); + // unseen game screen + SDL_Surface *_screen; +#ifdef USE_RGB_COLOR + Graphics::PixelFormat _screenFormat; + Graphics::PixelFormat _cursorFormat; + Common::List<Graphics::PixelFormat> _supportedFormats; /** - * Setup the window icon. + * Update the list of supported pixel formats. + * This method is invoked by loadGFXMode(). */ - virtual void setupIcon(); + void detectSupportedFormats(); +#endif - /** - * Get the file path where the user configuration - * of ScummVM will be saved. - */ - virtual Common::String getDefaultConfigFileName(); + // temporary screen (for scalers) + SDL_Surface *_tmpscreen; + SDL_Surface *_tmpscreen2; + + // overlay + SDL_Surface *_overlayscreen; + bool _overlayVisible; + Graphics::PixelFormat _overlayFormat; + + // CD Audio + SDL_CD *_cdrom; + int _cdTrack, _cdNumLoops, _cdStartFrame, _cdDuration; + uint32 _cdEndTime, _cdStopTime; + + enum { + kTransactionNone = 0, + kTransactionActive = 1, + kTransactionRollback = 2 + }; + + struct TransactionDetails { + bool sizeChanged; + bool needHotswap; + bool needUpdatescreen; + bool normal1xScaler; +#ifdef USE_RGB_COLOR + bool formatChanged; +#endif + }; + TransactionDetails _transactionDetails; + + struct VideoState { + bool setup; + + bool fullscreen; + bool aspectRatioCorrection; + AspectRatio desiredAspectRatio; + + int mode; + int scaleFactor; + + int screenWidth, screenHeight; + int overlayWidth, overlayHeight; + int hardwareWidth, hardwareHeight; +#ifdef USE_RGB_COLOR + Graphics::PixelFormat format; +#endif + }; + VideoState _videoMode, _oldVideoMode; + + virtual void setGraphicsModeIntern(); // overloaded by CE backend + + /** Force full redraw on next updateScreen */ + bool _forceFull; + ScalerProc *_scalerProc; + int _scalerType; + int _transactionMode; + + bool _screenIsLocked; + Graphics::Surface _framebuffer; + + /** Current video mode flags (see DF_* constants) */ + bool _modeChanged; + int _screenChangeCount; + + enum { + NUM_DIRTY_RECT = 100, + MAX_SCALING = 3 + }; + + // Dirty rect management + SDL_Rect _dirtyRectList[NUM_DIRTY_RECT]; + int _numDirtyRects; + + // Keyboard mouse emulation. Disabled by fingolfin 2004-12-18. + // I am keeping the rest of the code in for now, since the joystick + // code (or rather, "hack") uses it, too. + struct KbdMouse { + int16 x, y, x_vel, y_vel, x_max, y_max, x_down_count, y_down_count; + uint32 last_time, delay_time, x_down_time, y_down_time; + }; + + struct MousePos { + // The mouse position, using either virtual (game) or real + // (overlay) coordinates. + int16 x, y; + + // The size and hotspot of the original cursor image. + int16 w, h; + int16 hotX, hotY; -#ifdef USE_OPENGL - OSystem::GraphicsMode *_graphicsModes; - int _graphicsMode; - int _sdlModesCount; - int _glModesCount; + // The size and hotspot of the pre-scaled cursor image, in real + // coordinates. + int16 rW, rH; + int16 rHotX, rHotY; + + // The size and hotspot of the pre-scaled cursor image, in game + // coordinates. + int16 vW, vH; + int16 vHotX, vHotY; + + MousePos() : x(0), y(0), w(0), h(0), hotX(0), hotY(0), + rW(0), rH(0), rHotX(0), rHotY(0), vW(0), vH(0), + vHotX(0), vHotY(0) + { } + }; + + // mouse + KbdMouse _km; + bool _mouseVisible; + bool _mouseNeedsRedraw; + byte *_mouseData; + SDL_Rect _mouseBackup; + MousePos _mouseCurState; +#ifdef USE_RGB_COLOR + uint32 _mouseKeyColor; +#else + byte _mouseKeyColor; +#endif + int _cursorTargetScale; + bool _cursorPaletteDisabled; + SDL_Surface *_mouseOrigSurface; + SDL_Surface *_mouseSurface; + enum { + kMouseColorKey = 1 + }; + + // Scroll lock state - since SDL doesn't track it + bool _scrollLock; + + // joystick + SDL_Joystick *_joystick; + + // Shake mode + int _currentShakePos; + int _newShakePos; + + // Palette data + SDL_Color _currentPalette[256]; + uint _paletteDirtyStart, _paletteDirtyEnd; + + // Cursor palette data + SDL_Color _cursorPalette[256]; /** - * Creates the merged graphics modes list + * Mutex which prevents multiple threads from interfering with each other + * when accessing the screen. */ - virtual void setupGraphicsModes(); + MutexRef _graphicsMutex; - virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const; - virtual int getDefaultGraphicsMode() const; - virtual bool setGraphicsMode(int mode); - virtual int getGraphicsMode() const; +#ifdef MIXER_DOUBLE_BUFFERING + SDL_mutex *_soundMutex; + SDL_cond *_soundCond; + SDL_Thread *_soundThread; + bool _soundThreadIsRunning; + bool _soundThreadShouldQuit; + + byte _activeSoundBuf; + uint _soundBufSize; + byte *_soundBuffers[2]; + + void mixerProducerThread(); + static int SDLCALL mixerProducerThreadEntry(void *arg); + void initThreadedMixer(Audio::MixerImpl *mixer, uint bufSize); + void deinitThreadedMixer(); #endif + + FilesystemFactory *_fsFactory; + Common::SaveFileManager *_savefile; + Audio::MixerImpl *_mixer; + + SDL_TimerID _timerID; + Common::TimerManager *_timer; + +protected: + virtual void addDirtyRect(int x, int y, int w, int h, bool realCoordinates = false); // overloaded by CE backend + + virtual void drawMouse(); // overloaded by CE backend + virtual void undrawMouse(); // overloaded by CE backend (FIXME) + virtual void blitCursor(); // overloaded by CE backend (FIXME) + + /** Set the position of the virtual mouse cursor. */ + void setMousePos(int x, int y); + virtual void fillMouseEvent(Common::Event &event, int x, int y); // overloaded by CE backend + void toggleMouseGrab(); + + virtual void internUpdateScreen(); // overloaded by CE backend + + virtual bool loadGFXMode(); // overloaded by CE backend + virtual void unloadGFXMode(); // overloaded by CE backend + virtual bool hotswapGFXMode(); // overloaded by CE backend + + void setFullscreenMode(bool enable); + void setAspectRatioCorrection(bool enable); + + virtual bool saveScreenshot(const char *filename); // overloaded by CE backend + + int effectiveScreenHeight() const; + + void setupIcon(); + void handleKbdMouse(); + + virtual bool remapKey(SDL_Event &ev, Common::Event &event); + + bool handleScalerHotkeys(const SDL_KeyboardEvent &key); + bool isScalerHotkey(const Common::Event &event); }; #endif diff --git a/backends/platform/sdl/win32/win32-main.cpp b/backends/platform/sdl/win32/win32-main.cpp deleted file mode 100644 index 25f208ddac..0000000000 --- a/backends/platform/sdl/win32/win32-main.cpp +++ /dev/null @@ -1,66 +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$ - * - */ - -#ifdef WIN32 - -// Fix for bug #2895217 "MSVC compilation broken with r47595": -// We need to keep this on top of the "common/scummsys.h"(base/main.h) include, -// otherwise we will get errors about the windows headers redefining -// "ARRAYSIZE" for example. -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#undef ARRAYSIZE // winnt.h defines ARRAYSIZE, but we want our own one... - -#include "backends/platform/sdl/win32/win32.h" -#include "backends/plugins/sdl/sdl-provider.h" -#include "base/main.h" - -int __stdcall WinMain(HINSTANCE /*hInst*/, HINSTANCE /*hPrevInst*/, LPSTR /*lpCmdLine*/, int /*iShowCmd*/) { - SDL_SetModuleHandle(GetModuleHandle(NULL)); - return main(__argc, __argv); -} - -int main(int argc, char *argv[]) { - // Create our OSystem instance - g_system = new OSystem_Win32(); - assert(g_system); - - // Pre initialize the backend - ((OSystem_Win32 *)g_system)->init(); - -#ifdef DYNAMIC_MODULES - PluginManager::instance().addPluginProvider(new SDLPluginProvider()); -#endif - - // Invoke the actual ScummVM main entry point: - int res = scummvm_main(argc, argv); - - // Free OSystem - delete (OSystem_Win32 *)g_system; - - return res; -} - -#endif diff --git a/backends/platform/sdl/win32/win32.cpp b/backends/platform/sdl/win32/win32.cpp deleted file mode 100644 index 05005dee6f..0000000000 --- a/backends/platform/sdl/win32/win32.cpp +++ /dev/null @@ -1,93 +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$ - * - */ - -#ifdef WIN32 - -#include <windows.h> -#define WIN32_LEAN_AND_MEAN -#undef ARRAYSIZE // winnt.h defines ARRAYSIZE, but we want our own one... - -#include "backends/platform/sdl/win32/win32.h" -#include "backends/fs/windows/windows-fs-factory.h" - -#define DEFAULT_CONFIG_FILE "scummvm.ini" - -void OSystem_Win32::init() { - // Initialze File System Factory - _fsFactory = new WindowsFilesystemFactory(); - - // Invoke parent implementation of this method - OSystem_SDL::init(); -} - -Common::String OSystem_Win32::getDefaultConfigFileName() { - char configFile[MAXPATHLEN]; - - OSVERSIONINFO win32OsVersion; - ZeroMemory(&win32OsVersion, sizeof(OSVERSIONINFO)); - win32OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&win32OsVersion); - // Check for non-9X version of Windows. - if (win32OsVersion.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) { - // Use the Application Data directory of the user profile. - if (win32OsVersion.dwMajorVersion >= 5) { - if (!GetEnvironmentVariable("APPDATA", configFile, sizeof(configFile))) - error("Unable to access application data directory"); - } else { - if (!GetEnvironmentVariable("USERPROFILE", configFile, sizeof(configFile))) - error("Unable to access user profile directory"); - - strcat(configFile, "\\Application Data"); - CreateDirectory(configFile, NULL); - } - - strcat(configFile, "\\ScummVM"); - CreateDirectory(configFile, NULL); - strcat(configFile, "\\" DEFAULT_CONFIG_FILE); - - FILE *tmp = NULL; - if ((tmp = fopen(configFile, "r")) == NULL) { - // Check windows directory - char oldConfigFile[MAXPATHLEN]; - GetWindowsDirectory(oldConfigFile, MAXPATHLEN); - strcat(oldConfigFile, "\\" DEFAULT_CONFIG_FILE); - if ((tmp = fopen(oldConfigFile, "r"))) { - strcpy(configFile, oldConfigFile); - - fclose(tmp); - } - } else { - fclose(tmp); - } - } else { - // Check windows directory - GetWindowsDirectory(configFile, MAXPATHLEN); - strcat(configFile, "\\" DEFAULT_CONFIG_FILE); - } - - return configFile; -} - -#endif diff --git a/backends/platform/sdl/win32/win32.h b/backends/platform/sdl/win32/win32.h deleted file mode 100644 index f18ee6ead1..0000000000 --- a/backends/platform/sdl/win32/win32.h +++ /dev/null @@ -1,39 +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$ - * - */ - -#ifndef PLATFORM_SDL_WIN32_H -#define PLATFORM_SDL_WIN32_H - -#include "backends/platform/sdl/sdl.h" - -class OSystem_Win32 : public OSystem_SDL { -public: - virtual void init(); - -protected: - virtual Common::String getDefaultConfigFileName(); -}; - -#endif diff --git a/backends/platform/symbian/AdaptAllMMPs.pl b/backends/platform/symbian/AdaptAllMMPs.pl index 8e97f469f9..8786ecff32 100644 --- a/backends/platform/symbian/AdaptAllMMPs.pl +++ b/backends/platform/symbian/AdaptAllMMPs.pl @@ -34,6 +34,7 @@ chdir("../../../"); "mmp/scummvm_teenagent.mmp", "mmp/scummvm_mohawk.mmp", "mmp/scummvm_hugo.mmp", + "mmp/scummvm_toon.mmp", # Target Platform Project Files "S60/ScummVM_S60.mmp", "S60v3/ScummVM_S60v3.mmp", @@ -92,6 +93,9 @@ my @excludes_graphics = ( "iff.cpp" ); +my @excludes_gui = ( +); + # the USE_ARM_* defines not parsed correctly, exclude manually: my @excludes_scumm = ( ".*ARM.*", # the *ARM.s files are added in .mpp files based on WINS/ARM build! @@ -104,7 +108,7 @@ my @excludes_scumm = ( #arseModule(mmpStr, dirStr, ifdefArray, [exclusionsArray]) ParseModule("_base", "base", \@section_empty); # now in ./TRG/ScummVM_TRG.mmp, these never change anyways... ParseModule("_base", "common", \@section_empty); -ParseModule("_base", "gui", \@section_empty); +ParseModule("_base", "gui", \@section_empty, \@excludes_gui); ParseModule("_base", "graphics", \@section_empty, \@excludes_graphics); ParseModule("_base", "sound", \@section_empty, \@excludes_snd); @@ -135,6 +139,7 @@ ParseModule("_draci", "draci", \@section_empty); ParseModule("_teenagent","teenagent", \@section_empty); ParseModule("_mohawk" ,"mohawk", \@section_empty); ParseModule("_hugo" ,"hugo", \@section_empty); +ParseModule("_toon" ,"toon", \@section_empty); print " ======================================================================================= Done. Enjoy :P diff --git a/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl b/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl index a0ec338ca0..bf80c36a0e 100644 --- a/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl +++ b/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl @@ -4,7 +4,7 @@ @WorkingEngines = qw( scumm agos sky queen gob groovie saga drascula kyra lure agi touche parallaction cine - cruise made m4 tinsel tucker sword1 sword2 draci sci teenagent mohawk hugo + cruise made m4 tinsel tucker sword1 sword2 draci sci teenagent mohawk hugo toon ); @WorkingEngines_1st = qw( @@ -16,7 +16,7 @@ @WorkingEngines_2nd = qw( agos sky gob kyra lure agi tinsel - sword1 sword2 draci sci teenagent hugo + sword1 sword2 draci sci teenagent hugo toon ); @TestingEngines = qw( @@ -302,8 +302,8 @@ # the first one includes all SDKs & release-ready engines $VariationSets{'ALL'}{'all'} = "$DefaultFeatures @WorkingEngines @EnablableSubEngines"; - $VariationSets{'ALL'}{'1St'} = "$DefaultFeatures @WorkingEngines_1st @EnablableSubEngines"; - $VariationSets{'ALL'}{'2nd'} = "$DefaultFeatures @WorkingEngines_2nd @EnablableSubEngines"; +# $VariationSets{'ALL'}{'1St'} = "$DefaultFeatures @WorkingEngines_1st @EnablableSubEngines"; +# $VariationSets{'ALL'}{'2nd'} = "$DefaultFeatures @WorkingEngines_2nd @EnablableSubEngines"; # now one for each ready-for-release engine if (0) { diff --git a/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in b/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in index 12193a8781..d044b33bb0 100644 --- a/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in +++ b/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in @@ -115,13 +115,14 @@ SOURCEPATH ..\..\..\..\base SOURCEPATH ..\..\..\.. // backend EPOC/SDL/ESDL specific includes +SOURCE backends\platform\sdl\events.cpp +SOURCE backends\platform\sdl\graphics.cpp SOURCE backends\platform\sdl\hardwarekeys.cpp SOURCE backends\platform\sdl\sdl.cpp SOURCE backends\fs\symbian\symbian-fs-factory.cpp SOURCE backends\platform\symbian\src\SymbianOS.cpp SOURCE backends\platform\symbian\src\SymbianActions.cpp SOURCE backends\platform\symbian\src\ScummApp.cpp -SOURCE backends\platform\symbian\src\SymbianMain.cpp SOURCE gui\Key.cpp SOURCE gui\KeysDialog.cpp diff --git a/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in b/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in index 31c98b90f1..bcc00017ab 100644 --- a/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in +++ b/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in @@ -115,13 +115,14 @@ SOURCEPATH ..\..\..\..\base SOURCEPATH ..\..\..\.. // backend EPOC/SDL/ESDL specific includes +SOURCE backends\platform\sdl\events.cpp +SOURCE backends\platform\sdl\graphics.cpp SOURCE backends\platform\sdl\hardwarekeys.cpp SOURCE backends\platform\sdl\sdl.cpp SOURCE backends\fs\symbian\symbian-fs-factory.cpp SOURCE backends\platform\symbian\src\SymbianOS.cpp SOURCE backends\platform\symbian\src\SymbianActions.cpp SOURCE backends\platform\symbian\src\ScummApp.cpp -SOURCE backends\platform\symbian\src\SymbianMain.cpp SOURCE gui\Key.cpp SOURCE gui\KeysDialog.cpp diff --git a/backends/platform/symbian/UIQ3/ScummVM_A0000658_UIQ3.mmp.in b/backends/platform/symbian/UIQ3/ScummVM_A0000658_UIQ3.mmp.in index 2e50c12cc3..83ce9bc599 100644 --- a/backends/platform/symbian/UIQ3/ScummVM_A0000658_UIQ3.mmp.in +++ b/backends/platform/symbian/UIQ3/ScummVM_A0000658_UIQ3.mmp.in @@ -36,6 +36,7 @@ TARGET ScummVM_A0000658.exe TARGETPATH sys\bin TARGETTYPE exe + OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char UID 0x100039ce 0xA0000658 @@ -112,14 +113,14 @@ SOURCEPATH ..\..\..\..\base SOURCEPATH ..\..\..\.. // backend EPOC/SDL/ESDL specific includes -SOURCE backends\platform\sdl\hardwarekeys.cpp +SOURCE backends\platform\sdl\events.cpp +SOURCE backends\platform\sdl\graphics.cpp SOURCE backends\platform\sdl\hardwarekeys.cpp SOURCE backends\platform\sdl\sdl.cpp SOURCE backends\fs\symbian\symbian-fs-factory.cpp SOURCE backends\platform\symbian\src\SymbianOS.cpp SOURCE backends\platform\symbian\src\SymbianActions.cpp SOURCE backends\platform\symbian\src\ScummApp.cpp -SOURCE backends\platform\symbian\src\SymbianMain.cpp SOURCE gui\Key.cpp SOURCE gui\KeysDialog.cpp diff --git a/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in b/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in index b00c848667..3c8e41784a 100644 --- a/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in +++ b/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in @@ -113,14 +113,14 @@ SOURCEPATH ..\..\..\..\base SOURCEPATH ..\..\..\.. // backend EPOC/SDL/ESDL specific includes -SOURCE backends\platform\sdl\hardwarekeys.cpp +SOURCE backends\platform\sdl\events.cpp +SOURCE backends\platform\sdl\graphics.cpp SOURCE backends\platform\sdl\hardwarekeys.cpp SOURCE backends\platform\sdl\sdl.cpp SOURCE backends\fs\symbian\symbian-fs-factory.cpp SOURCE backends\platform\symbian\src\SymbianOS.cpp SOURCE backends\platform\symbian\src\SymbianActions.cpp SOURCE backends\platform\symbian\src\ScummApp.cpp -SOURCE backends\platform\symbian\src\SymbianMain.cpp SOURCE gui\Key.cpp SOURCE gui\KeysDialog.cpp diff --git a/backends/platform/symbian/mmp/scummvm_base.mmp.in b/backends/platform/symbian/mmp/scummvm_base.mmp.in index e799975385..8f51e3c7b5 100644 --- a/backends/platform/symbian/mmp/scummvm_base.mmp.in +++ b/backends/platform/symbian/mmp/scummvm_base.mmp.in @@ -125,24 +125,12 @@ SOURCE engines\game.cpp SOURCE engines\advanceddetector.cpp SOURCE engines\savestate.cpp // backend specific includes -SOURCE backends\modular-backend.cpp -SOURCE backends\audiocd\default\default-audiocd.cpp -SOURCE backends\audiocd\sdl\sdl-audiocd.cpp -SOURCE backends\events\sdl\sdl-events.cpp -SOURCE backends\events\symbiansdl\symbiansdl-events.cpp SOURCE backends\fs\abstract-fs.cpp SOURCE backends\fs\symbian\symbianstream.cpp -SOURCE backends\graphics\sdl\sdl-graphics.cpp -SOURCE backends\graphics\symbiansdl\symbiansdl-graphics.cpp SOURCE backends\keymapper\action.cpp SOURCE backends\keymapper\keymap.cpp SOURCE backends\keymapper\keymapper.cpp SOURCE backends\keymapper\remap-dialog.cpp -SOURCE backends\mixer\sdl\sdl-mixer.cpp -SOURCE backends\mixer\symbiansdl\symbiansdl-mixer.cpp -SOURCE backends\mutex\sdl\sdl-mutex.cpp -SOURCE backends\timer\sdl\sdl-timer.cpp - // Source files for virtual keyboard SOURCE backends\vkeybd\image-map.cpp SOURCE backends\vkeybd\polygon.cpp diff --git a/backends/platform/symbian/mmp/scummvm_toon.mmp.in b/backends/platform/symbian/mmp/scummvm_toon.mmp.in new file mode 100644 index 0000000000..7b907fd92f --- /dev/null +++ b/backends/platform/symbian/mmp/scummvm_toon.mmp.in @@ -0,0 +1,64 @@ +/* ScummVM - Graphic Adventure Engine + * Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL + * Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System + * Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer + * Copyright (C) 2005-2010 The ScummVM project + * + * 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$ + * + */ + +// +// EPOC MMP makefile project for ScummVM +// + +// *** Definitions + +TARGET scummvm_toon.lib +TARGETTYPE lib +OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp +OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings +OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char +ALWAYS_BUILD_AS_ARM + +//START_AUTO_MACROS_SLAVE// + + // empty base file, will be updated by Perl build scripts + +//STOP_AUTO_MACROS_SLAVE// + +// *** SOURCE files + +SOURCEPATH ..\..\..\..\engines\toon + +//START_AUTO_OBJECTS_TOON_// + + // empty base file, will be updated by Perl build scripts + +//STOP_AUTO_OBJECTS_TOON_// + +// *** Include paths + +USERINCLUDE ..\..\..\..\engines +USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\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/src/SymbianOS.cpp b/backends/platform/symbian/src/SymbianOS.cpp index d86adbf354..50ab7e00b1 100644 --- a/backends/platform/symbian/src/SymbianOS.cpp +++ b/backends/platform/symbian/src/SymbianOS.cpp @@ -26,17 +26,26 @@ #include <sdlapp.h> // for CSDLApp::GetExecutablePathCStr() @ Symbian::GetExecutablePath() #include <bautils.h> +#include "backends/fs/symbian/symbian-fs-factory.h" #include "backends/platform/symbian/src/SymbianOS.h" #include "backends/platform/symbian/src/SymbianActions.h" +#include "backends/saves/default/default-saves.h" + +#include "base/main.h" + #include "common/config-manager.h" #include "common/scummsys.h" +#include "common/translation.h" + #include "gui/message.h" -#include "backends/fs/symbian/symbian-fs-factory.h" -#include "backends/saves/default/default-saves.h" -#include "backends/events/symbiansdl/symbiansdl-events.h" -#include "backends/graphics/symbiansdl/symbiansdl-graphics.h" -#include "backends/mixer/symbiansdl/symbiansdl-mixer.h" +#include "sound/mixer_intern.h" + +#ifdef SAMPLES_PER_SEC_8000 // the GreanSymbianMMP format cannot handle values for defines :( + #define SAMPLES_PER_SEC 8000 +#else + #define SAMPLES_PER_SEC 16000 +#endif #define DEFAULT_CONFIG_FILE "scummvm.ini" #define DEFAULT_SAVE_PATH "Savegames" @@ -49,7 +58,8 @@ void FatalError(const char *msg) { TPtrC8 msgPtr((const TUint8 *)msg); TBuf<512> msg16Bit; msg16Bit.Copy(msgPtr); -#ifndef S60 +#ifdef S60 +#else CEikonEnv::Static()->InfoWinL(_L("ScummVM Fatal Error"), msg16Bit); #endif if (g_system) @@ -57,7 +67,7 @@ void FatalError(const char *msg) { } // make this easily available everywhere -char *GetExecutablePath() { +char* GetExecutablePath() { return CSDLApp::GetExecutablePathCStr(); } @@ -65,13 +75,66 @@ char *GetExecutablePath() { ////////// OSystem_SDL_Symbian ////////////////////////////////////////// -OSystem_SDL_Symbian::OSystem_SDL_Symbian() - : - _RFs(0) { - +static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { + {"1x", "Fullscreen", GFX_NORMAL}, + {0, 0, 0} +}; + +bool OSystem_SDL_Symbian::hasFeature(Feature f) { + switch (f) { + case kFeatureFullscreenMode: + case kFeatureAspectRatioCorrection: + case kFeatureCursorHasPalette: +#ifdef USE_VIBRA_SE_PXXX + case kFeatureVibration: +#endif + return true; + + default: + return false; + } +} + +void OSystem_SDL_Symbian::setFeatureState(Feature f, bool enable) { + switch (f) { + case kFeatureVirtualKeyboard: + if (enable) { + } + else { + + } + break; + case kFeatureDisableKeyFiltering: + GUI::Actions::Instance()->beginMapping(enable); + break; + default: + OSystem_SDL::setFeatureState(f, enable); + } } -void OSystem_SDL_Symbian::init() { +static Common::String getDefaultConfigFileName() { + char configFile[MAXPATHLEN]; + strcpy(configFile, Symbian::GetExecutablePath()); + strcat(configFile, DEFAULT_CONFIG_FILE); + return configFile; +} + +Common::SeekableReadStream *OSystem_SDL_Symbian::createConfigReadStream() { + Common::FSNode file(getDefaultConfigFileName()); + return file.createReadStream(); +} + +Common::WriteStream *OSystem_SDL_Symbian::createConfigWriteStream() { + Common::FSNode file(getDefaultConfigFileName()); + return file.createWriteStream(); +} + +OSystem_SDL_Symbian::zoneDesc OSystem_SDL_Symbian::_zones[TOTAL_ZONES] = { + { 0, 0, 320, 145 }, + { 0, 145, 150, 55 }, + { 150, 145, 170, 55 } +}; +OSystem_SDL_Symbian::OSystem_SDL_Symbian() :_channels(0),_stereo_mix_buffer(0) { _RFs = &CEikonEnv::Static()->FsSession(); _fsFactory = new SymbianFilesystemFactory(); } @@ -81,19 +144,20 @@ void OSystem_SDL_Symbian::initBackend() { Common::String savePath; savePath = Symbian::GetExecutablePath(); savePath += DEFAULT_SAVE_PATH "\\"; - _savefileManager = new DefaultSaveFileManager(savePath); + _savefile = new DefaultSaveFileManager(savePath); // If savepath has not already been set then set it if (!ConfMan.hasKey("savepath")) { ConfMan.set("savepath", savePath); + } // Ensure that the current set path (might have been altered by the user) exists Common::String currentPath = ConfMan.get("savepath"); TFileName fname; - TPtrC8 ptr((const unsigned char*)currentPath.c_str(), currentPath.size()); + TPtrC8 ptr((const unsigned char*)currentPath.c_str(),currentPath.size()); fname.Copy(ptr); - BaflUtils::EnsurePathExistsL(static_cast<OSystem_SDL_Symbian *>(g_system)->FsSession(), fname); + BaflUtils::EnsurePathExistsL(static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(), fname); ConfMan.setBool("FM_high_quality", false); #if !defined(S60) || defined(S60V3) // S60 has low quality as default @@ -101,26 +165,11 @@ void OSystem_SDL_Symbian::initBackend() { #else ConfMan.setBool("FM_medium_quality", false); #endif - // Symbian OS should have joystick_num set to 0 in the ini file, - // but uiq devices might refuse opening the joystick - ConfMan.setInt("joystick_num", 0); + ConfMan.setInt("joystick_num", 0); // Symbian OS should have joystick_num set to 0 in the ini file , but uiq devices might refuse opening the joystick ConfMan.flushToDisk(); GUI::Actions::init(); - // Creates the backend managers - if (_eventManager == 0) - _eventManager = new SymbianSdlEventManager(this); - if (_mixerManager == 0) { - _mixerManager = new SymbianSdlMixerManager(); - - // Setup and start mixer - _mixerManager->init(); - } - if (_graphicsManager == 0) - _graphicsManager = new SymbianSdlGraphicsManager(); - - // Call parent implementation of this method OSystem_SDL::initBackend(); // Initialize global key mapping for Smartphones @@ -128,6 +177,7 @@ void OSystem_SDL_Symbian::initBackend() { actions->initInstanceMain(this); actions->loadMapping(); + initZones(); } void OSystem_SDL_Symbian::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) { @@ -137,23 +187,286 @@ void OSystem_SDL_Symbian::addSysArchivesToSearchSet(Common::SearchSet &s, int pr } } +OSystem_SDL_Symbian::~OSystem_SDL_Symbian() { + delete[] _stereo_mix_buffer; +} + +int OSystem_SDL_Symbian::getDefaultGraphicsMode() const { + return GFX_NORMAL; +} + +const OSystem::GraphicsMode *OSystem_SDL_Symbian::getSupportedGraphicsModes() const { + return s_supportedGraphicsModes; +} + +// make sure we always go to normal, even if the string might be set wrong! +bool OSystem_SDL_Symbian::setGraphicsMode(const char * /*name*/) { + // let parent OSystem_SDL handle it + return OSystem_SDL::setGraphicsMode(getDefaultGraphicsMode()); +} + void OSystem_SDL_Symbian::quitWithErrorMsg(const char * /*aMsg*/) { + CEikonEnv::Static()->AlertWin(_L("quitWithErrorMsg()")) ; if (g_system) g_system->quit(); } +// Overloaded from SDL_Commmon void OSystem_SDL_Symbian::quit() { delete GUI_Actions::Instance(); - - // Call parent implementation of this method OSystem_SDL::quit(); } +void OSystem_SDL_Symbian::setupMixer() { + + SDL_AudioSpec desired; + SDL_AudioSpec obtained; + + // Determine the desired output sampling frequency. + uint32 samplesPerSec = 0; + if (ConfMan.hasKey("output_rate")) + samplesPerSec = ConfMan.getInt("output_rate"); + if (samplesPerSec <= 0) + samplesPerSec = SAMPLES_PER_SEC; + + // Determine the sample buffer size. We want it to store enough data for + // at least 1/16th of a second (though at most 8192 samples). Note + // that it must be a power of two. So e.g. at 22050 Hz, we request a + // sample buffer size of 2048. + uint32 samples = 8192; + while (samples * 16 > samplesPerSec * 2) + samples >>= 1; + + memset(&desired, 0, sizeof(desired)); + desired.freq = samplesPerSec; + desired.format = AUDIO_S16SYS; + desired.channels = 2; + desired.samples = (uint16)samples; + desired.callback = symbianMixCallback; + desired.userdata = this; + + assert(!_mixer); + if (SDL_OpenAudio(&desired, &obtained) != 0) { + warning("Could not open audio device: %s", SDL_GetError()); + _mixer = new Audio::MixerImpl(this, samplesPerSec); + assert(_mixer); + _mixer->setReady(false); + } else { + // Note: This should be the obtained output rate, but it seems that at + // least on some platforms SDL will lie and claim it did get the rate + // even if it didn't. Probably only happens for "weird" rates, though. + samplesPerSec = obtained.freq; + _channels = obtained.channels; + + // Need to create mixbuffer for stereo mix to downmix + if (_channels != 2) { + _stereo_mix_buffer = new byte [obtained.size*2];//*2 for stereo values + } + + // Create the mixer instance and start the sound processing + _mixer = new Audio::MixerImpl(this, samplesPerSec); + assert(_mixer); + _mixer->setReady(true); + SDL_PauseAudio(0); + } +} + +/** + * The mixer callback function. + */ +void OSystem_SDL_Symbian::symbianMixCallback(void *sys, byte *samples, int len) { + OSystem_SDL_Symbian *this_ = (OSystem_SDL_Symbian *)sys; + assert(this_); + + if (!this_->_mixer) + return; + +#if defined (S60) && !defined(S60V3) + // If not stereo then we need to downmix + if (this_->_mixer->_channels != 2) { + this_->_mixer->mixCallback(_stereo_mix_buffer, len * 2); + + int16 *bitmixDst = (int16 *)samples; + int16 *bitmixSrc = (int16 *)_stereo_mix_buffer; + + for (int loop = len / 2; loop >= 0; loop --) { + *bitmixDst = (*bitmixSrc + *(bitmixSrc + 1)) >> 1; + bitmixDst++; + bitmixSrc += 2; + } + } else +#else + this_->_mixer->mixCallback(samples, len); +#endif +} + + +/** + * This is an implementation by the remapKey function + * @param SDL_Event to remap + * @param ScumVM event to modify if special result is requested + * @return true if Common::Event has a valid return status + */ +bool OSystem_SDL_Symbian::remapKey(SDL_Event &ev, Common::Event &event) { + if (GUI::Actions::Instance()->mappingActive() || ev.key.keysym.sym <= SDLK_UNKNOWN) + return false; + + for (TInt loop = 0; loop < GUI::ACTION_LAST; loop++) { + if (GUI::Actions::Instance()->getMapping(loop) == ev.key.keysym.sym && + GUI::Actions::Instance()->isEnabled(loop)) { + // Create proper event instead + switch (loop) { + case GUI::ACTION_UP: + if (ev.type == SDL_KEYDOWN) { + _km.y_vel = -1; + _km.y_down_count = 1; + } else { + _km.y_vel = 0; + _km.y_down_count = 0; + } + event.type = Common::EVENT_MOUSEMOVE; + fillMouseEvent(event, _km.x, _km.y); + + return true; + + case GUI::ACTION_DOWN: + if (ev.type == SDL_KEYDOWN) { + _km.y_vel = 1; + _km.y_down_count = 1; + } else { + _km.y_vel = 0; + _km.y_down_count = 0; + } + event.type = Common::EVENT_MOUSEMOVE; + fillMouseEvent(event, _km.x, _km.y); + + return true; + + case GUI::ACTION_LEFT: + if (ev.type == SDL_KEYDOWN) { + _km.x_vel = -1; + _km.x_down_count = 1; + } else { + _km.x_vel = 0; + _km.x_down_count = 0; + } + event.type = Common::EVENT_MOUSEMOVE; + fillMouseEvent(event, _km.x, _km.y); + + return true; + + case GUI::ACTION_RIGHT: + if (ev.type == SDL_KEYDOWN) { + _km.x_vel = 1; + _km.x_down_count = 1; + } else { + _km.x_vel = 0; + _km.x_down_count = 0; + } + event.type = Common::EVENT_MOUSEMOVE; + fillMouseEvent(event, _km.x, _km.y); + + return true; + + case GUI::ACTION_LEFTCLICK: + event.type = (ev.type == SDL_KEYDOWN ? Common::EVENT_LBUTTONDOWN : Common::EVENT_LBUTTONUP); + fillMouseEvent(event, _km.x, _km.y); + + return true; + + case GUI::ACTION_RIGHTCLICK: + event.type = (ev.type == SDL_KEYDOWN ? Common::EVENT_RBUTTONDOWN : Common::EVENT_RBUTTONUP); + fillMouseEvent(event, _km.x, _km.y); + + return true; + + case GUI::ACTION_ZONE: + if (ev.type == SDL_KEYDOWN) { + int i; + + for (i=0; i < TOTAL_ZONES; i++) + if (_km.x >= _zones[i].x && _km.y >= _zones[i].y && + _km.x <= _zones[i].x + _zones[i].width && _km.y <= _zones[i].y + _zones[i].height + ) { + _mouseXZone[i] = _km.x; + _mouseYZone[i] = _km.y; + break; + } + _currentZone++; + if (_currentZone >= TOTAL_ZONES) + _currentZone = 0; + event.type = Common::EVENT_MOUSEMOVE; + fillMouseEvent(event, _mouseXZone[_currentZone], _mouseYZone[_currentZone]); + SDL_WarpMouse(event.mouse.x, event.mouse.y); + } + + return true; + case GUI::ACTION_MULTI: { + GUI::Key &key = GUI::Actions::Instance()->getKeyAction(loop); + // if key code is pause, then change event to interactive or just fall through + if (key.keycode() == SDLK_PAUSE) { + event.type = Common::EVENT_PREDICTIVE_DIALOG; + return true; + } + } + case GUI::ACTION_SAVE: + case GUI::ACTION_SKIP: + case GUI::ACTION_SKIP_TEXT: + case GUI::ACTION_PAUSE: + case GUI::ACTION_SWAPCHAR: + case GUI::ACTION_FASTMODE: + case GUI::ACTION_DEBUGGER: + case GUI::ACTION_MAINMENU: + case GUI::ACTION_VKB: + case GUI::ACTION_KEYMAPPER:{ + GUI::Key &key = GUI::Actions::Instance()->getKeyAction(loop); + ev.key.keysym.sym = (SDLKey) key.keycode(); + ev.key.keysym.scancode = 0; + ev.key.keysym.mod = (SDLMod) key.flags(); + + // Translate from SDL keymod event to Scummvm Key Mod Common::Event. + // This codes is also present in GP32 backend and in SDL backend as a static function + // Perhaps it should be shared. + if (key.flags() != 0) { + event.kbd.flags = 0; + + if (ev.key.keysym.mod & KMOD_SHIFT) + event.kbd.flags |= Common::KBD_SHIFT; + + if (ev.key.keysym.mod & KMOD_ALT) + event.kbd.flags |= Common::KBD_ALT; + + if (ev.key.keysym.mod & KMOD_CTRL) + event.kbd.flags |= Common::KBD_CTRL; + } + + return false; + } + + case GUI::ACTION_QUIT: + { + GUI::MessageDialog alert(_("Do you want to quit ?"), _("Yes"), _("No")); + if (alert.runModal() == GUI::kMessageOK) + quit(); + + return true; + } + } + } + } + + return false; +} + +void OSystem_SDL_Symbian::setWindowCaption(const char *caption) { + OSystem_SDL::setWindowCaption(caption); +} + void OSystem_SDL_Symbian::engineInit() { // Check mappings for the engine just started - checkMappings(); + check_mappings(); } void OSystem_SDL_Symbian::engineDone() { @@ -161,26 +474,22 @@ void OSystem_SDL_Symbian::engineDone() { GUI::Actions::Instance()->initInstanceMain(this); } -void OSystem_SDL_Symbian::checkMappings() { +void OSystem_SDL_Symbian::check_mappings() { if (ConfMan.get("gameid").empty() || GUI::Actions::Instance()->initialized()) return; GUI::Actions::Instance()->initInstanceGame(); } -bool OSystem_SDL_Symbian::setGraphicsMode(const char * /*name*/) { - return _graphicsManager->setGraphicsMode(0); -} +void OSystem_SDL_Symbian::initZones() { + int i; -Common::String OSystem_SDL_Symbian::getDefaultConfigFileName() { - char configFile[MAXPATHLEN]; - strcpy(configFile, Symbian::GetExecutablePath()); - strcat(configFile, DEFAULT_CONFIG_FILE); - return configFile; -} + _currentZone = 0; -void OSystem_SDL_Symbian::setupIcon() { - // Don't for Symbian: it uses the EScummVM.aif file for the icon. + for (i = 0; i < TOTAL_ZONES; i++) { + _mouseXZone[i] = (_zones[i].x + (_zones[i].width / 2)); + _mouseYZone[i] = (_zones[i].y + (_zones[i].height / 2)); + } } RFs& OSystem_SDL_Symbian::FsSession() { @@ -206,3 +515,67 @@ void* scumm_bsearch(const void *key, const void *base, size_t nmemb, size_t size return NULL; } + +extern "C" +{ +// Include the snprintf and vsnprintf implementations as 'C' code +#include "vsnprintf.h" +} + +// Symbian SDL_Main implementation +// Redirects standard io, creates Symbian specific SDL backend (inherited from main SDL) +int main(int argc, char *argv[]) { + // + // Set up redirects for stdout/stderr under Symbian. + // Code copied from SDL_main. + // + + // Symbian does not like any output to the console through any *print* function + char STDOUT_FILE[256], STDERR_FILE[256]; // shhh, don't tell anybody :) + strcpy(STDOUT_FILE, Symbian::GetExecutablePath()); + strcpy(STDERR_FILE, Symbian::GetExecutablePath()); + strcat(STDOUT_FILE, "scummvm.stdout.txt"); + strcat(STDERR_FILE, "scummvm.stderr.txt"); + + /* Flush the output in case anything is queued */ + fclose(stdout); + fclose(stderr); + + /* Redirect standard input and standard output */ + FILE *newfp = freopen(STDOUT_FILE, "w", stdout); + if (newfp == NULL) { /* This happens on NT */ +#if !defined(stdout) + stdout = fopen(STDOUT_FILE, "w"); +#else + newfp = fopen(STDOUT_FILE, "w"); + if (newfp) { + *stdout = *newfp; + } +#endif + } + newfp = freopen(STDERR_FILE, "w", stderr); + if (newfp == NULL) { /* This happens on NT */ +#if !defined(stderr) + stderr = fopen(STDERR_FILE, "w"); +#else + newfp = fopen(STDERR_FILE, "w"); + if (newfp) { + *stderr = *newfp; + } +#endif + } + setbuf(stderr, NULL); /* No buffering */ + + // Create our OSystem instance + g_system = new OSystem_SDL_Symbian(); + assert(g_system); + +#ifdef DYNAMIC_MODULES + PluginManager::instance().addPluginProvider(new SDLPluginProvider()); +#endif + + // Invoke the actual ScummVM main entry point: + int res = scummvm_main(argc, argv); + g_system->quit(); // TODO: Consider removing / replacing this! + return res; +} diff --git a/backends/platform/symbian/src/SymbianOS.h b/backends/platform/symbian/src/SymbianOS.h index 0142054492..85b5e131da 100644 --- a/backends/platform/symbian/src/SymbianOS.h +++ b/backends/platform/symbian/src/SymbianOS.h @@ -22,52 +22,73 @@ * $Id$ */ -#ifndef PLATFORM_SDL_SYMBIAN_H -#define PLATFORM_SDL_SYMBIAN_H +#ifndef SDLSYMBIAN_H +#define SDLSYMBIAN_H #include "backends/platform/sdl/sdl.h" +#define TOTAL_ZONES 3 class RFs; class OSystem_SDL_Symbian : public OSystem_SDL { public: OSystem_SDL_Symbian(); + virtual ~OSystem_SDL_Symbian(); - // Override from OSystem_SDL - virtual void init(); - virtual void initBackend(); - virtual void quit(); - virtual void engineInit(); - virtual void engineDone(); - virtual bool setGraphicsMode(const char *name); - virtual Common::String getDefaultConfigFileName(); - virtual void setupIcon(); - +public: /** - * Returns reference to File session + * The following method is called once, from main.cpp, after all + * config data (including command line params etc.) are fully loaded. */ - RFs& FsSession(); + virtual void initBackend(); + int getDefaultGraphicsMode() const; + const OSystem::GraphicsMode *getSupportedGraphicsModes() const; + bool setGraphicsMode(const char *name); void quitWithErrorMsg(const char *msg); + virtual bool hasFeature(Feature f); + void setFeatureState(Feature f, bool enable); + + // Set function that generates samples + // + // This function is overridden by the symbian port in order to provide MONO audio + // downmix is done by supplying our own audiocallback + // + virtual void setupMixer(); // overloaded by CE backend + + // Overloaded from SDL_Commmon + void quit(); + + // Returns reference to File session + RFs& FsSession(); void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0); +protected: + // + // The mixer callback function. + // + static void symbianMixCallback(void *s, byte *samples, int len); + - // Vibration support + virtual Common::SeekableReadStream *createConfigReadStream(); + virtual Common::WriteStream *createConfigWriteStream(); +public: + // vibration support #ifdef USE_VIBRA_SE_PXXX - /** - * Intialize the vibration api used if present and supported - */ + // + // Intialize the vibration api used if present and supported + // void initializeVibration(); - /** - * Turn vibration on, repeat no time - * @param vibraLength number of repetitions - */ + // + // Turn vibration on, repeat no time + // @param vibraLength number of repetitions + // void vibrationOn(int vibraLength); - /** - * Turns the vibration off - */ + // + // Turns the vibration off + // void vibrationOff(); protected: @@ -75,11 +96,54 @@ protected: #endif // USE_VIBRA_SE_PXXX protected: + + // + // This is an implementation by the remapKey function + // @param SDL_Event to remap + // @param ScumVM event to modify if special result is requested + // @return true if Common::Event has a valid return status + // + bool remapKey(SDL_Event &ev, Common::Event &event); + + void setWindowCaption(const char *caption); + /** - * Used to intialized special game mappings + * Allows the backend to perform engine specific init. + * Called just before the engine is run. */ - void checkMappings(); + virtual void engineInit(); + + /** + * Allows the backend to perform engine specific de-init. + * Called after the engine finishes. + */ + virtual void engineDone(); + + // + // Used to intialized special game mappings + // + void check_mappings(); + + void initZones(); + + // Audio + int _channels; + + byte *_stereo_mix_buffer; + + // Used to handle joystick navi zones + 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]; RFs* _RFs; }; diff --git a/backends/platform/symbian/src/Symbianmain.cpp b/backends/platform/symbian/src/Symbianmain.cpp deleted file mode 100644 index 4aaa05926f..0000000000 --- a/backends/platform/symbian/src/Symbianmain.cpp +++ /dev/null @@ -1,99 +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$ - * - */ - -#include "base/main.h" -#include "backends/platform/symbian/src/SymbianOS.h" -#include "backends/platform/symbian/src/portdefs.h" - -extern "C" -{ -// Include the snprintf and vsnprintf implementations as 'C' code -#include "vsnprintf.h" -} - -// Symbian SDL_Main implementation -// Redirects standard io, creates Symbian specific SDL backend (inherited from main SDL) -int main(int argc, char *argv[]) { - // - // Set up redirects for stdout/stderr under Symbian. - // Code copied from SDL_main. - // - - // Symbian does not like any output to the console through any *print* function - char STDOUT_FILE[256], STDERR_FILE[256]; // shhh, don't tell anybody :) - strcpy(STDOUT_FILE, Symbian::GetExecutablePath()); - strcpy(STDERR_FILE, Symbian::GetExecutablePath()); - strcat(STDOUT_FILE, "scummvm.stdout.txt"); - strcat(STDERR_FILE, "scummvm.stderr.txt"); - - /* Flush the output in case anything is queued */ - fclose(stdout); - fclose(stderr); - - /* Redirect standard input and standard output */ - FILE *newfp = freopen(STDOUT_FILE, "w", stdout); - if (newfp == NULL) { /* This happens on NT */ -#if !defined(stdout) - stdout = fopen(STDOUT_FILE, "w"); -#else - newfp = fopen(STDOUT_FILE, "w"); - if (newfp) { - *stdout = *newfp; - } -#endif - } - newfp = freopen(STDERR_FILE, "w", stderr); - if (newfp == NULL) { /* This happens on NT */ -#if !defined(stderr) - stderr = fopen(STDERR_FILE, "w"); -#else - newfp = fopen(STDERR_FILE, "w"); - if (newfp) { - *stderr = *newfp; - } -#endif - } - setbuf(stderr, NULL); /* No buffering */ - - // Create our OSystem instance - g_system = new OSystem_SDL_Symbian(); - assert(g_system); - - // Pre initialize the backend - ((OSystem_SDL_Symbian *)g_system)->init(); - -#ifdef DYNAMIC_MODULES - PluginManager::instance().addPluginProvider(new SDLPluginProvider()); -#endif - - // Invoke the actual ScummVM main entry point: - int res = scummvm_main(argc, argv); - - // Free OSystem - delete (OSystem_SDL_Symbian *)g_system; - - return res; -} - diff --git a/backends/platform/symbian/src/portdefs.h b/backends/platform/symbian/src/portdefs.h index 2a26771a0a..6868faaa89 100644 --- a/backends/platform/symbian/src/portdefs.h +++ b/backends/platform/symbian/src/portdefs.h @@ -45,6 +45,13 @@ // and we _really_ don't wanna link with any other windows LIBC library! #if defined(__GCC32__) + FIXME: If the following macros are ever used, then this will lead + to serious errors, e.g. an almost guaranteed buffer overflow + in Common::String::format(). Do *NOT* re-#define vsnprintf to + vsprintf, it will lead to disaster! + This shouldn't be necessary anyway, since we have + backends/platform/symbian/src/vsnprintf.h + #define snprintf(buf,len,args...) sprintf(buf,args) #define vsnprintf(buf,len,format,valist) vsprintf(buf,format,valist) diff --git a/backends/platform/wii/main.cpp b/backends/platform/wii/main.cpp index 7f141f2339..aa688534fc 100644 --- a/backends/platform/wii/main.cpp +++ b/backends/platform/wii/main.cpp @@ -25,6 +25,7 @@ #include <unistd.h> #include "osystem.h" +#include "backends/plugins/wii/wii-provider.h" #include <ogc/machine/processor.h> #include <fat.h> @@ -210,6 +211,10 @@ int main(int argc, char *argv[]) { g_system = new OSystem_Wii(); assert(g_system); +#ifdef DYNAMIC_MODULES + PluginManager::instance().addPluginProvider(new WiiPluginProvider()); +#endif + res = scummvm_main(argc, argv); g_system->quit(); diff --git a/backends/platform/wii/options.cpp b/backends/platform/wii/options.cpp index 2a47958e3b..ffabc5ae97 100644 --- a/backends/platform/wii/options.cpp +++ b/backends/platform/wii/options.cpp @@ -183,7 +183,7 @@ void WiiOptionsDialog::handleTickle() { break; default: - label = String::printf(_("Network not initialised (%d)"), status); + label = String::format(_("Network not initialised (%d)"), status); break; } diff --git a/backends/platform/wii/wii.mk b/backends/platform/wii/wii.mk index c1512551d7..28066df8d4 100644 --- a/backends/platform/wii/wii.mk +++ b/backends/platform/wii/wii.mk @@ -32,6 +32,10 @@ else $(CP) $(srcdir)/dists/wii/icon.png wiidist/scummvm/ sed "s/@REVISION@/$(VER_SVNREV)/;s/@TIMESTAMP@/`date +%Y%m%d%H%M%S`/" < $(srcdir)/dists/wii/meta.xml > wiidist/scummvm/meta.xml endif +ifeq ($(DYNAMIC_MODULES),1) + $(MKDIR) wiidist/scummvm/plugins + for i in $(PLUGINS); do $(STRIP) --strip-debug $$i -o wiidist/scummvm/plugins/`basename $$i`; done +endif sed 's/$$/\r/' < $(srcdir)/dists/wii/READMII > wiidist/scummvm/READMII.txt for i in $(DIST_FILES_DOCS); do sed 's/$$/\r/' < $$i > wiidist/scummvm/`basename $$i`.txt; done $(CP) $(DIST_FILES_THEMES) wiidist/scummvm/ diff --git a/backends/platform/wince/CEActionsPocket.cpp b/backends/platform/wince/CEActionsPocket.cpp index 64abd0be3e..99d0be2bdc 100644 --- a/backends/platform/wince/CEActionsPocket.cpp +++ b/backends/platform/wince/CEActionsPocket.cpp @@ -23,21 +23,25 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "backends/platform/wince/wince-sdl.h" #include "CEActionsPocket.h" #include "EventsBuffer.h" #include "gui/message.h" -#include "scumm/scumm.h" #include "common/config-manager.h" #include "gui/KeysDialog.h" #include "common/translation.h" + #ifdef _WIN32_WCE #define KEY_ALL_SKIP 3457 #endif -const String pocketActionNames[] = { +const Common::String pocketActionNames[] = { _s("Pause"), _s("Save"), _s("Quit"), @@ -64,7 +68,7 @@ void CEActionsPocket::init() { } -String CEActionsPocket::actionName(GUI::ActionType action) { +Common::String CEActionsPocket::actionName(GUI::ActionType action) { return _(pocketActionNames[action]); } @@ -72,7 +76,7 @@ int CEActionsPocket::size() { return POCKET_ACTION_LAST; } -String CEActionsPocket::domain() { +Common::String CEActionsPocket::domain() { return ConfMan.kApplicationDomain; } @@ -81,8 +85,7 @@ int CEActionsPocket::version() { } CEActionsPocket::CEActionsPocket(const Common::String &gameid) : -GUI::Actions() -{ +GUI::Actions() { int i; _right_click_needed = false; @@ -114,7 +117,7 @@ void CEActionsPocket::initInstanceMain(OSystem *mainSystem) { } void CEActionsPocket::initInstanceGame() { - String gameid(ConfMan.get("gameid")); + Common::String gameid(ConfMan.get("gameid")); bool is_simon = (strncmp(gameid.c_str(), "simon", 5) == 0); bool is_sword1 = (gameid == "sword1"); bool is_sword2 = (strcmp(gameid.c_str(), "sword2") == 0); diff --git a/backends/platform/wince/CEActionsPocket.h b/backends/platform/wince/CEActionsPocket.h index 0fe29a9e86..72a2064fbf 100644 --- a/backends/platform/wince/CEActionsPocket.h +++ b/backends/platform/wince/CEActionsPocket.h @@ -28,7 +28,7 @@ #include "common/scummsys.h" #include "common/system.h" -#include "wince-sdl.h" +#include "common/str.h" #include "gui/Key.h" #include "gui/Actions.h" @@ -58,33 +58,35 @@ enum pocketActionType { POCKET_ACTION_LAST }; +class OSystem_WINCE3; + class CEActionsPocket : public GUI::Actions { - public: - // Actions - bool perform(GUI::ActionType action, bool pushed = true); - String actionName(GUI::ActionType action); - int size(); +public: + // Actions + bool perform(GUI::ActionType action, bool pushed = true); + Common::String actionName(GUI::ActionType action); + int size(); - static void init(); - void initInstanceMain(OSystem *mainSystem); - void initInstanceGame(); + static void init(); + void initInstanceMain(OSystem *mainSystem); + void initInstanceGame(); - // Action domain - String domain(); - int version(); + // Action domain + Common::String domain(); + int version(); - // Utility - bool needsRightClickMapping(); - bool needsHideToolbarMapping(); - bool needsZoomMapping(); + // Utility + bool needsRightClickMapping(); + bool needsHideToolbarMapping(); + bool needsZoomMapping(); - ~CEActionsPocket(); - private: - CEActionsPocket(const Common::String &gameid); - bool _right_click_needed; - bool _hide_toolbar_needed; - bool _zoom_needed; - OSystem_WINCE3 *_CESystem; - }; + ~CEActionsPocket(); +private: + CEActionsPocket(const Common::String &gameid); + bool _right_click_needed; + bool _hide_toolbar_needed; + bool _zoom_needed; + OSystem_WINCE3 *_CESystem; +}; #endif diff --git a/backends/platform/wince/CEActionsSmartphone.cpp b/backends/platform/wince/CEActionsSmartphone.cpp index af80bd2908..5c7feb4950 100644 --- a/backends/platform/wince/CEActionsSmartphone.cpp +++ b/backends/platform/wince/CEActionsSmartphone.cpp @@ -23,10 +23,14 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "backends/platform/wince/wince-sdl.h" + #include "CEActionsSmartphone.h" #include "EventsBuffer.h" #include "gui/message.h" -#include "scumm/scumm.h" #include "common/config-manager.h" #include "gui/KeysDialog.h" diff --git a/backends/platform/wince/CEActionsSmartphone.h b/backends/platform/wince/CEActionsSmartphone.h index 36797cd2c8..29156bb152 100644 --- a/backends/platform/wince/CEActionsSmartphone.h +++ b/backends/platform/wince/CEActionsSmartphone.h @@ -28,7 +28,7 @@ #include "common/scummsys.h" #include "common/system.h" -#include "wince-sdl.h" +#include "common/str.h" #include "gui/Key.h" #include "gui/Actions.h" @@ -55,24 +55,24 @@ enum smartphoneActionType { class CEActionsSmartphone : public GUI::Actions { - public: - // Actions - bool perform(GUI::ActionType action, bool pushed = true); - String actionName(GUI::ActionType action); - int size(); - static void init(); - void initInstanceMain(OSystem *mainSystem); - void initInstanceGame(); +public: + // Actions + bool perform(GUI::ActionType action, bool pushed = true); + Common::String actionName(GUI::ActionType action); + int size(); + static void init(); + void initInstanceMain(OSystem *mainSystem); + void initInstanceGame(); - // Action domain - String domain(); - int version(); + // Action domain + Common::String domain(); + int version(); - ~CEActionsSmartphone(); - private: - CEActionsSmartphone(); - bool _right_click_needed; - OSystem_WINCE3 *_CESystem; - }; + ~CEActionsSmartphone(); +private: + CEActionsSmartphone(); + bool _right_click_needed; + OSystem_WINCE3 *_CESystem; +}; #endif diff --git a/backends/platform/wince/CEDevice.cpp b/backends/platform/wince/CEDevice.cpp index 98a8fb95f6..08acbbbfcd 100644 --- a/backends/platform/wince/CEDevice.cpp +++ b/backends/platform/wince/CEDevice.cpp @@ -23,11 +23,14 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + #include "CEDevice.h" #include <SDL.h> -#include "wince-sdl.h" +#include "backends/platform/wince/wince-sdl.h" static void (WINAPI* _SHIdleTimerReset)(void) = NULL; static HANDLE (WINAPI* _SetPowerRequirement)(PVOID,int,ULONG,PVOID,ULONG) = NULL; diff --git a/backends/platform/wince/CEDevice.h b/backends/platform/wince/CEDevice.h index ca2f908c6d..b2b20d05ce 100644 --- a/backends/platform/wince/CEDevice.h +++ b/backends/platform/wince/CEDevice.h @@ -31,20 +31,20 @@ #include "common/str.h" class CEDevice { - public: - static void init(); - static void end(); - static void wakeUp(); - static bool hasPocketPCResolution(); - static bool hasSquareQVGAResolution(); - static bool hasDesktopResolution(); - static bool hasWideResolution(); - static bool hasSmartphoneResolution(); - static bool isSmartphone(); +public: + static void init(); + static void end(); + static void wakeUp(); + static bool hasPocketPCResolution(); + static bool hasSquareQVGAResolution(); + static bool hasDesktopResolution(); + static bool hasWideResolution(); + static bool hasSmartphoneResolution(); + static bool isSmartphone(); - private: - static DWORD reg_access(TCHAR *key, TCHAR *val, DWORD data); - static void backlight_xchg(); +private: + static DWORD reg_access(TCHAR *key, TCHAR *val, DWORD data); + static void backlight_xchg(); }; #endif diff --git a/backends/platform/wince/CELauncherDialog.cpp b/backends/platform/wince/CELauncherDialog.cpp index 11e4900c2d..66a691f51b 100644 --- a/backends/platform/wince/CELauncherDialog.cpp +++ b/backends/platform/wince/CELauncherDialog.cpp @@ -23,8 +23,10 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL -#include "wince-sdl.h" +#include "backends/platform/wince/wince-sdl.h" #include "CELauncherDialog.h" diff --git a/backends/platform/wince/CEScaler.cpp b/backends/platform/wince/CEScaler.cpp index fd47635e05..182a7e0c94 100644 --- a/backends/platform/wince/CEScaler.cpp +++ b/backends/platform/wince/CEScaler.cpp @@ -22,6 +22,7 @@ * $Id$ * */ + #include "graphics/scaler/intern.h" #include "CEScaler.h" diff --git a/backends/platform/wince/CEgui/GUIElement.cpp b/backends/platform/wince/CEgui/GUIElement.cpp index 23e7843de1..7689837e3d 100644 --- a/backends/platform/wince/CEgui/GUIElement.cpp +++ b/backends/platform/wince/CEgui/GUIElement.cpp @@ -23,104 +23,108 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include <SDL.h> + #include "Toolbar.h" #include "SDL_ImageResource.h" 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) - { - } +GUIElement::GUIElement(int x, int y, int width, int height) : +_background(0), _drawn(false), _visible(true), _x(x), _y(y), _width(width), _height(height) { +} - bool GUIElement::setBackground(WORD backgroundReference) { - _background = new SDL_ImageResource(); - if (!_background->load(backgroundReference)) { - delete _background; - _background = NULL; - return false; - } - if (!_height && !_width) { - _height = _background->height(); - _width = _background->width(); - } - else - if (_background->height() != _height || _background->width() != _width) { - delete _background; - _background = NULL; - return false; - } - return true; +bool GUIElement::setBackground(WORD backgroundReference) { + _background = new SDL_ImageResource(); + if (!_background->load(backgroundReference)) { + delete _background; + _background = NULL; + return false; } - - void GUIElement::move(int x, int y) { - _x = x; - _y = y; + if (!_height && !_width) { + _height = _background->height(); + _width = _background->width(); } + else + if (_background->height() != _height || _background->width() != _width) { + delete _background; + _background = NULL; + return false; + } + return true; +} - bool GUIElement::draw(SDL_Surface *surface) { - if (_background && !_drawn && _visible) { - SDL_Rect rect; - - rect.x = _x; - rect.y = _y; - rect.w = _width; - rect.h = _height; +void GUIElement::move(int x, int y) { + _x = x; + _y = y; +} - SDL_BlitSurface(_background->get(), NULL, surface, &rect); +bool GUIElement::draw(SDL_Surface *surface) { + if (_background && !_drawn && _visible) { + SDL_Rect rect; - _drawn = true; + rect.x = _x; + rect.y = _y; + rect.w = _width; + rect.h = _height; - return true; - } - else - return false; - } + SDL_BlitSurface(_background->get(), NULL, surface, &rect); - bool GUIElement::checkInside(int x, int y) { - if (x >= _x && x <= _x + _width && y >= _y && y <= _y + _height) - return true; - else - return false; - } + _drawn = true; - void GUIElement::setVisible(bool visibility) { - if (visibility && !_visible) - _drawn = false; - _visible = visibility; + return true; } + else + return false; +} - bool GUIElement::visible() { - return _visible; - } +bool GUIElement::checkInside(int x, int y) { + if (x >= _x && x <= _x + _width && y >= _y && y <= _y + _height) + return true; + else + return false; +} - void GUIElement::forceRedraw() { +void GUIElement::setVisible(bool visibility) { + if (visibility && !_visible) _drawn = false; - } + _visible = visibility; +} - bool GUIElement::drawn() { - return _drawn; - } +bool GUIElement::visible() { + return _visible; +} - int GUIElement::x() { - return _x; - } +void GUIElement::forceRedraw() { + _drawn = false; +} - int GUIElement::y() { - return _y; - } +bool GUIElement::drawn() { + return _drawn; +} - int GUIElement::width() { - return _width; - } +int GUIElement::x() { + return _x; +} - int GUIElement::height() { - return _height; - } +int GUIElement::y() { + return _y; +} - GUIElement::~GUIElement() { - delete _background; - } +int GUIElement::width() { + return _width; +} + +int GUIElement::height() { + return _height; +} +GUIElement::~GUIElement() { + delete _background; } + +} // End of namespace CEGUI diff --git a/backends/platform/wince/CEgui/GUIElement.h b/backends/platform/wince/CEgui/GUIElement.h index 7e4572d377..c599ebe9b5 100644 --- a/backends/platform/wince/CEgui/GUIElement.h +++ b/backends/platform/wince/CEgui/GUIElement.h @@ -29,39 +29,40 @@ #include "common/scummsys.h" #include "common/system.h" -#include "SDL.h" - -#include "SDL_ImageResource.h" +struct SDL_Surface; namespace CEGUI { - class GUIElement { - public: - bool setBackground(WORD backgroundReference); - void setVisible(bool visibility); - virtual void forceRedraw(); - virtual bool draw(SDL_Surface *surface); - virtual ~GUIElement(); - void move(int x, int y); - int width(); - int height(); - int x(); - int y(); - virtual bool action(int x, int y, bool pushed) = 0; - bool visible(); - bool drawn(); - protected: - GUIElement(int x = 0, int y = 0, int width = 0, int height = 0); - bool checkInside(int x, int y); - bool _visible; - SDL_ImageResource *_background; - int _x; - int _y; - bool _drawn; - private: - int _width; - int _height; - }; -} +class SDL_ImageResource; + +class GUIElement { +public: + bool setBackground(WORD backgroundReference); + void setVisible(bool visibility); + virtual void forceRedraw(); + virtual bool draw(SDL_Surface *surface); + virtual ~GUIElement(); + void move(int x, int y); + int width(); + int height(); + int x(); + int y(); + virtual bool action(int x, int y, bool pushed) = 0; + bool visible(); + bool drawn(); +protected: + GUIElement(int x = 0, int y = 0, int width = 0, int height = 0); + bool checkInside(int x, int y); + bool _visible; + SDL_ImageResource *_background; + int _x; + int _y; + bool _drawn; +private: + int _width; + int _height; +}; + +} // End of namespace CEGUI #endif diff --git a/backends/platform/wince/CEgui/ItemAction.cpp b/backends/platform/wince/CEgui/ItemAction.cpp index 3808622b2e..55805744e6 100644 --- a/backends/platform/wince/CEgui/ItemAction.cpp +++ b/backends/platform/wince/CEgui/ItemAction.cpp @@ -27,25 +27,25 @@ namespace CEGUI { - ItemAction::ItemAction(WORD reference, GUI::ActionType action) : - PanelItem(reference) { - _action = action; - if (!GUI::Actions::Instance()->isEnabled(_action)) - _visible = false; - } - - - ItemAction::~ItemAction() { - } - - bool ItemAction::action(int x, int y, bool pushed) { - - if (checkInside(x, y) && _visible && pushed) { - GUI::Actions::Instance()->perform(_action, true); - GUI::Actions::Instance()->perform(_action, false); - return true; - } - else - return false; - } +ItemAction::ItemAction(WORD reference, GUI::ActionType action) : +PanelItem(reference) { + _action = action; + if (!GUI::Actions::Instance()->isEnabled(_action)) + _visible = false; } + + +ItemAction::~ItemAction() { +} + +bool ItemAction::action(int x, int y, bool pushed) { + + if (checkInside(x, y) && _visible && pushed) { + GUI::Actions::Instance()->perform(_action, true); + GUI::Actions::Instance()->perform(_action, false); + return true; + } else + return false; +} + +} // End of namespace CEGUI diff --git a/backends/platform/wince/CEgui/ItemAction.h b/backends/platform/wince/CEgui/ItemAction.h index 74ed6bec4d..4f35b3090d 100644 --- a/backends/platform/wince/CEgui/ItemAction.h +++ b/backends/platform/wince/CEgui/ItemAction.h @@ -31,16 +31,18 @@ #include "gui/Actions.h" #include "CEgui/PanelItem.h" + namespace CEGUI { - class ItemAction : public PanelItem { - public: - ItemAction(WORD reference, GUI::ActionType action); - virtual ~ItemAction(); - virtual bool action(int x, int y, bool pushed); - private: - GUI::ActionType _action; - }; -} +class ItemAction : public PanelItem { +public: + ItemAction(WORD reference, GUI::ActionType action); + virtual ~ItemAction(); + virtual bool action(int x, int y, bool pushed); +private: + GUI::ActionType _action; +}; + +} // End of namespace CEGUI #endif diff --git a/backends/platform/wince/CEgui/ItemSwitch.cpp b/backends/platform/wince/CEgui/ItemSwitch.cpp index 8e0121f7c4..d4648f7556 100644 --- a/backends/platform/wince/CEgui/ItemSwitch.cpp +++ b/backends/platform/wince/CEgui/ItemSwitch.cpp @@ -24,71 +24,73 @@ */ #include "ItemSwitch.h" +#include "SDL_ImageResource.h" namespace CEGUI { - void ItemSwitch::init(WORD referenceTrue, WORD referenceFalse) { - _backgroundTrue = _background; - _backgroundFalse = new SDL_ImageResource(); - if (!_backgroundFalse->load(referenceFalse)) { - delete _backgroundFalse; - delete _background; - _background = NULL; - _backgroundFalse = NULL; - } +void ItemSwitch::init(WORD referenceTrue, WORD referenceFalse) { + _backgroundTrue = _background; + _backgroundFalse = new SDL_ImageResource(); + if (!_backgroundFalse->load(referenceFalse)) { + delete _backgroundFalse; + delete _background; + _background = NULL; + _backgroundFalse = NULL; } +} - ItemSwitch::ItemSwitch(WORD referenceTrue, WORD referenceFalse, bool *item) : - PanelItem(referenceTrue) { - init(referenceTrue, referenceFalse); - _item = item; - _itemmax = -1; - if (!*_item) - _background = _backgroundFalse; - } +ItemSwitch::ItemSwitch(WORD referenceTrue, WORD referenceFalse, bool *item) : +PanelItem(referenceTrue) { + init(referenceTrue, referenceFalse); + _item = item; + _itemmax = -1; + if (!*_item) + _background = _backgroundFalse; +} - ItemSwitch::ItemSwitch(WORD referenceTrue, WORD referenceFalse, int *item, int max) : - PanelItem(referenceTrue) { - init(referenceTrue, referenceFalse); - _itemmultiple = item; - _itemmax = max; - if (!*item) - _background = _backgroundFalse; - } +ItemSwitch::ItemSwitch(WORD referenceTrue, WORD referenceFalse, int *item, int max) : +PanelItem(referenceTrue) { + init(referenceTrue, referenceFalse); + _itemmultiple = item; + _itemmax = max; + if (!*item) + _background = _backgroundFalse; +} - ItemSwitch::~ItemSwitch() { - delete _backgroundFalse; - } +ItemSwitch::~ItemSwitch() { + delete _backgroundFalse; +} - bool ItemSwitch::action(int x, int y, bool pushed) { +bool ItemSwitch::action(int x, int y, bool pushed) { - if (checkInside(x, y) && _visible && pushed) { - if (_itemmax <= 0) { - *_item = !*_item; - if (*_item) - _background = _backgroundTrue; - else - _background = _backgroundFalse; + if (checkInside(x, y) && _visible && pushed) { + if (_itemmax <= 0) { + *_item = !*_item; + if (*_item) + _background = _backgroundTrue; + else + _background = _backgroundFalse; - if (_panel) - _panel->forceRedraw(); + if (_panel) + _panel->forceRedraw(); - return true; - } else { - *_itemmultiple = *_itemmultiple + 1; - if (*_itemmultiple > _itemmax) - *_itemmultiple = 0; - if (*_itemmultiple) - _background = _backgroundTrue; - else - _background = _backgroundFalse; + return true; + } else { + *_itemmultiple = *_itemmultiple + 1; + if (*_itemmultiple > _itemmax) + *_itemmultiple = 0; + if (*_itemmultiple) + _background = _backgroundTrue; + else + _background = _backgroundFalse; - if (_panel) - _panel->forceRedraw(); + if (_panel) + _panel->forceRedraw(); - return true; - } - } else - return false; - } + return true; + } + } else + return false; } + +} // End of namespace CEGUI diff --git a/backends/platform/wince/CEgui/ItemSwitch.h b/backends/platform/wince/CEgui/ItemSwitch.h index 8d03ee77cb..1ca6f3c288 100644 --- a/backends/platform/wince/CEgui/ItemSwitch.h +++ b/backends/platform/wince/CEgui/ItemSwitch.h @@ -36,20 +36,23 @@ using GUI::Key; namespace CEGUI { - class ItemSwitch : public PanelItem { - public: - ItemSwitch(WORD referenceTrue, WORD referenceFalse, bool *item); - ItemSwitch(WORD referenceTrue, WORD referenceFalse, int *item, int max); - virtual ~ItemSwitch(); - virtual bool action(int x, int y, bool pushed); - private: - void init(WORD referenceTrue, WORD referenceFalse); - bool *_item; - static bool _itemdummy; - int *_itemmultiple, _itemmax; - SDL_ImageResource *_backgroundTrue; - SDL_ImageResource *_backgroundFalse; - }; -} +class SDL_ImageResource; + +class ItemSwitch : public PanelItem { +public: + ItemSwitch(WORD referenceTrue, WORD referenceFalse, bool *item); + ItemSwitch(WORD referenceTrue, WORD referenceFalse, int *item, int max); + virtual ~ItemSwitch(); + virtual bool action(int x, int y, bool pushed); +private: + void init(WORD referenceTrue, WORD referenceFalse); + bool *_item; + static bool _itemdummy; + int *_itemmultiple, _itemmax; + SDL_ImageResource *_backgroundTrue; + SDL_ImageResource *_backgroundFalse; +}; + +} // End of namespace CEGUI #endif diff --git a/backends/platform/wince/CEgui/Panel.cpp b/backends/platform/wince/CEgui/Panel.cpp index a2d965ca78..dfdd6526be 100644 --- a/backends/platform/wince/CEgui/Panel.cpp +++ b/backends/platform/wince/CEgui/Panel.cpp @@ -27,59 +27,58 @@ namespace CEGUI { - Panel::Panel(int interleave_first, int interleave) : Toolbar() - { - _interleave = interleave; - _currentItem = interleave_first; - } +Panel::Panel(int interleave_first, int interleave) : Toolbar() { + _interleave = interleave; + _currentItem = interleave_first; +} - bool Panel::add(const String &name, const PanelItem *item) { - _itemsMap[name] = (PanelItem*)item; - _itemsMap[name]->move(_currentItem, _y + 10); - _itemsMap[name]->setPanel(this); - _currentItem += _interleave; +bool Panel::add(const String &name, const PanelItem *item) { + _itemsMap[name] = (PanelItem*)item; + _itemsMap[name]->move(_currentItem, _y + 10); + _itemsMap[name]->setPanel(this); + _currentItem += _interleave; - return true; - } + return true; +} - bool Panel::draw(SDL_Surface *surface) { - ItemMap::const_iterator iterator; - if (!_drawn && _visible) { - GUIElement::draw(surface); - for (iterator = _itemsMap.begin(); iterator != _itemsMap.end(); ++iterator) { - ((GUIElement*)(iterator->_value))->draw(surface); - } - return true; +bool Panel::draw(SDL_Surface *surface) { + ItemMap::const_iterator iterator; + if (!_drawn && _visible) { + GUIElement::draw(surface); + for (iterator = _itemsMap.begin(); iterator != _itemsMap.end(); ++iterator) { + ((GUIElement*)(iterator->_value))->draw(surface); } - else - return false; + return true; } + else + return false; +} - void Panel::forceRedraw() { - ItemMap::const_iterator iterator; - GUIElement::forceRedraw(); - for (iterator = _itemsMap.begin(); iterator != _itemsMap.end(); ++iterator) - ((GUIElement*)(iterator->_value))->forceRedraw(); - } +void Panel::forceRedraw() { + ItemMap::const_iterator iterator; + GUIElement::forceRedraw(); + for (iterator = _itemsMap.begin(); iterator != _itemsMap.end(); ++iterator) + ((GUIElement*)(iterator->_value))->forceRedraw(); +} - bool Panel::action(int x, int y, bool pushed) { - ItemMap::const_iterator iterator; - bool result = false; - if (!_visible || !checkInside(x, y)) - return false; +bool Panel::action(int x, int y, bool pushed) { + ItemMap::const_iterator iterator; + bool result = false; + if (!_visible || !checkInside(x, y)) + return false; - for (iterator = _itemsMap.begin(); !result && iterator != _itemsMap.end(); ++iterator) - result = ((GUIElement*)(iterator->_value))->action(x, y, pushed); - return result; - } + for (iterator = _itemsMap.begin(); !result && iterator != _itemsMap.end(); ++iterator) + result = ((GUIElement*)(iterator->_value))->action(x, y, pushed); + return result; +} - void Panel::clear() { - _itemsMap.clear(); - } +void Panel::clear() { + _itemsMap.clear(); +} - Panel::~Panel() { - _itemsMap.clear(); - } +Panel::~Panel() { + _itemsMap.clear(); } +} // End of namespace CEGUI diff --git a/backends/platform/wince/CEgui/Panel.h b/backends/platform/wince/CEgui/Panel.h index 6626e41866..e6b693360d 100644 --- a/backends/platform/wince/CEgui/Panel.h +++ b/backends/platform/wince/CEgui/Panel.h @@ -40,23 +40,24 @@ using Common::HashMap; namespace CEGUI { - class Panel : public Toolbar { - public: - Panel(int interleave_first, int interleave); - virtual bool draw(SDL_Surface *surface); - virtual ~Panel(); - bool add(const String &name, const PanelItem *item); - void clear(); - virtual void forceRedraw(); - virtual bool action(int x, int y, bool pushed); - private: - - typedef HashMap<String, PanelItem*, Common::IgnoreCase_Hash , Common::IgnoreCase_EqualTo> ItemMap; - - ItemMap _itemsMap; - int _interleave; - int _currentItem; - }; -} +class Panel : public Toolbar { +public: + Panel(int interleave_first, int interleave); + virtual bool draw(SDL_Surface *surface); + virtual ~Panel(); + bool add(const String &name, const PanelItem *item); + void clear(); + virtual void forceRedraw(); + virtual bool action(int x, int y, bool pushed); +private: + + typedef HashMap<String, PanelItem*, Common::IgnoreCase_Hash , Common::IgnoreCase_EqualTo> ItemMap; + + ItemMap _itemsMap; + int _interleave; + int _currentItem; +}; + +} // End of namespace CEGUI #endif diff --git a/backends/platform/wince/CEgui/PanelItem.cpp b/backends/platform/wince/CEgui/PanelItem.cpp index 0898839c5d..8c68c79784 100644 --- a/backends/platform/wince/CEgui/PanelItem.cpp +++ b/backends/platform/wince/CEgui/PanelItem.cpp @@ -27,21 +27,21 @@ namespace CEGUI { - PanelItem::PanelItem(WORD reference) : GUIElement() { - setBackground(reference); - _panel = NULL; - } +PanelItem::PanelItem(WORD reference) : GUIElement() { + setBackground(reference); + _panel = NULL; +} - PanelItem::~PanelItem() { - } +PanelItem::~PanelItem() { +} - bool PanelItem::action(int x, int y, bool pushed) { - return false; - } +bool PanelItem::action(int x, int y, bool pushed) { + return false; +} - void PanelItem::setPanel(Panel *panel) { - _panel = panel; - } +void PanelItem::setPanel(Panel *panel) { + _panel = panel; } +} // End of namespace CEGUI diff --git a/backends/platform/wince/CEgui/PanelItem.h b/backends/platform/wince/CEgui/PanelItem.h index 55920c304a..14b62f0f20 100644 --- a/backends/platform/wince/CEgui/PanelItem.h +++ b/backends/platform/wince/CEgui/PanelItem.h @@ -33,18 +33,19 @@ namespace CEGUI { - class Panel; - - class PanelItem : public GUIElement { - friend class Panel; - public: - PanelItem(WORD reference); - virtual ~PanelItem(); - virtual bool action(int x, int y, bool pushed); - protected: - void setPanel(Panel *panel); - Panel *_panel; - }; -} +class Panel; + +class PanelItem : public GUIElement { +friend class Panel; +public: + PanelItem(WORD reference); + virtual ~PanelItem(); + virtual bool action(int x, int y, bool pushed); +protected: + void setPanel(Panel *panel); + Panel *_panel; +}; + +} // End of namespace CEGUI #endif diff --git a/backends/platform/wince/CEgui/PanelKeyboard.cpp b/backends/platform/wince/CEgui/PanelKeyboard.cpp index 369a75cae1..1b2a478746 100644 --- a/backends/platform/wince/CEgui/PanelKeyboard.cpp +++ b/backends/platform/wince/CEgui/PanelKeyboard.cpp @@ -23,77 +23,81 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include <SDL.h> + #include "PanelKeyboard.h" 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 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} } }; - PanelKeyboard::PanelKeyboard(WORD reference) : Toolbar() { - setBackground(reference); - _state = false; - _lastKey.setKey(0); - } - - - PanelKeyboard::~PanelKeyboard() { - } - - bool PanelKeyboard::action(int x, int y, bool pushed) { - Key key; - - if (checkInside(x, y)) { - int keyAscii = 0; - int keyCode = 0; - if (x < 185) { - // Alpha selection - 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]; - } 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]; - } else if (x >= 302 && x <= 316) { - if (y < _y +20) { - // Backspace - keyAscii = VK_BACK; keyCode = keyAscii; - } else { - // Enter - keyAscii = 13; keyCode = 13; - } - } +PanelKeyboard::PanelKeyboard(WORD reference) : Toolbar() { + setBackground(reference); + _state = false; + _lastKey.setKey(0); +} + + +PanelKeyboard::~PanelKeyboard() { +} - if (keyAscii != 0) { - if (_state && pushed && keyCode != _lastKey.keycode()) // if cursor is still down and off the current key - return false; - else if (_state && !pushed && keyCode != _lastKey.keycode()) { // cursor is up but off the current key - keyAscii = _lastKey.ascii(); - keyCode = _lastKey.keycode(); - } - _state = pushed; - _lastKey.setKey(keyAscii, tolower(keyCode)); - - key.setKey(keyAscii, tolower(keyCode)); - return EventsBuffer::simulateKey(&key, pushed); +bool PanelKeyboard::action(int x, int y, bool pushed) { + Key key; + + if (checkInside(x, y)) { + int keyAscii = 0; + int keyCode = 0; + if (x < 185) { + // Alpha selection + 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]; + } 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]; + } else if (x >= 302 && x <= 316) { + if (y < _y +20) { + // Backspace + keyAscii = VK_BACK; keyCode = keyAscii; + } else { + // Enter + keyAscii = 13; keyCode = 13; } - else if (_state && !pushed) { // cursor is in some forbidden region and is up - _state = false; - key = _lastKey; - return EventsBuffer::simulateKey(&key, false); - } else - return false; } - else if (_state && !pushed) { // cursor left the keyboard area and is up + + if (keyAscii != 0) { + if (_state && pushed && keyCode != _lastKey.keycode()) // if cursor is still down and off the current key + return false; + else if (_state && !pushed && keyCode != _lastKey.keycode()) { // cursor is up but off the current key + keyAscii = _lastKey.ascii(); + keyCode = _lastKey.keycode(); + } + _state = pushed; + _lastKey.setKey(keyAscii, tolower(keyCode)); + + key.setKey(keyAscii, tolower(keyCode)); + return EventsBuffer::simulateKey(&key, pushed); + } else if (_state && !pushed) { // cursor is in some forbidden region and is up _state = false; key = _lastKey; return EventsBuffer::simulateKey(&key, false); } else return false; - } + } else if (_state && !pushed) { // cursor left the keyboard area and is up + _state = false; + key = _lastKey; + return EventsBuffer::simulateKey(&key, false); + } else + return false; } +} // End of namespace CEGUI + diff --git a/backends/platform/wince/CEgui/PanelKeyboard.h b/backends/platform/wince/CEgui/PanelKeyboard.h index f441e14771..b98e6ff3a8 100644 --- a/backends/platform/wince/CEgui/PanelKeyboard.h +++ b/backends/platform/wince/CEgui/PanelKeyboard.h @@ -37,15 +37,16 @@ using CEKEYS::EventsBuffer; namespace CEGUI { - class PanelKeyboard : public Toolbar { - public: - PanelKeyboard(WORD reference); - virtual ~PanelKeyboard(); - virtual bool action(int x, int y, bool pushed); - private: - bool _state; - Key _lastKey; - }; -} +class PanelKeyboard : public Toolbar { +public: + PanelKeyboard(WORD reference); + virtual ~PanelKeyboard(); + virtual bool action(int x, int y, bool pushed); +private: + bool _state; + Key _lastKey; +}; + +} // End of namespace CEGUI #endif diff --git a/backends/platform/wince/CEgui/SDL_ImageResource.cpp b/backends/platform/wince/CEgui/SDL_ImageResource.cpp index ce6ebd6382..567013b5ff 100644 --- a/backends/platform/wince/CEgui/SDL_ImageResource.cpp +++ b/backends/platform/wince/CEgui/SDL_ImageResource.cpp @@ -23,63 +23,67 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "SDL.h" #include "SDL_ImageResource.h" namespace CEGUI { - SDL_ImageResource::SDL_ImageResource() : - _surface(0) - { - } +SDL_ImageResource::SDL_ImageResource() : + _surface(0) { +} - SDL_Surface* SDL_ImageResource::load(WORD resourceID) { - HRSRC resource; - HGLOBAL resourceGlobal; - LPVOID resourcePointer; - DWORD resourceSize; - SDL_RWops *surfaceData; - HMODULE moduleHandle; +SDL_Surface* SDL_ImageResource::load(WORD resourceID) { + HRSRC resource; + HGLOBAL resourceGlobal; + LPVOID resourcePointer; + DWORD resourceSize; + SDL_RWops *surfaceData; + HMODULE moduleHandle; - moduleHandle = GetModuleHandle(NULL); - resource = FindResource(moduleHandle, MAKEINTRESOURCE(resourceID), TEXT("BINARY")); - if (!resource) - return NULL; - resourceSize = SizeofResource(moduleHandle, resource); - if (!resourceSize) - return NULL; - resourceGlobal = LoadResource(moduleHandle, resource); - if (!resourceGlobal) - return NULL; - resourcePointer = LockResource(resourceGlobal); - if (!resourcePointer) - return NULL; + moduleHandle = GetModuleHandle(NULL); + resource = FindResource(moduleHandle, MAKEINTRESOURCE(resourceID), TEXT("BINARY")); + if (!resource) + return NULL; + resourceSize = SizeofResource(moduleHandle, resource); + if (!resourceSize) + return NULL; + resourceGlobal = LoadResource(moduleHandle, resource); + if (!resourceGlobal) + return NULL; + resourcePointer = LockResource(resourceGlobal); + if (!resourcePointer) + return NULL; - surfaceData = SDL_RWFromMem(resourcePointer, resourceSize); - if (!surfaceData) - return NULL; - _surface = SDL_LoadBMP_RW(surfaceData, 1); + surfaceData = SDL_RWFromMem(resourcePointer, resourceSize); + if (!surfaceData) + return NULL; + _surface = SDL_LoadBMP_RW(surfaceData, 1); - return _surface; - } + return _surface; +} - SDL_Surface* SDL_ImageResource::get() { - return _surface; - } +SDL_Surface* SDL_ImageResource::get() { + return _surface; +} - int SDL_ImageResource::height() { - if (_surface) - return _surface->h; - return 0; - } +int SDL_ImageResource::height() { + if (_surface) + return _surface->h; + return 0; +} - int SDL_ImageResource::width() { - if (_surface) - return _surface->w; - return 0; - } +int SDL_ImageResource::width() { + if (_surface) + return _surface->w; + return 0; +} - SDL_ImageResource::~SDL_ImageResource() { - if (_surface) - SDL_FreeSurface(_surface); - } +SDL_ImageResource::~SDL_ImageResource() { + if (_surface) + SDL_FreeSurface(_surface); } + +} // End of namespace CEGUI diff --git a/backends/platform/wince/CEgui/SDL_ImageResource.h b/backends/platform/wince/CEgui/SDL_ImageResource.h index 454237dd15..5affd5c33c 100644 --- a/backends/platform/wince/CEgui/SDL_ImageResource.h +++ b/backends/platform/wince/CEgui/SDL_ImageResource.h @@ -29,20 +29,22 @@ #include "common/scummsys.h" #include "common/system.h" -#include "SDL.h" +struct SDL_Surface; namespace CEGUI { - class SDL_ImageResource { - public: - SDL_ImageResource(); - SDL_Surface* load(WORD resourceID); - SDL_Surface* get(); - int height(); - int width(); - virtual ~SDL_ImageResource(); - private: - SDL_Surface *_surface; - }; -} + +class SDL_ImageResource { +public: + SDL_ImageResource(); + SDL_Surface* load(WORD resourceID); + SDL_Surface* get(); + int height(); + int width(); + virtual ~SDL_ImageResource(); +private: + SDL_Surface *_surface; +}; + +} // End of namespace CEGUI #endif diff --git a/backends/platform/wince/CEgui/Toolbar.cpp b/backends/platform/wince/CEgui/Toolbar.cpp index 0501249de9..c41a30cb43 100644 --- a/backends/platform/wince/CEgui/Toolbar.cpp +++ b/backends/platform/wince/CEgui/Toolbar.cpp @@ -27,12 +27,12 @@ namespace CEGUI { - // Not to be drawn on game screen ! - Toolbar::Toolbar() : GUIElement(0, 0, 320, 40) - { - } +// Not to be drawn on game screen ! +Toolbar::Toolbar() : GUIElement(0, 0, 320, 40) { +} - Toolbar::~Toolbar() { - } +Toolbar::~Toolbar() { } + +} // End of namespace CEGUI diff --git a/backends/platform/wince/CEgui/Toolbar.h b/backends/platform/wince/CEgui/Toolbar.h index 3c48e6188a..9fdf05ab3f 100644 --- a/backends/platform/wince/CEgui/Toolbar.h +++ b/backends/platform/wince/CEgui/Toolbar.h @@ -27,25 +27,20 @@ #define CEGUI_TOOLBAR_H #include "common/scummsys.h" -#include "common/system.h" - -//#include "common/map.h" -#include "common/str.h" #include "GUIElement.h" - - namespace CEGUI { - class Toolbar : public GUIElement { - public: - virtual ~Toolbar(); - virtual bool action(int x, int y, bool pushed) = 0; - protected: - Toolbar(); +class Toolbar : public GUIElement { +public: + virtual ~Toolbar(); + virtual bool action(int x, int y, bool pushed) = 0; +protected: + Toolbar(); + +}; - }; -} +} // End of namespace CEGUI #endif diff --git a/backends/platform/wince/CEgui/ToolbarHandler.cpp b/backends/platform/wince/CEgui/ToolbarHandler.cpp index 3f93a4720d..f74d24ad25 100644 --- a/backends/platform/wince/CEgui/ToolbarHandler.cpp +++ b/backends/platform/wince/CEgui/ToolbarHandler.cpp @@ -23,106 +23,111 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include <SDL.h> + #include "ToolbarHandler.h" namespace CEGUI { - ToolbarHandler::ToolbarHandler(): - _current(""), _active(NULL) { - } - +ToolbarHandler::ToolbarHandler(): +_current(""), _active(NULL) { +} - bool ToolbarHandler::add(const String &name, const Toolbar &toolbar) { - _toolbarMap[name] = (Toolbar*)&toolbar; - if (!_active) { - _active = &((Toolbar&)toolbar); - _current = name; - } +bool ToolbarHandler::add(const String &name, const Toolbar &toolbar) { + _toolbarMap[name] = (Toolbar*)&toolbar; - return true; + if (!_active) { + _active = &((Toolbar&)toolbar); + _current = name; } - String ToolbarHandler::activeName() { - return _current; - } + return true; +} - bool ToolbarHandler::setActive(const String &name) { - if (!_toolbarMap.contains(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) - _current = name; - _active = _toolbarMap[name]; - _active->forceRedraw(); +String ToolbarHandler::activeName() { + return _current; +} + +bool ToolbarHandler::setActive(const String &name) { + if (!_toolbarMap.contains(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) + _current = name; + _active = _toolbarMap[name]; + _active->forceRedraw(); + return true; +} - bool ToolbarHandler::action(int x, int y, bool pushed) { - if (_active && _active->visible()) { - // FIXME ! - if (_offset > 240) - return _active->action(x / 2, (y - _offset) / 2, pushed); - else - return _active->action(x, y - _offset, pushed); - } +bool ToolbarHandler::action(int x, int y, bool pushed) { + if (_active && _active->visible()) { + // FIXME ! + if (_offset > 240) + return _active->action(x / 2, (y - _offset) / 2, pushed); else - return false; + return _active->action(x, y - _offset, pushed); } + else + return false; +} - void ToolbarHandler::setVisible(bool visible) { - if (_active) - _active->setVisible(visible); - } +void ToolbarHandler::setVisible(bool visible) { + if (_active) + _active->setVisible(visible); +} - bool ToolbarHandler::visible() { - if (_active) - return _active->visible(); - else - return false; - } +bool ToolbarHandler::visible() { + if (_active) + return _active->visible(); + else + return false; +} - void ToolbarHandler::forceRedraw() { - if (_active) - _active->forceRedraw(); - } +void ToolbarHandler::forceRedraw() { + if (_active) + _active->forceRedraw(); +} - bool ToolbarHandler::drawn() { - if (_active) - return _active->drawn(); - else - return false; - } +bool ToolbarHandler::drawn() { + if (_active) + return _active->drawn(); + else + return false; +} - bool ToolbarHandler::draw(SDL_Surface *surface, SDL_Rect *rect) { - if (_active) { - bool result = _active->draw(surface); - if (result) { - rect->x = _active->x(); - rect->y = _active->y(); - rect->w = _active->width(); - rect->h = _active->height(); - } - return result; +bool ToolbarHandler::draw(SDL_Surface *surface, SDL_Rect *rect) { + if (_active) { + bool result = _active->draw(surface); + if (result) { + rect->x = _active->x(); + rect->y = _active->y(); + rect->w = _active->width(); + rect->h = _active->height(); } - else - return false; - } + return result; + } else + return false; +} - void ToolbarHandler::setOffset(int offset) { - _offset = offset; - } +void ToolbarHandler::setOffset(int offset) { + _offset = offset; +} - int ToolbarHandler::getOffset() { - return _offset; - } +int ToolbarHandler::getOffset() { + return _offset; +} - Toolbar* ToolbarHandler::active() { - return _active; - } +Toolbar* ToolbarHandler::active() { + return _active; +} - ToolbarHandler::~ToolbarHandler() { - _toolbarMap.clear(); - } +ToolbarHandler::~ToolbarHandler() { + _toolbarMap.clear(); } + +} // End of namespace CEGUI diff --git a/backends/platform/wince/CEgui/ToolbarHandler.h b/backends/platform/wince/CEgui/ToolbarHandler.h index 4a79ed1609..e3bf590768 100644 --- a/backends/platform/wince/CEgui/ToolbarHandler.h +++ b/backends/platform/wince/CEgui/ToolbarHandler.h @@ -39,29 +39,30 @@ using Common::HashMap; namespace CEGUI { - class ToolbarHandler { - public: - ToolbarHandler(); - bool add(const String &name, const Toolbar &toolbar); - bool setActive(const String &name); - bool action(int x, int y, bool pushed); - void setVisible(bool visible); - bool visible(); - String activeName(); - void forceRedraw(); - void setOffset(int offset); - int getOffset(); - bool draw(SDL_Surface *surface, SDL_Rect *rect); - bool drawn(); - Toolbar *active(); - virtual ~ToolbarHandler(); - private: +class ToolbarHandler { +public: + ToolbarHandler(); + bool add(const String &name, const Toolbar &toolbar); + bool setActive(const String &name); + bool action(int x, int y, bool pushed); + void setVisible(bool visible); + bool visible(); + String activeName(); + void forceRedraw(); + void setOffset(int offset); + int getOffset(); + bool draw(SDL_Surface *surface, SDL_Rect *rect); + bool drawn(); + Toolbar *active(); + virtual ~ToolbarHandler(); +private: - HashMap<String, Toolbar*, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _toolbarMap; - String _current; - Toolbar *_active; - int _offset; - }; -} + HashMap<String, Toolbar*, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _toolbarMap; + String _current; + Toolbar *_active; + int _offset; +}; + +} // End of namespace CEGUI #endif diff --git a/backends/platform/wince/CEkeys/EventsBuffer.cpp b/backends/platform/wince/CEkeys/EventsBuffer.cpp index f31a77570f..3cdcb44173 100644 --- a/backends/platform/wince/CEkeys/EventsBuffer.cpp +++ b/backends/platform/wince/CEkeys/EventsBuffer.cpp @@ -23,6 +23,11 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include <SDL.h> + #include "EventsBuffer.h" namespace CEKEYS { diff --git a/backends/platform/wince/CEkeys/EventsBuffer.h b/backends/platform/wince/CEkeys/EventsBuffer.h index 44e1c66e47..22590db03c 100644 --- a/backends/platform/wince/CEkeys/EventsBuffer.h +++ b/backends/platform/wince/CEkeys/EventsBuffer.h @@ -30,8 +30,6 @@ #include "common/system.h" #include "common/list.h" -#include <SDL.h> - #include "gui/Key.h" namespace CEKEYS { diff --git a/backends/platform/wince/missing/assert.h b/backends/platform/wince/missing/assert.h index 0a9dc23bb8..734b8f9482 100644 --- a/backends/platform/wince/missing/assert.h +++ b/backends/platform/wince/missing/assert.h @@ -3,7 +3,7 @@ // defined in common/util.h void CDECL _declspec(noreturn) error(const char *s, ...); -#define assert(e) ((e) ? 0 : (::error("Assertion failed " #e " (%s, %d)", __FILE__, __LINE__))) +#define assert(e) ((e) ? 0 : (::error("Assertion failed %s (%s, %d)", #e, __FILE__, __LINE__))) #define abort() ::error("Abort (%s, %d)", __FILE__, __LINE__) diff --git a/backends/platform/wince/missing/conio.h b/backends/platform/wince/missing/conio.h deleted file mode 100644 index 0cb5c297ea..0000000000 --- a/backends/platform/wince/missing/conio.h +++ /dev/null @@ -1,2 +0,0 @@ -/* Header is not present in Windows CE SDK */ - diff --git a/backends/platform/wince/missing/dir.h b/backends/platform/wince/missing/dir.h deleted file mode 100644 index 7ee9f5e5ba..0000000000 --- a/backends/platform/wince/missing/dir.h +++ /dev/null @@ -1 +0,0 @@ -/* Header is not present in Windows CE SDK */ diff --git a/backends/platform/wince/missing/direct.h b/backends/platform/wince/missing/direct.h deleted file mode 100644 index 7ee9f5e5ba..0000000000 --- a/backends/platform/wince/missing/direct.h +++ /dev/null @@ -1 +0,0 @@ -/* Header is not present in Windows CE SDK */ diff --git a/backends/platform/wince/missing/dirent.h b/backends/platform/wince/missing/dirent.h deleted file mode 100644 index 07e54bbb9d..0000000000 --- a/backends/platform/wince/missing/dirent.h +++ /dev/null @@ -1,52 +0,0 @@ -/* Header is not present in Windows CE SDK */ -/* It would not be a bad idea to take this thing from gcc distro and port - it properly. For now only required part is ported. */ - -struct dirent -{ - long d_ino; /* Always zero. */ - unsigned short d_reclen; /* Always zero. */ - unsigned short d_namlen; /* Length of name in d_name. */ - char* d_name; /* File name. */ - /* NOTE: The name in the dirent structure points to the name in the - * finddata_t structure in the DIR. */ -}; - -/* - * This is an internal data structure. Good programmers will not use it - * except as an argument to one of the functions below. - */ -typedef struct -{ - /* disk transfer area for this dir */ -/* struct _finddata_t dd_dta; */ - - /* dirent struct to return from dir (NOTE: this makes this thread - * safe as long as only one thread uses a particular DIR struct at - * a time) */ - struct dirent dd_dir; - - /* _findnext handle */ - long dd_handle; - - /* - * Status of search: - * 0 = not started yet (next entry to read is first entry) - * -1 = off the end - * positive = 0 based index of next entry - */ - short dd_stat; - - /* given path for dir with search pattern (struct is extended) */ - char dd_name[1]; -} DIR; - - -DIR* opendir (const char*); -struct dirent* readdir (DIR*); -int closedir (DIR*); -/* -void rewinddir (DIR*); -long telldir (DIR*); -void seekdir (DIR*, long); -*/ diff --git a/backends/platform/wince/missing/fcntl.h b/backends/platform/wince/missing/fcntl.h deleted file mode 100644 index 7ee9f5e5ba..0000000000 --- a/backends/platform/wince/missing/fcntl.h +++ /dev/null @@ -1 +0,0 @@ -/* Header is not present in Windows CE SDK */ diff --git a/backends/platform/wince/missing/gcc/assert.h b/backends/platform/wince/missing/gcc/assert.h deleted file mode 100644 index 06742532ac..0000000000 --- a/backends/platform/wince/missing/gcc/assert.h +++ /dev/null @@ -1,9 +0,0 @@ -/* Header is not present in Windows CE SDK */ - -// defined in common/util.h -void CDECL _declspec(noreturn) error(const char *s, ...); - -#define assert(e) ((e) ? (void) 0 : (::error("Assertion failed " #e " (%s, %d)", __FILE__, __LINE__))) - -#define abort() ::error("Abort (%s, %d)", __FILE__, __LINE__) - diff --git a/backends/platform/wince/missing/gcc/direct.h b/backends/platform/wince/missing/gcc/direct.h deleted file mode 100644 index 7ee9f5e5ba..0000000000 --- a/backends/platform/wince/missing/gcc/direct.h +++ /dev/null @@ -1 +0,0 @@ -/* Header is not present in Windows CE SDK */ diff --git a/backends/platform/wince/missing/gcc/errno.h b/backends/platform/wince/missing/gcc/errno.h deleted file mode 100644 index 7ee9f5e5ba..0000000000 --- a/backends/platform/wince/missing/gcc/errno.h +++ /dev/null @@ -1 +0,0 @@ -/* Header is not present in Windows CE SDK */ diff --git a/backends/platform/wince/missing/gcc/sys/stat.h b/backends/platform/wince/missing/gcc/sys/stat.h deleted file mode 100644 index d9eef1318d..0000000000 --- a/backends/platform/wince/missing/gcc/sys/stat.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Header is not present in Windows CE SDK */ - -#include <sys/types.h> - -struct stat { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - time_t st_atime; - time_t st_mtime; - time_t st_ctime; -}; - - -#define _S_IFDIR 0040000 /* directory */ -#define S_IFDIR _S_IFDIR - -int stat(const char *, struct stat *); diff --git a/backends/platform/wince/missing/missing.cpp b/backends/platform/wince/missing/missing.cpp index 532f1d2e89..92af3e6961 100644 --- a/backends/platform/wince/missing/missing.cpp +++ b/backends/platform/wince/missing/missing.cpp @@ -29,19 +29,14 @@ * by Vasyl Tsvirkunov */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL #include <windows.h> #include <tchar.h> #include <string.h> #include <stdlib.h> -#include "sys/stat.h" -#ifndef __GNUC__ -#include "sys/time.h" -#else #include <stdio.h> -#endif -#include "time.h" -#include "dirent.h" #include "common/debug.h" char *strdup(const char *strSource); @@ -74,44 +69,8 @@ void *bsearch(const void *key, const void *base, size_t nmemb, return NULL; } -static WIN32_FIND_DATA wfd; - -int stat(const char *fname, struct stat *ss) { - TCHAR fnameUnc[MAX_PATH+1]; - HANDLE handle; - int len; - - if (fname == NULL || ss == NULL) - return -1; - - /* Special case (dummy on WinCE) */ - len = strlen(fname); - if (len >= 2 && fname[len-1] == '.' && fname[len-2] == '.' && - (len == 2 || fname[len-3] == '\\')) { - /* That's everything implemented so far */ - memset(ss, 0, sizeof(struct stat)); - ss->st_size = 1024; - ss->st_mode |= S_IFDIR; - return 0; - } - - MultiByteToWideChar(CP_ACP, 0, fname, -1, fnameUnc, MAX_PATH); - handle = FindFirstFile(fnameUnc, &wfd); - FindClose(handle); - if (handle == INVALID_HANDLE_VALUE) - return -1; - else - { - /* That's everything implemented so far */ - memset(ss, 0, sizeof(struct stat)); - ss->st_size = wfd.nFileSizeLow; - if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - ss->st_mode |= S_IFDIR; - } - return 0; -} +static char cwd[MAX_PATH+1] = ""; -char cwd[MAX_PATH+1] = ""; EXT_C char *getcwd(char *buffer, int maxlen) { TCHAR fileUnc[MAX_PATH+1]; char* plast; @@ -226,112 +185,6 @@ int _access(const char *path, int mode) { // evc only functions follow #ifndef __GNUC__ -/* Limited dirent implementation. Used by UI.C and DEVICES.C */ -DIR* opendir(const char* fname) { - DIR* pdir; - char fnameMask[MAX_PATH+1]; - TCHAR fnameUnc[MAX_PATH+1]; - char nameFound[MAX_PATH+1]; - - if (fname == NULL) - return NULL; - - strcpy(fnameMask, fname); - if (!strlen(fnameMask) || fnameMask[strlen(fnameMask)-1] != '\\') - strncat(fnameMask, "\\", MAX_PATH-strlen(fnameMask)-1); - strncat(fnameMask, "*.*", MAX_PATH-strlen(fnameMask)-4); - - pdir = (DIR*)malloc(sizeof(DIR)+strlen(fname)); - pdir->dd_dir.d_ino = 0; - pdir->dd_dir.d_reclen = 0; - pdir->dd_dir.d_name = 0; - pdir->dd_dir.d_namlen = 0; - - pdir->dd_handle = 0; - pdir->dd_stat = 0; - strcpy(pdir->dd_name, fname); /* it has exactly enough space for fname and nul char */ - - MultiByteToWideChar(CP_ACP, 0, fnameMask, -1, fnameUnc, MAX_PATH); - if ((pdir->dd_handle = (long)FindFirstFile(fnameUnc, &wfd)) == (long)INVALID_HANDLE_VALUE) { - free(pdir); - return NULL; - } else { - WideCharToMultiByte(CP_ACP, 0, wfd.cFileName, -1, nameFound, MAX_PATH, NULL, NULL); - - pdir->dd_dir.d_name = strdup(nameFound); - pdir->dd_dir.d_namlen = strlen(nameFound); - } - return pdir; -} - -struct dirent* readdir(DIR* dir) { - char nameFound[MAX_PATH+1]; - static struct dirent dummy; - - if (dir->dd_stat == 0) { - dummy.d_name = "."; - dummy.d_namlen = 1; - dir->dd_stat ++; - return &dummy; - } else if (dir->dd_stat == 1) { - dummy.d_name = ".."; - dummy.d_namlen = 2; - dir->dd_stat ++; - return &dummy; - } else if (dir->dd_stat == 2) { - dir->dd_stat++; - return &dir->dd_dir; - } else { - if (FindNextFile((HANDLE)dir->dd_handle, &wfd) == 0) { - dir->dd_stat = -1; - return NULL; - } - WideCharToMultiByte(CP_ACP, 0, wfd.cFileName, -1, nameFound, MAX_PATH, NULL, NULL); - - free(dir->dd_dir.d_name); - - dir->dd_dir.d_name = strdup(nameFound); - dir->dd_dir.d_namlen = strlen(nameFound); - - dir->dd_stat ++; - - return &dir->dd_dir; - } -} - -int closedir(DIR* dir) { - if (dir == NULL) - return 0; - - if (dir->dd_handle) - FindClose((HANDLE)dir->dd_handle); - - free(dir->dd_dir.d_name); - free(dir); - return 1; -} - -/* Make directory, Unix style */ -void mkdir(char* dirname, int mode) { - char path[MAX_PATH+1]; - TCHAR pathUnc[MAX_PATH+1]; - char *ptr; - strncpy(path, dirname, MAX_PATH); - if (*path == '/') - *path = '\\'; - /* Run through the string and attempt creating all subdirs on the path */ - for (ptr = path+1; *ptr; ptr ++) { - if (*ptr == '\\' || *ptr == '/') { - *ptr = 0; - MultiByteToWideChar(CP_ACP, 0, path, -1, pathUnc, MAX_PATH); - CreateDirectory(pathUnc, 0); - *ptr = '\\'; - } - } - MultiByteToWideChar(CP_ACP, 0, path, -1, pathUnc, MAX_PATH); - CreateDirectory(pathUnc, 0); -} - char *strdup(const char *strSource) { char *buffer; size_z len = strlen(strSource) + 1; diff --git a/backends/platform/wince/missing/signal.h b/backends/platform/wince/missing/signal.h deleted file mode 100644 index 128d6bf1db..0000000000 --- a/backends/platform/wince/missing/signal.h +++ /dev/null @@ -1,3 +0,0 @@ -/* Header is not present in Windows CE SDK */ -/* Functionality is not critical -- Pocket PC devices do not have Ctrl+C */ -#define signal(a,b) diff --git a/backends/platform/wince/missing/sys/stat.h b/backends/platform/wince/missing/sys/stat.h deleted file mode 100644 index 8f5bda59e1..0000000000 --- a/backends/platform/wince/missing/sys/stat.h +++ /dev/null @@ -1,25 +0,0 @@ -/* Header is not present in Windows CE SDK */ - -#include <sys/types.h> - -#ifndef __MINGW32CE__ -struct stat { - _dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - _dev_t st_rdev; - _off_t st_size; - time_t st_atime; - time_t st_mtime; - time_t st_ctime; -}; - -int stat(const char *, struct stat *); - -#endif - -#define _S_IFDIR 0040000 /* directory */ -#define S_IFDIR _S_IFDIR diff --git a/backends/platform/wince/missing/sys/time.h b/backends/platform/wince/missing/sys/time.h deleted file mode 100644 index ded29bb009..0000000000 --- a/backends/platform/wince/missing/sys/time.h +++ /dev/null @@ -1,10 +0,0 @@ -/* Header is not present in Windows CE SDK */ - -struct timeval -{ - int tv_sec; - int tv_usec; -}; - -void gettimeofday(struct timeval* tp, void* dummy); -void usleep(long usec); diff --git a/backends/platform/wince/missing/sys/types.h b/backends/platform/wince/missing/sys/types.h deleted file mode 100644 index b6c05e3958..0000000000 --- a/backends/platform/wince/missing/sys/types.h +++ /dev/null @@ -1,5 +0,0 @@ -/* Header is not present in Windows CE SDK */ - -typedef unsigned short _ino_t; -typedef unsigned int _dev_t; -typedef long _off_t; diff --git a/backends/platform/wince/missing/unistd.h b/backends/platform/wince/missing/unistd.h deleted file mode 100644 index 7ee9f5e5ba..0000000000 --- a/backends/platform/wince/missing/unistd.h +++ /dev/null @@ -1 +0,0 @@ -/* Header is not present in Windows CE SDK */ diff --git a/backends/platform/wince/portdefs.h b/backends/platform/wince/portdefs.h index 4b9c53e707..cbf2006be2 100644 --- a/backends/platform/wince/portdefs.h +++ b/backends/platform/wince/portdefs.h @@ -69,14 +69,10 @@ char *strpbrk(const char *s, const char *accept); #include <string.h> #include <io.h> #include <stdarg.h> -#include <fcntl.h> -#include <conio.h> -#include <malloc.h> #include <assert.h> #include <mmsystem.h> #include <ctype.h> //#include <direct.h> -#include <time.h> #ifdef __MINGW32CE__ void *bsearch(const void *, const void *, size_t, size_t, int (*x) (const void *, const void *)); diff --git a/backends/platform/wince/wince-sdl.cpp b/backends/platform/wince/wince-sdl.cpp index ac9be5df48..3f64cb7d5d 100644 --- a/backends/platform/wince/wince-sdl.cpp +++ b/backends/platform/wince/wince-sdl.cpp @@ -23,6 +23,9 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + #include "backends/platform/wince/wince-sdl.h" #include "common/config-manager.h" @@ -970,8 +973,9 @@ bool OSystem_WINCE3::getFeatureState(Feature f) { return false; case kFeatureVirtualKeyboard: return (_panelStateForced); + default: + return OSystem_SDL::getFeatureState(f); } - return OSystem_SDL::getFeatureState(f); } void OSystem_WINCE3::check_mappings() { @@ -2053,7 +2057,7 @@ void OSystem_WINCE3::undrawMouse() { if (SDL_LockSurface(_overlayVisible ? _overlayscreen : _screen) == -1) error("SDL_LockSurface failed: %s", SDL_GetError()); - int x, y; + int y; if (!_overlayVisible) { byte *dst, *bak = _mouseBackupOld; @@ -2242,14 +2246,15 @@ static int mapKeyCE(SDLKey key, SDLMod mod, Uint16 unicode, bool unfilter) { if (unfilter) { switch (key) { - case SDLK_ESCAPE: - return SDLK_BACKSPACE; - case SDLK_F8: - return SDLK_ASTERISK; - case SDLK_F9: - return SDLK_HASH; + case SDLK_ESCAPE: + return SDLK_BACKSPACE; + case SDLK_F8: + return SDLK_ASTERISK; + case SDLK_F9: + return SDLK_HASH; + default: + return key; } - return key; } if (key >= SDLK_KP0 && key <= SDLK_KP9) { @@ -2265,7 +2270,6 @@ static int mapKeyCE(SDLKey key, SDLMod mod, Uint16 unicode, bool unfilter) { bool OSystem_WINCE3::pollEvent(Common::Event &event) { SDL_Event ev; ev.type = SDL_NOEVENT; - byte b = 0; DWORD currentTime; bool keyEvent = false; int deltaX, deltaY; |