diff options
Diffstat (limited to 'backends')
-rw-r--r-- | backends/keymapper/keymapper.cpp | 2 | ||||
-rw-r--r-- | backends/midi/windows.cpp | 40 | ||||
-rw-r--r-- | backends/platform/dc/dc.h | 2 | ||||
-rw-r--r-- | backends/platform/iphone/iphone_common.h | 43 | ||||
-rw-r--r-- | backends/platform/iphone/iphone_main.mm | 3 | ||||
-rw-r--r-- | backends/platform/iphone/iphone_video.h | 26 | ||||
-rw-r--r-- | backends/platform/iphone/iphone_video.mm | 564 | ||||
-rw-r--r-- | backends/platform/iphone/osys_events.cpp | 50 | ||||
-rw-r--r-- | backends/platform/iphone/osys_main.cpp | 21 | ||||
-rw-r--r-- | backends/platform/iphone/osys_main.h | 36 | ||||
-rw-r--r-- | backends/platform/iphone/osys_video.cpp | 432 | ||||
-rw-r--r-- | backends/platform/iphone/osys_video.mm | 485 | ||||
-rw-r--r-- | backends/platform/maemo/maemo-common.h | 9 | ||||
-rw-r--r-- | backends/platform/maemo/maemo.cpp | 11 |
14 files changed, 892 insertions, 832 deletions
diff --git a/backends/keymapper/keymapper.cpp b/backends/keymapper/keymapper.cpp index aafdd604a2..189f862469 100644 --- a/backends/keymapper/keymapper.cpp +++ b/backends/keymapper/keymapper.cpp @@ -119,7 +119,7 @@ void Keymapper::cleanupGameKeymaps() { // the game specific (=deleted) ones. Stack<MapRecord> newStack; - for (int i = 0; i < _activeMaps.size(); i++) { + for (Stack<MapRecord>::size_type i = 0; i < _activeMaps.size(); i++) { if (_activeMaps[i].global) newStack.push(_activeMaps[i]); } diff --git a/backends/midi/windows.cpp b/backends/midi/windows.cpp index 828411cd22..f4c5431d6e 100644 --- a/backends/midi/windows.cpp +++ b/backends/midi/windows.cpp @@ -177,13 +177,49 @@ MusicDevices WindowsMusicPlugin::getDevices() const { int numDevs = midiOutGetNumDevs(); MIDIOUTCAPS tmp; + Common::StringArray deviceNames; for (int i = 0; i < numDevs; i++) { if (midiOutGetDevCaps(i, &tmp, sizeof(MIDIOUTCAPS)) != MMSYSERR_NOERROR) break; + deviceNames.push_back(tmp.szPname); + } + + // Check for non-unique device names. This may happen if someone has devices with identical + // names (e. g. more than one USB device of the exact same hardware type). It seems that this + // does happen in reality sometimes. We generate index numbers for these devices. + // This is not an ideal solution, since this index could change whenever another USB + // device gets plugged in or removed, switched off or just plugged into a different port. + // Unfortunately midiOutGetDevCaps() does not generate any other unique information + // that could be used. Our index numbers which match the device order should at least be + // a little more stable than just using the midiOutGetDevCaps() device ID, since a missing + // device (e.g. switched off) should actually not be harmful to our indices (as it would be + // when using the device IDs). The cases where users have devices with identical names should + // be rare enough anyway. + Common::Array<int> nonUniqueIndex; + for (int i = 0; i < numDevs; i++) { + int match = -1; + for (int ii = 0; ii < i; ii++) { + if (deviceNames[i] == deviceNames[ii]) { + if (nonUniqueIndex[ii] == -1) + nonUniqueIndex[ii] = 0; + if (++match == 0) + ++match; + } + } + nonUniqueIndex.push_back(match); + } + + // We now add the index number to the non-unique device names to make them unique. + for (int i = 0; i < numDevs; i++) { + if (nonUniqueIndex[i] != -1) + deviceNames[i] = Common::String::format("%s - #%.02d", deviceNames[i].c_str(), nonUniqueIndex[i]); + } + + for (Common::StringArray::iterator i = deviceNames.begin(); i != deviceNames.end(); ++i) // There is no way to detect the "MusicType" so I just set it to MT_GM // The user will have to manually select his MT32 type device and his GM type device. - devices.push_back(MusicDevice(this, tmp.szPname, MT_GM)); - } + devices.push_back(MusicDevice(this, *i, MT_GM)); + return devices; } diff --git a/backends/platform/dc/dc.h b/backends/platform/dc/dc.h index 2e32ff3eb4..8ca48bf19e 100644 --- a/backends/platform/dc/dc.h +++ b/backends/platform/dc/dc.h @@ -29,6 +29,8 @@ #include "backends/audiocd/default/default-audiocd.h" #include "backends/fs/fs-factory.h" #include "audio/mixer_intern.h" +#include "common/language.h" +#include "common/platform.h" #ifdef DYNAMIC_MODULES #include "backends/plugins/dynamic-plugin.h" #endif diff --git a/backends/platform/iphone/iphone_common.h b/backends/platform/iphone/iphone_common.h index 5a46a6dde6..19e4f2ce9b 100644 --- a/backends/platform/iphone/iphone_common.h +++ b/backends/platform/iphone/iphone_common.h @@ -23,6 +23,8 @@ #ifndef BACKENDS_PLATFORM_IPHONE_IPHONE_COMMON_H #define BACKENDS_PLATFORM_IPHONE_IPHONE_COMMON_H +#include "graphics/surface.h" + enum InputEvent { kInputMouseDown, kInputMouseUp, @@ -55,21 +57,40 @@ enum GraphicsModes { kGraphicsModeNone = 1 }; +struct VideoContext { + VideoContext() : asprectRatioCorrection(), screenWidth(), screenHeight(), overlayVisible(false), + overlayWidth(), overlayHeight(), mouseX(), mouseY(), + mouseHotspotX(), mouseHotspotY(), mouseWidth(), mouseHeight(), + mouseIsVisible(), graphicsMode(kGraphicsModeLinear), shakeOffsetY() { + } + + // Game screen state + bool asprectRatioCorrection; + uint screenWidth, screenHeight; + Graphics::Surface screenTexture; + + // Overlay state + bool overlayVisible; + uint overlayWidth, overlayHeight; + Graphics::Surface overlayTexture; + + // Mouse cursor state + uint mouseX, mouseY; + int mouseHotspotX, mouseHotspotY; + uint mouseWidth, mouseHeight; + bool mouseIsVisible; + Graphics::Surface mouseTexture; + + // Misc state + GraphicsModes graphicsMode; + int shakeOffsetY; +}; + // On the ObjC side -void iPhone_setGraphicsMode(GraphicsModes mode); -void iPhone_updateScreen(int mouseX, int mouseY); -void iPhone_updateScreenRect(unsigned short *screen, int x1, int y1, int x2, int y2); -void iPhone_updateOverlayRect(unsigned short *screen, int x1, int y1, int x2, int y2); -void iPhone_initSurface(int width, int height); -void iPhone_setShakeOffset(int offset); +void iPhone_updateScreen(); bool iPhone_fetchEvent(int *outEvent, int *outX, int *outY); const char *iPhone_getDocumentsDir(); bool iPhone_isHighResDevice(); -int iPhone_getScreenHeight(); -int iPhone_getScreenWidth(); -void iPhone_enableOverlay(int state); -void iPhone_showCursor(int state); -void iPhone_setMouseCursor(unsigned short *buffer, int width, int height, int hotspotX, int hotspotY); uint getSizeNextPOT(uint size); diff --git a/backends/platform/iphone/iphone_main.mm b/backends/platform/iphone/iphone_main.mm index 1559ef8a6e..20406e6342 100644 --- a/backends/platform/iphone/iphone_main.mm +++ b/backends/platform/iphone/iphone_main.mm @@ -20,6 +20,9 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + #include <UIKit/UIKit.h> #include <Foundation/NSThread.h> diff --git a/backends/platform/iphone/iphone_video.h b/backends/platform/iphone/iphone_video.h index 43a643ab4a..55a4acb7c7 100644 --- a/backends/platform/iphone/iphone_video.h +++ b/backends/platform/iphone/iphone_video.h @@ -32,9 +32,11 @@ #include <OpenGLES/ES1/glext.h> #include "iphone_keyboard.h" +#include "iphone_common.h" @interface iPhoneView : UIView { - void *_screenSurface; + VideoContext _videoContext; + NSMutableArray *_events; SoftKeyboard *_keyboardView; @@ -47,19 +49,33 @@ UIDeviceOrientation _orientation; + GLint _renderBufferWidth; + GLint _renderBufferHeight; + GLfloat _gameScreenVertCoords[4 * 2]; GLfloat _gameScreenTexCoords[4 * 2]; + CGRect _gameScreenRect; GLfloat _overlayVertCoords[4 * 2]; GLfloat _overlayTexCoords[4 * 2]; + CGRect _overlayRect; + + GLfloat _mouseVertCoords[4 * 2]; + GLfloat _mouseTexCoords[4 * 2]; + GLint _mouseHotspotX, _mouseHotspotY; + GLint _mouseWidth, _mouseHeight; + GLfloat _mouseScaleX, _mouseScaleY; + + int _scaledShakeOffsetY; } - (id)initWithFrame:(struct CGRect)frame; -- (void)drawRect:(CGRect)frame; +- (VideoContext *)getVideoContext; -- (void *)getSurface; +- (void)drawRect:(CGRect)frame; +- (void)createScreenTexture; - (void)initSurface; - (void)setViewTransformation; @@ -71,6 +87,8 @@ - (void)updateMouseSurface; - (void)clearColorBuffer; +- (void)notifyMouseMove; +- (void)updateMouseCursorScaling; - (void)updateMouseCursor; - (id)getEvent; @@ -83,4 +101,6 @@ @end +extern iPhoneView *g_iPhoneViewInstance; + #endif diff --git a/backends/platform/iphone/iphone_video.mm b/backends/platform/iphone/iphone_video.mm index 86365cbefe..04aaf59b21 100644 --- a/backends/platform/iphone/iphone_video.mm +++ b/backends/platform/iphone/iphone_video.mm @@ -20,49 +20,22 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + #include "iphone_video.h" -#include "iphone_common.h" -static iPhoneView *sharedInstance = nil; -static GraphicsModes _graphicsMode = kGraphicsModeLinear; -static int _width = 0; -static int _height = 0; +#include "graphics/colormasks.h" + +iPhoneView *g_iPhoneViewInstance = nil; static int _fullWidth; static int _fullHeight; -static CGRect _gameScreenRect; - -static char *_gameScreenTextureBuffer = 0; -static int _gameScreenTextureWidth = 0; -static int _gameScreenTextureHeight = 0; - -static char *_overlayTexBuffer = 0; -static int _overlayTexWidth = 0; -static int _overlayTexHeight = 0; -static int _overlayWidth = 0; -static int _overlayHeight = 0; -static CGRect _overlayRect; static int _needsScreenUpdate = 0; -static int _overlayIsEnabled = 0; static UITouch *_firstTouch = NULL; static UITouch *_secondTouch = NULL; -static unsigned short *_mouseCursor = NULL; -static int _mouseCursorHeight = 0; -static int _mouseCursorWidth = 0; -static int _mouseCursorHotspotX = 0; -static int _mouseCursorHotspotY = 0; -static int _mouseX = 0; -static int _mouseY = 0; -static int _mouseCursorEnabled = 0; - -static GLint _renderBufferWidth; -static GLint _renderBufferHeight; - -static int _shakeOffsetY; -static int _scaledShakeOffsetY; - #if 0 static long lastTick = 0; static int frames = 0; @@ -83,83 +56,20 @@ int printOglError(const char *file, int line) { return retCode; } -void iPhone_setGraphicsMode(GraphicsModes mode) { - _graphicsMode = mode; - - [sharedInstance performSelectorOnMainThread:@selector(setGraphicsMode) withObject:nil waitUntilDone: YES]; -} - -void iPhone_showCursor(int state) { - _mouseCursorEnabled = state; -} - -void iPhone_setMouseCursor(unsigned short *buffer, int width, int height, int hotspotX, int hotspotY) { - _mouseCursor = buffer; - - _mouseCursorWidth = width; - _mouseCursorHeight = height; - - _mouseCursorHotspotX = hotspotX; - _mouseCursorHotspotY = hotspotY; - - [sharedInstance performSelectorOnMainThread:@selector(updateMouseCursor) withObject:nil waitUntilDone: YES]; -} - -void iPhone_enableOverlay(int state) { - _overlayIsEnabled = state; - - [sharedInstance performSelectorOnMainThread:@selector(clearColorBuffer) withObject:nil waitUntilDone: YES]; -} - -int iPhone_getScreenHeight() { - return _overlayHeight; -} - -int iPhone_getScreenWidth() { - return _overlayWidth; -} - bool iPhone_isHighResDevice() { return _fullHeight > 480; } -void iPhone_updateScreen(int mouseX, int mouseY) { +void iPhone_updateScreen() { //printf("Mouse: (%i, %i)\n", mouseX, mouseY); - - _mouseX = mouseX; - _mouseY = mouseY; - if (!_needsScreenUpdate) { _needsScreenUpdate = 1; - [sharedInstance performSelectorOnMainThread:@selector(updateSurface) withObject:nil waitUntilDone: NO]; + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateSurface) withObject:nil waitUntilDone: NO]; } } -void iPhone_updateScreenRect(unsigned short *screen, int x1, int y1, int x2, int y2) { - for (int y = y1; y < y2; ++y) - memcpy(&_gameScreenTextureBuffer[(y * _gameScreenTextureWidth + x1) * 2], &screen[y * _width + x1], (x2 - x1) * 2); -} - -void iPhone_updateOverlayRect(unsigned short *screen, int x1, int y1, int x2, int y2) { - //printf("Overlaywidth: %u, fullwidth %u\n", _overlayWidth, _fullWidth); - for (int y = y1; y < y2; ++y) - memcpy(&_overlayTexBuffer[(y * _overlayTexWidth + x1) * 2], &screen[y * _overlayWidth + x1], (x2 - x1) * 2); -} - -void iPhone_initSurface(int width, int height) { - _width = width; - _height = height; - _shakeOffsetY = 0; - [sharedInstance performSelectorOnMainThread:@selector(initSurface) withObject:nil waitUntilDone: YES]; -} - -void iPhone_setShakeOffset(int offset) { - _shakeOffsetY = offset; - [sharedInstance performSelectorOnMainThread:@selector(setViewTransformation) withObject:nil waitUntilDone: YES]; -} - bool iPhone_fetchEvent(int *outEvent, int *outX, int *outY) { - id event = [sharedInstance getEvent]; + id event = [g_iPhoneViewInstance getEvent]; if (event == nil) { return false; } @@ -196,92 +106,16 @@ const char *iPhone_getDocumentsDir() { return [documentsDirectory UTF8String]; } -/** - * Converts portrait mode coordinates into rotated mode coordinates. - */ -static bool convertToRotatedCoords(UIDeviceOrientation orientation, CGPoint point, CGPoint *result) { - switch (orientation) { - case UIDeviceOrientationLandscapeLeft: - result->x = point.y; - result->y = _renderBufferWidth - point.x; - return true; - - case UIDeviceOrientationLandscapeRight: - result->x = _renderBufferHeight - point.y; - result->y = point.x; - return true; - - case UIDeviceOrientationPortrait: - result->x = point.x; - result->y = point.y; - return true; - - default: - return false; - } -} - -static bool getMouseCoords(UIDeviceOrientation orientation, CGPoint point, int *x, int *y) { - if (!convertToRotatedCoords(orientation, point, &point)) - return false; - - CGRect *area; - int width, height, offsetY; - if (_overlayIsEnabled) { - area = &_overlayRect; - width = _overlayWidth; - height = _overlayHeight; - offsetY = _shakeOffsetY; - } else { - area = &_gameScreenRect; - width = _width; - height = _height; - offsetY = _scaledShakeOffsetY; - } - - point.x = (point.x - CGRectGetMinX(*area)) / CGRectGetWidth(*area); - point.y = (point.y - CGRectGetMinY(*area)) / CGRectGetHeight(*area); - - *x = (int)(point.x * width); - // offsetY describes the translation of the screen in the upward direction, - // thus we need to add it here. - *y = (int)(point.y * height + offsetY); - - // Clip coordinates - if (*x < 0 || *x > CGRectGetWidth(*area) || *y < 0 || *y > CGRectGetHeight(*area)) - return false; - - return true; -} - -static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { - if (!tex) - return; - - glBindTexture(GL_TEXTURE_2D, tex); printOpenGLError(); - - GLint filter = GL_LINEAR; - - switch (mode) { - case kGraphicsModeLinear: - filter = GL_LINEAR; - break; - - case kGraphicsModeNone: - filter = GL_NEAREST; - break; - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); printOpenGLError(); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); printOpenGLError(); -} - @implementation iPhoneView + (Class)layerClass { return [CAEAGLLayer class]; } +- (VideoContext *)getVideoContext { + return &_videoContext; +} + - (void)createContext { CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; @@ -317,20 +151,18 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { return; } - _overlayHeight = _renderBufferWidth; - _overlayWidth = _renderBufferHeight; - _overlayTexWidth = getSizeNextPOT(_overlayHeight); - _overlayTexHeight = getSizeNextPOT(_overlayWidth); + _videoContext.overlayHeight = _renderBufferWidth; + _videoContext.overlayWidth = _renderBufferHeight; + uint overlayTextureWidth = getSizeNextPOT(_videoContext.overlayHeight); + uint overlayTextureHeight = getSizeNextPOT(_videoContext.overlayWidth); // Since the overlay size won't change the whole run, we can // precalculate the texture coordinates for the overlay texture here // and just use it later on. - _overlayTexCoords[2] = _overlayTexCoords[6] = _overlayWidth / (GLfloat)_overlayTexWidth; - _overlayTexCoords[5] = _overlayTexCoords[7] = _overlayHeight / (GLfloat)_overlayTexHeight; + _overlayTexCoords[2] = _overlayTexCoords[6] = _videoContext.overlayWidth / (GLfloat)overlayTextureWidth; + _overlayTexCoords[5] = _overlayTexCoords[7] = _videoContext.overlayHeight / (GLfloat)overlayTextureHeight; - int textureSize = _overlayTexWidth * _overlayTexHeight * 2; - _overlayTexBuffer = (char *)malloc(textureSize); - memset(_overlayTexBuffer, 0, textureSize); + _videoContext.overlayTexture.create(overlayTextureWidth, overlayTextureHeight, Graphics::createPixelFormat<5551>()); glViewport(0, 0, _renderBufferWidth, _renderBufferHeight); printOpenGLError(); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); printOpenGLError(); @@ -356,13 +188,15 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { _fullWidth = (int)frame.size.width; _fullHeight = (int)frame.size.height; - sharedInstance = self; + g_iPhoneViewInstance = self; _keyboardView = nil; _screenTexture = 0; _overlayTexture = 0; _mouseCursorTexture = 0; + _scaledShakeOffsetY = 0; + _gameScreenVertCoords[0] = _gameScreenVertCoords[1] = _gameScreenVertCoords[2] = _gameScreenVertCoords[3] = _gameScreenVertCoords[4] = _gameScreenVertCoords[5] = @@ -383,6 +217,16 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { _overlayTexCoords[4] = _overlayTexCoords[5] = _overlayTexCoords[6] = _overlayTexCoords[7] = 0; + _mouseVertCoords[0] = _mouseVertCoords[1] = + _mouseVertCoords[2] = _mouseVertCoords[3] = + _mouseVertCoords[4] = _mouseVertCoords[5] = + _mouseVertCoords[6] = _mouseVertCoords[7] = 0; + + _mouseTexCoords[0] = _mouseTexCoords[1] = + _mouseTexCoords[2] = _mouseTexCoords[3] = + _mouseTexCoords[4] = _mouseTexCoords[5] = + _mouseTexCoords[6] = _mouseTexCoords[7] = 0; + // Initialize the OpenGL ES context [self createContext]; @@ -396,12 +240,9 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { [_keyboardView dealloc]; } - free(_gameScreenTextureBuffer); - free(_overlayTexBuffer); -} - -- (void *)getSurface { - return _screenSurface; + _videoContext.screenTexture.free(); + _videoContext.overlayTexture.free(); + _videoContext.mouseTexture.free(); } - (void)drawRect:(CGRect)frame { @@ -419,10 +260,32 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { #endif } +- (void)setFilterModeForTexture:(GLuint)tex { + if (!tex) + return; + + glBindTexture(GL_TEXTURE_2D, tex); printOpenGLError(); + + GLint filter = GL_LINEAR; + + switch (_videoContext.graphicsMode) { + case kGraphicsModeLinear: + filter = GL_LINEAR; + break; + + case kGraphicsModeNone: + filter = GL_NEAREST; + break; + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); printOpenGLError(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); printOpenGLError(); +} + - (void)setGraphicsMode { - setFilterModeForTexture(_screenTexture, _graphicsMode); - setFilterModeForTexture(_overlayTexture, _graphicsMode); - setFilterModeForTexture(_mouseCursorTexture, _graphicsMode); + [self setFilterModeForTexture:_screenTexture]; + [self setFilterModeForTexture:_overlayTexture]; + [self setFilterModeForTexture:_mouseCursorTexture]; } - (void)updateSurface { @@ -435,10 +298,10 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { [self updateMainSurface]; - if (_overlayIsEnabled) + if (_videoContext.overlayVisible) [self updateOverlaySurface]; - if (_mouseCursorEnabled) + if (_videoContext.mouseIsVisible) [self updateMouseSurface]; glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); @@ -446,17 +309,70 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { } +- (void)notifyMouseMove { + const GLint mouseX = (GLint)(_videoContext.mouseX * _mouseScaleX) - _mouseHotspotX; + const GLint mouseY = (GLint)(_videoContext.mouseY * _mouseScaleY) - _mouseHotspotY; + + _mouseVertCoords[0] = _mouseVertCoords[4] = mouseX; + _mouseVertCoords[1] = _mouseVertCoords[3] = mouseY; + _mouseVertCoords[2] = _mouseVertCoords[6] = mouseX + _mouseWidth; + _mouseVertCoords[5] = _mouseVertCoords[7] = mouseY + _mouseHeight; +} + +- (void)updateMouseCursorScaling { + CGRect *rect; + int maxWidth, maxHeight; + + if (!_videoContext.overlayVisible) { + rect = &_gameScreenRect; + maxWidth = _videoContext.screenWidth; + maxHeight = _videoContext.screenHeight; + } else { + rect = &_overlayRect; + maxWidth = _videoContext.overlayWidth; + maxHeight = _videoContext.overlayHeight; + } + + if (!maxWidth || !maxHeight) { + printf("WARNING: updateMouseCursorScaling called when screen was not ready (%d)!\n", _videoContext.overlayVisible); + return; + } + + _mouseScaleX = CGRectGetWidth(*rect) / (GLfloat)maxWidth; + _mouseScaleY = CGRectGetHeight(*rect) / (GLfloat)maxHeight; + + _mouseWidth = (GLint)(_videoContext.mouseWidth * _mouseScaleX); + _mouseHeight = (GLint)(_videoContext.mouseHeight * _mouseScaleY); + + _mouseHotspotX = (GLint)(_videoContext.mouseHotspotX * _mouseScaleX); + _mouseHotspotY = (GLint)(_videoContext.mouseHotspotY * _mouseScaleY); + + // We subtract the screen offset to the hotspot here to simplify the + // screen offset handling in the mouse code. Note the subtraction here + // makes sure that the offset actually gets added to the mouse position, + // since the hotspot offset is substracted from the position. + _mouseHotspotX -= (GLint)CGRectGetMinX(*rect); + _mouseHotspotY -= (GLint)CGRectGetMinY(*rect); + + // FIXME: For now we also adapt the mouse position here. In reality we + // would be better off to also adjust the event position when switching + // from overlay to game screen or vica versa. + [self notifyMouseMove]; +} + - (void)updateMouseCursor { if (_mouseCursorTexture == 0) { glGenTextures(1, &_mouseCursorTexture); printOpenGLError(); - setFilterModeForTexture(_mouseCursorTexture, _graphicsMode); + [self setFilterModeForTexture:_mouseCursorTexture]; } - glBindTexture(GL_TEXTURE_2D, _mouseCursorTexture); printOpenGLError(); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getSizeNextPOT(_mouseCursorWidth), getSizeNextPOT(_mouseCursorHeight), 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _mouseCursor); printOpenGLError(); + [self updateMouseCursorScaling]; - free(_mouseCursor); - _mouseCursor = NULL; + _mouseTexCoords[2] = _mouseTexCoords[6] = _videoContext.mouseWidth / (GLfloat)_videoContext.mouseTexture.w; + _mouseTexCoords[5] = _mouseTexCoords[7] = _videoContext.mouseHeight / (GLfloat)_videoContext.mouseTexture.h; + + glBindTexture(GL_TEXTURE_2D, _mouseCursorTexture); printOpenGLError(); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.mouseTexture.w, _videoContext.mouseTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.mouseTexture.pixels); printOpenGLError(); } - (void)updateMainSurface { @@ -468,7 +384,7 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { // Unfortunately we have to update the whole texture every frame, since glTexSubImage2D is actually slower in all cases // due to the iPhone internals having to convert the whole texture back from its internal format when used. // In the future we could use several tiled textures instead. - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _gameScreenTextureWidth, _gameScreenTextureHeight, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, _gameScreenTextureBuffer); printOpenGLError(); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _videoContext.screenTexture.w, _videoContext.screenTexture.h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, _videoContext.screenTexture.pixels); printOpenGLError(); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); } @@ -477,147 +393,83 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { glTexCoordPointer(2, GL_FLOAT, 0, _overlayTexCoords); printOpenGLError(); glBindTexture(GL_TEXTURE_2D, _overlayTexture); printOpenGLError(); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _overlayTexWidth, _overlayTexHeight, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _overlayTexBuffer); printOpenGLError(); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _videoContext.overlayTexture.w, _videoContext.overlayTexture.h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, _videoContext.overlayTexture.pixels); printOpenGLError(); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); } - (void)updateMouseSurface { - int width = _mouseCursorWidth; - int height = _mouseCursorHeight; - - int mouseX = _mouseX; - int mouseY = _mouseY; - - int hotspotX = _mouseCursorHotspotX; - int hotspotY = _mouseCursorHotspotY; - - CGRect *rect; - int maxWidth, maxHeight; - - if (!_overlayIsEnabled) { - rect = &_gameScreenRect; - maxWidth = _width; - maxHeight = _height; - } else { - rect = &_overlayRect; - maxWidth = _overlayWidth; - maxHeight = _overlayHeight; - } - - const GLfloat scaleX = CGRectGetWidth(*rect) / (GLfloat)maxWidth; - const GLfloat scaleY = CGRectGetHeight(*rect) / (GLfloat)maxHeight; - - mouseX = (int)(mouseX * scaleX); - mouseY = (int)(mouseY * scaleY); - hotspotX = (int)(hotspotX * scaleX); - hotspotY = (int)(hotspotY * scaleY); - width = (int)(width * scaleX); - height = (int)(height * scaleY); - - mouseX -= hotspotX; - mouseY -= hotspotY; - - mouseX += (int)CGRectGetMinX(*rect); - mouseY += (int)CGRectGetMinY(*rect); - - GLfloat vertices[] = { - // Top left - mouseX , mouseY, - // Top right - mouseX + width, mouseY, - // Bottom left - mouseX , mouseY + height, - // Bottom right - mouseX + width, mouseY + height - }; - - //printf("Cursor: width %u height %u\n", _mouseCursorWidth, _mouseCursorHeight); - - float texWidth = _mouseCursorWidth / (float)getSizeNextPOT(_mouseCursorWidth); - float texHeight = _mouseCursorHeight / (float)getSizeNextPOT(_mouseCursorHeight); - - const GLfloat texCoords[] = { - // Top left - 0 , 0, - // Top right - texWidth, 0, - // Bottom left - 0 , texHeight, - // Bottom right - texWidth, texHeight - }; - - glVertexPointer(2, GL_FLOAT, 0, vertices); printOpenGLError(); - glTexCoordPointer(2, GL_FLOAT, 0, texCoords); printOpenGLError(); + glVertexPointer(2, GL_FLOAT, 0, _mouseVertCoords); printOpenGLError(); + glTexCoordPointer(2, GL_FLOAT, 0, _mouseTexCoords); printOpenGLError(); glBindTexture(GL_TEXTURE_2D, _mouseCursorTexture); printOpenGLError(); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); } -- (void)initSurface { - _gameScreenTextureWidth = getSizeNextPOT(_width); - _gameScreenTextureHeight = getSizeNextPOT(_height); - - _gameScreenTexCoords[2] = _gameScreenTexCoords[6] = _width / (GLfloat)_gameScreenTextureWidth; - _gameScreenTexCoords[5] = _gameScreenTexCoords[7] = _height / (GLfloat)_gameScreenTextureHeight; +- (void)setUpOrientation:(UIDeviceOrientation)orientation width:(int *)width height:(int *)height { + _orientation = orientation; - _orientation = [[UIDevice currentDevice] orientation]; + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + // We always force the origin (0,0) to be in the upper left corner. switch (_orientation) { - case UIDeviceOrientationLandscapeLeft: case UIDeviceOrientationLandscapeRight: - case UIDeviceOrientationPortrait: + glRotatef( 90, 0, 0, 1); printOpenGLError(); + glOrthof(0, _renderBufferHeight, _renderBufferWidth, 0, 0, 1); printOpenGLError(); + + *width = _renderBufferHeight; + *height = _renderBufferWidth; + break; + + case UIDeviceOrientationLandscapeLeft: + glRotatef(-90, 0, 0, 1); printOpenGLError(); + glOrthof(0, _renderBufferHeight, _renderBufferWidth, 0, 0, 1); printOpenGLError(); + + *width = _renderBufferHeight; + *height = _renderBufferWidth; break; + case UIDeviceOrientationPortrait: default: + // We must force the portrait orientation here, since we might not know + // the real orientation. _orientation = UIDeviceOrientationPortrait; - } - - //printf("Window: (%d, %d), Surface: (%d, %d), Texture(%d, %d)\n", _fullWidth, _fullHeight, _width, _height, _gameScreenTextureWidth, _gameScreenTextureHeight); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); + glOrthof(0, _renderBufferWidth, _renderBufferHeight, 0, 0, 1); printOpenGLError(); - int screenWidth, screenHeight; + *width = _renderBufferWidth; + *height = _renderBufferHeight; + break; + } +} - // Set the origin (0,0) depending on the rotation mode. - if (_orientation == UIDeviceOrientationLandscapeRight) { - glRotatef( 90, 0, 0, 1); printOpenGLError(); - glOrthof(0, _renderBufferHeight, _renderBufferWidth, 0, 0, 1); printOpenGLError(); +- (void)createScreenTexture { + const uint screenTexWidth = getSizeNextPOT(_videoContext.screenWidth); + const uint screenTexHeight = getSizeNextPOT(_videoContext.screenHeight); - screenWidth = _renderBufferHeight; - screenHeight = _renderBufferWidth; - } else if (_orientation == UIDeviceOrientationLandscapeLeft) { - glRotatef(-90, 0, 0, 1); printOpenGLError(); - glOrthof(0, _renderBufferHeight, _renderBufferWidth, 0, 0, 1); printOpenGLError(); + _gameScreenTexCoords[2] = _gameScreenTexCoords[6] = _videoContext.screenWidth / (GLfloat)screenTexWidth; + _gameScreenTexCoords[5] = _gameScreenTexCoords[7] = _videoContext.screenHeight / (GLfloat)screenTexHeight; - screenWidth = _renderBufferHeight; - screenHeight = _renderBufferWidth; - } else if (_orientation == UIDeviceOrientationPortrait) { - glOrthof(0, _renderBufferWidth, _renderBufferHeight, 0, 0, 1); printOpenGLError(); + _videoContext.screenTexture.create(screenTexWidth, screenTexHeight, Graphics::createPixelFormat<565>()); +} - screenWidth = _renderBufferWidth; - screenHeight = _renderBufferHeight; - } +- (void)initSurface { + int screenWidth, screenHeight; + [self setUpOrientation:[[UIDevice currentDevice] orientation] width:&screenWidth height:&screenHeight]; if (_screenTexture > 0) { glDeleteTextures(1, &_screenTexture); printOpenGLError(); } glGenTextures(1, &_screenTexture); printOpenGLError(); - setFilterModeForTexture(_screenTexture, _graphicsMode); + [self setFilterModeForTexture:_screenTexture]; if (_overlayTexture > 0) { glDeleteTextures(1, &_overlayTexture); printOpenGLError(); } glGenTextures(1, &_overlayTexture); printOpenGLError(); - setFilterModeForTexture(_overlayTexture, _graphicsMode); - - free(_gameScreenTextureBuffer); - int textureSize = _gameScreenTextureWidth * _gameScreenTextureHeight * 2; - _gameScreenTextureBuffer = (char *)malloc(textureSize); - memset(_gameScreenTextureBuffer, 0, textureSize); + [self setFilterModeForTexture:_overlayTexture]; glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); @@ -628,10 +480,19 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { [[_keyboardView inputView] removeFromSuperview]; } + GLfloat adjustedWidth = _videoContext.screenWidth; + GLfloat adjustedHeight = _videoContext.screenHeight; + if (_videoContext.asprectRatioCorrection) { + if (_videoContext.screenWidth == 320 && _videoContext.screenHeight == 200) + adjustedHeight = 240; + else if (_videoContext.screenWidth == 640 && _videoContext.screenHeight == 400) + adjustedHeight = 480; + } + float overlayPortraitRatio; if (_orientation == UIDeviceOrientationLandscapeLeft || _orientation == UIDeviceOrientationLandscapeRight) { - GLfloat gameScreenRatio = (GLfloat)_width / (GLfloat)_height; + GLfloat gameScreenRatio = adjustedWidth / adjustedHeight; GLfloat screenRatio = (GLfloat)screenWidth / (GLfloat)screenHeight; // These are the width/height according to the portrait layout! @@ -660,7 +521,7 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { _gameScreenRect = CGRectMake(xOffset, yOffset, rectWidth, rectHeight); overlayPortraitRatio = 1.0f; } else { - float ratio = (float)_height / (float)_width; + GLfloat ratio = adjustedHeight / adjustedWidth; int height = (int)(screenWidth * ratio); //printf("Making rect (%u, %u)\n", screenWidth, height); _gameScreenRect = CGRectMake(0, 0, screenWidth, height); @@ -674,7 +535,7 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { [self addSubview:[_keyboardView inputView]]; [self addSubview: _keyboardView]; [[_keyboardView inputView] becomeFirstResponder]; - overlayPortraitRatio = (_overlayHeight * ratio) / _overlayWidth; + overlayPortraitRatio = (_videoContext.overlayHeight * ratio) / _videoContext.overlayWidth; } _overlayRect = CGRectMake(0, 0, screenWidth, screenHeight * overlayPortraitRatio); @@ -688,6 +549,7 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { _overlayVertCoords[5] = _overlayVertCoords[7] = CGRectGetMaxY(_overlayRect); [self setViewTransformation]; + [self updateMouseCursorScaling]; } - (void)setViewTransformation { @@ -698,7 +560,7 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { // Scale the shake offset according to the overlay size. We need this to // adjust the overlay mouse click coordinates when an offset is set. - _scaledShakeOffsetY = (int)(_shakeOffsetY / (GLfloat)_height * CGRectGetHeight(_overlayRect)); + _scaledShakeOffsetY = (int)(_videoContext.shakeOffsetY / (GLfloat)_videoContext.screenHeight * CGRectGetHeight(_overlayRect)); // Apply the shakeing to the output screen. glTranslatef(0, -_scaledShakeOffsetY, 0); @@ -732,6 +594,64 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { [_events addObject: event]; } +/** + * Converts portrait mode coordinates into rotated mode coordinates. + */ +- (bool)convertToRotatedCoords:(CGPoint)point result:(CGPoint *)result { + switch (_orientation) { + case UIDeviceOrientationLandscapeLeft: + result->x = point.y; + result->y = _renderBufferWidth - point.x; + return true; + + case UIDeviceOrientationLandscapeRight: + result->x = _renderBufferHeight - point.y; + result->y = point.x; + return true; + + case UIDeviceOrientationPortrait: + result->x = point.x; + result->y = point.y; + return true; + + default: + return false; + } +} + +- (bool)getMouseCoords:(CGPoint)point eventX:(int *)x eventY:(int *)y { + if (![self convertToRotatedCoords:point result:&point]) + return false; + + CGRect *area; + int width, height, offsetY; + if (_videoContext.overlayVisible) { + area = &_overlayRect; + width = _videoContext.overlayWidth; + height = _videoContext.overlayHeight; + offsetY = _scaledShakeOffsetY; + } else { + area = &_gameScreenRect; + width = _videoContext.screenWidth; + height = _videoContext.screenHeight; + offsetY = _videoContext.shakeOffsetY; + } + + point.x = (point.x - CGRectGetMinX(*area)) / CGRectGetWidth(*area); + point.y = (point.y - CGRectGetMinY(*area)) / CGRectGetHeight(*area); + + *x = (int)(point.x * width); + // offsetY describes the translation of the screen in the upward direction, + // thus we need to add it here. + *y = (int)(point.y * height + offsetY); + + // Clip coordinates + if (*x < 0 || *x > width || *y < 0 || *y > height) + return false; + + return true; +} + - (void)deviceOrientationChanged:(UIDeviceOrientation)orientation { switch (orientation) { case UIDeviceOrientationLandscapeLeft: @@ -762,7 +682,7 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { case 1: { UITouch *touch = [touches anyObject]; CGPoint point = [touch locationInView:self]; - if (!getMouseCoords(_orientation, point, &x, &y)) + if (![self getMouseCoords:point eventX:&x eventY:&y]) return; _firstTouch = touch; @@ -780,7 +700,7 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { case 2: { UITouch *touch = [touches anyObject]; CGPoint point = [touch locationInView:self]; - if (!getMouseCoords(_orientation, point, &x, &y)) + if (![self getMouseCoords:point eventX:&x eventY:&y]) return; _secondTouch = touch; @@ -804,7 +724,7 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { for (UITouch *touch in touches) { if (touch == _firstTouch) { CGPoint point = [touch locationInView:self]; - if (!getMouseCoords(_orientation, point, &x, &y)) + if (![self getMouseCoords:point eventX:&x eventY:&y]) return; [self addEvent: @@ -817,7 +737,7 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { ]; } else if (touch == _secondTouch) { CGPoint point = [touch locationInView:self]; - if (!getMouseCoords(_orientation, point, &x, &y)) + if (![self getMouseCoords:point eventX:&x eventY:&y]) return; [self addEvent: @@ -840,7 +760,7 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { case 1: { UITouch *touch = [[allTouches allObjects] objectAtIndex:0]; CGPoint point = [touch locationInView:self]; - if (!getMouseCoords(_orientation, point, &x, &y)) + if (![self getMouseCoords:point eventX:&x eventY:&y]) return; [self addEvent: @@ -857,7 +777,7 @@ static void setFilterModeForTexture(GLuint tex, GraphicsModes mode) { case 2: { UITouch *touch = [[allTouches allObjects] objectAtIndex:1]; CGPoint point = [touch locationInView:self]; - if (!getMouseCoords(_orientation, point, &x, &y)) + if (![self getMouseCoords:point eventX:&x eventY:&y]) return; [self addEvent: diff --git a/backends/platform/iphone/osys_events.cpp b/backends/platform/iphone/osys_events.cpp index c167da35e6..85efbda208 100644 --- a/backends/platform/iphone/osys_events.cpp +++ b/backends/platform/iphone/osys_events.cpp @@ -122,8 +122,8 @@ bool OSystem_IPHONE::handleEvent_mouseDown(Common::Event &event, int x, int y) { if (_mouseClickAndDragEnabled) { event.type = Common::EVENT_LBUTTONDOWN; - event.mouse.x = _mouseX; - event.mouse.y = _mouseY; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; return true; } else { _lastMouseDown = getMillis(); @@ -140,17 +140,17 @@ bool OSystem_IPHONE::handleEvent_mouseUp(Common::Event &event, int x, int y) { return false; } else if (_mouseClickAndDragEnabled) { event.type = Common::EVENT_LBUTTONUP; - event.mouse.x = _mouseX; - event.mouse.y = _mouseY; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; } else { if (getMillis() - _lastMouseDown < 250) { event.type = Common::EVENT_LBUTTONDOWN; - event.mouse.x = _mouseX; - event.mouse.y = _mouseY; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; _queuedInputEvent.type = Common::EVENT_LBUTTONUP; - _queuedInputEvent.mouse.x = _mouseX; - _queuedInputEvent.mouse.y = _mouseY; + _queuedInputEvent.mouse.x = _videoContext->mouseX; + _queuedInputEvent.mouse.y = _videoContext->mouseY; _lastMouseTap = getMillis(); _queuedEventTime = _lastMouseTap + kQueuedInputEventDelay; } else @@ -167,12 +167,12 @@ bool OSystem_IPHONE::handleEvent_secondMouseDown(Common::Event &event, int x, in if (_mouseClickAndDragEnabled) { event.type = Common::EVENT_LBUTTONUP; - event.mouse.x = _mouseX; - event.mouse.y = _mouseY; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; _queuedInputEvent.type = Common::EVENT_RBUTTONDOWN; - _queuedInputEvent.mouse.x = _mouseX; - _queuedInputEvent.mouse.y = _mouseY; + _queuedInputEvent.mouse.x = _videoContext->mouseX; + _queuedInputEvent.mouse.y = _videoContext->mouseY; } else return false; @@ -184,7 +184,7 @@ bool OSystem_IPHONE::handleEvent_secondMouseUp(Common::Event &event, int x, int if (curTime - _lastSecondaryDown < 400) { //printf("Right tap!\n"); - if (curTime - _lastSecondaryTap < 400 && !_overlayVisible) { + if (curTime - _lastSecondaryTap < 400 && !_videoContext->overlayVisible) { //printf("Right escape!\n"); event.type = Common::EVENT_KEYDOWN; _queuedInputEvent.type = Common::EVENT_KEYUP; @@ -197,11 +197,11 @@ bool OSystem_IPHONE::handleEvent_secondMouseUp(Common::Event &event, int x, int } else if (!_mouseClickAndDragEnabled) { //printf("Rightclick!\n"); event.type = Common::EVENT_RBUTTONDOWN; - event.mouse.x = _mouseX; - event.mouse.y = _mouseY; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; _queuedInputEvent.type = Common::EVENT_RBUTTONUP; - _queuedInputEvent.mouse.x = _mouseX; - _queuedInputEvent.mouse.y = _mouseY; + _queuedInputEvent.mouse.x = _videoContext->mouseX; + _queuedInputEvent.mouse.y = _videoContext->mouseY; _lastSecondaryTap = curTime; _queuedEventTime = curTime + kQueuedInputEventDelay; } else { @@ -211,8 +211,8 @@ bool OSystem_IPHONE::handleEvent_secondMouseUp(Common::Event &event, int x, int } if (_mouseClickAndDragEnabled) { event.type = Common::EVENT_RBUTTONUP; - event.mouse.x = _mouseX; - event.mouse.y = _mouseY; + event.mouse.x = _videoContext->mouseX; + event.mouse.y = _videoContext->mouseY; } return true; @@ -234,11 +234,11 @@ bool OSystem_IPHONE::handleEvent_mouseDragged(Common::Event &event, int x, int y _lastPadX = x; _lastPadY = y; - mouseNewPosX = (int)(_mouseX - deltaX / 0.5f); - mouseNewPosY = (int)(_mouseY - deltaY / 0.5f); + mouseNewPosX = (int)(_videoContext->mouseX - deltaX / 0.5f); + mouseNewPosY = (int)(_videoContext->mouseY - deltaY / 0.5f); - int widthCap = _overlayVisible ? _overlayWidth : _screenWidth; - int heightCap = _overlayVisible ? _overlayHeight : _screenHeight; + int widthCap = _videoContext->overlayVisible ? _videoContext->overlayWidth : _videoContext->screenWidth; + int heightCap = _videoContext->overlayVisible ? _videoContext->overlayHeight : _videoContext->screenHeight; if (mouseNewPosX < 0) mouseNewPosX = 0; @@ -350,10 +350,10 @@ void OSystem_IPHONE::handleEvent_orientationChanged(int orientation) { if (_screenOrientation != newOrientation) { _screenOrientation = newOrientation; - iPhone_initSurface(_screenWidth, _screenHeight); + updateOutputSurface(); dirtyFullScreen(); - if (_overlayVisible) + if (_videoContext->overlayVisible) dirtyFullOverlayScreen(); updateScreen(); } diff --git a/backends/platform/iphone/osys_main.cpp b/backends/platform/iphone/osys_main.cpp index 2bdc09c9ce..f3e0d97b97 100644 --- a/backends/platform/iphone/osys_main.cpp +++ b/backends/platform/iphone/osys_main.cpp @@ -55,26 +55,28 @@ SoundProc OSystem_IPHONE::s_soundCallback = NULL; void *OSystem_IPHONE::s_soundParam = NULL; OSystem_IPHONE::OSystem_IPHONE() : - _mixer(NULL), _gameScreenRaw(NULL), - _overlayVisible(false), _gameScreenConverted(NULL), - _mouseHeight(0), _mouseWidth(0), _mouseBuf(NULL), _lastMouseTap(0), _queuedEventTime(0), + _mixer(NULL), _lastMouseTap(0), _queuedEventTime(0), _mouseNeedTextureUpdate(false), _secondaryTapped(false), _lastSecondaryTap(0), _screenOrientation(kScreenOrientationFlippedLandscape), _mouseClickAndDragEnabled(false), _gestureStartX(-1), _gestureStartY(-1), _fullScreenIsDirty(false), _fullScreenOverlayIsDirty(false), _mouseDirty(false), _timeSuspended(0), _lastDragPosX(-1), _lastDragPosY(-1), _screenChangeCount(0), - _overlayHeight(0), _overlayWidth(0), _overlayBuffer(0), _mouseCursorPaletteEnabled(false), - _currentGraphicsMode(kGraphicsModeLinear) { + _mouseCursorPaletteEnabled(false) { _queuedInputEvent.type = Common::EVENT_INVALID; _touchpadModeEnabled = !iPhone_isHighResDevice(); _fsFactory = new POSIXFilesystemFactory(); + initVideoContext(); } OSystem_IPHONE::~OSystem_IPHONE() { AudioQueueDispose(s_AudioQueue.queue, true); delete _mixer; - free(_gameScreenRaw); - free(_gameScreenConverted); + // Prevent accidental freeing of the screen texture here. This needs to be + // checked since we might use the screen texture as framebuffer in the case + // of hi-color games for example. + if (_framebuffer.pixels == _videoContext->screenTexture.pixels) + _framebuffer.free(); + _mouseBuffer.free(); } int OSystem_IPHONE::timerHandler(int t) { @@ -120,6 +122,9 @@ void OSystem_IPHONE::setFeatureState(Feature f, bool enable) { _mouseCursorPaletteEnabled = enable; } break; + case kFeatureAspectRatioCorrection: + _videoContext->asprectRatioCorrection = enable; + break; default: break; @@ -130,6 +135,8 @@ bool OSystem_IPHONE::getFeatureState(Feature f) { switch (f) { case kFeatureCursorPalette: return _mouseCursorPaletteEnabled; + case kFeatureAspectRatioCorrection: + return _videoContext->asprectRatioCorrection; default: return false; diff --git a/backends/platform/iphone/osys_main.h b/backends/platform/iphone/osys_main.h index e4b3d358d5..5d0f60c34c 100644 --- a/backends/platform/iphone/osys_main.h +++ b/backends/platform/iphone/osys_main.h @@ -59,39 +59,27 @@ protected: static SoundProc s_soundCallback; static void *s_soundParam; - int _currentGraphicsMode; - Audio::MixerImpl *_mixer; - Graphics::Surface _framebuffer; - byte *_gameScreenRaw; - OverlayColor *_overlayBuffer; - uint16 _overlayHeight; - uint16 _overlayWidth; + VideoContext *_videoContext; - uint16 *_gameScreenConverted; + Graphics::Surface _framebuffer; // For use with the game texture uint16 _gamePalette[256]; // For use with the mouse texture uint16 _gamePaletteRGBA5551[256]; - bool _overlayVisible; - uint16 _screenWidth; - uint16 _screenHeight; struct timeval _startTime; uint32 _timeSuspended; - bool _mouseVisible; bool _mouseCursorPaletteEnabled; uint16 _mouseCursorPalette[256]; - byte *_mouseBuf; - byte _mouseKeyColor; - uint _mouseWidth, _mouseHeight; - uint _mouseX, _mouseY; - int _mouseHotspotX, _mouseHotspotY; + Graphics::Surface _mouseBuffer; + uint16 _mouseKeyColor; bool _mouseDirty; bool _mouseNeedTextureUpdate; + long _lastMouseDown; long _lastMouseTap; long _queuedEventTime; @@ -133,9 +121,18 @@ public: virtual bool setGraphicsMode(int mode); virtual int getGraphicsMode() const; virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format); + + virtual void beginGFXTransaction(); + virtual TransactionError endGFXTransaction(); + virtual int16 getHeight(); virtual int16 getWidth(); +#ifdef USE_RGB_COLOR + virtual Graphics::PixelFormat getScreenFormat() const { return _framebuffer.format; } + virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const; +#endif + virtual PaletteManager *getPaletteManager() { return this; } protected: // PaletteManager API @@ -192,13 +189,14 @@ public: virtual void logMessage(LogMessageType::Type type, const char *message); protected: + void initVideoContext(); + void updateOutputSurface(); + void internUpdateScreen(); void dirtyFullScreen(); void dirtyFullOverlayScreen(); void suspendLoop(); void drawDirtyRect(const Common::Rect &dirtyRect); - void drawDirtyOverlayRect(const Common::Rect &dirtyRect); - void updateHardwareSurfaceForRect(const Common::Rect &updatedRect); void updateMouseTexture(); static void AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB); static int timerHandler(int t); diff --git a/backends/platform/iphone/osys_video.cpp b/backends/platform/iphone/osys_video.cpp deleted file mode 100644 index e26c360c82..0000000000 --- a/backends/platform/iphone/osys_video.cpp +++ /dev/null @@ -1,432 +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. - * - */ - -// 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 { - return s_supportedGraphicsModes; -} - - -int OSystem_IPHONE::getDefaultGraphicsMode() const { - return kGraphicsModeLinear; -} - -bool OSystem_IPHONE::setGraphicsMode(int mode) { - switch (mode) { - case kGraphicsModeNone: - case kGraphicsModeLinear: - _currentGraphicsMode = mode; - iPhone_setGraphicsMode((GraphicsModes)mode); - return true; - - default: - return false; - } -} - -int OSystem_IPHONE::getGraphicsMode() const { - return _currentGraphicsMode; -} - -void OSystem_IPHONE::initSize(uint width, uint height, const Graphics::PixelFormat *format) { - //printf("initSize(%i, %i)\n", width, height); - - _screenWidth = width; - _screenHeight = height; - - free(_gameScreenRaw); - - _gameScreenRaw = (byte *)malloc(width * height); - bzero(_gameScreenRaw, width * height); - - //free(_overlayBuffer); - - int fullSize = _screenWidth * _screenHeight * sizeof(OverlayColor); - //_overlayBuffer = (OverlayColor *)malloc(fullSize); - clearOverlay(); - - free(_gameScreenConverted); - - _gameScreenConverted = (uint16 *)malloc(fullSize); - bzero(_gameScreenConverted, fullSize); - - iPhone_initSurface(width, height); - - if (_overlayBuffer == NULL) { - _overlayHeight = iPhone_getScreenHeight(); - _overlayWidth = iPhone_getScreenWidth(); - - printf("Overlay: (%u x %u)\n", _overlayWidth, _overlayHeight); - _overlayBuffer = new OverlayColor[_overlayHeight * _overlayWidth]; - } - - _fullScreenIsDirty = false; - dirtyFullScreen(); - _mouseVisible = false; - _mouseCursorPaletteEnabled = false; - _screenChangeCount++; - updateScreen(); -} - -int16 OSystem_IPHONE::getHeight() { - return _screenHeight; -} - -int16 OSystem_IPHONE::getWidth() { - return _screenWidth; -} - -void OSystem_IPHONE::setPalette(const byte *colors, uint start, uint num) { - assert(start + num <= 256); - const byte *b = colors; - - for (uint i = start; i < start + num; ++i) { - _gamePalette[i] = Graphics::RGBToColor<Graphics::ColorMasks<565> >(b[0], b[1], b[2]); - _gamePaletteRGBA5551[i] = Graphics::RGBToColor<Graphics::ColorMasks<5551> >(b[0], b[1], b[2]); - b += 3; - } - - dirtyFullScreen(); -} - -void OSystem_IPHONE::grabPalette(byte *colors, uint start, uint num) { - assert(start + num <= 256); - byte *b = colors; - - for (uint i = start; i < start + num; ++i) { - Graphics::colorToRGB<Graphics::ColorMasks<565> >(_gamePalette[i], b[0], b[1], b[2]); - b += 3; - } -} - -void OSystem_IPHONE::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { - //printf("copyRectToScreen(%i, %i, %i, %i)\n", x, y, w, h); - //Clip the coordinates - if (x < 0) { - w += x; - buf -= x; - x = 0; - } - - if (y < 0) { - h += y; - buf -= y * pitch; - y = 0; - } - - if (w > _screenWidth - x) { - w = _screenWidth - x; - } - - if (h > _screenHeight - y) { - h = _screenHeight - y; - } - - if (w <= 0 || h <= 0) - return; - - if (!_fullScreenIsDirty) { - _dirtyRects.push_back(Common::Rect(x, y, x + w, y + h)); - } - - - byte *dst = _gameScreenRaw + y * _screenWidth + x; - if (_screenWidth == pitch && pitch == w) - memcpy(dst, buf, h * w); - else { - do { - memcpy(dst, buf, w); - buf += pitch; - dst += _screenWidth; - } while (--h); - } -} - -void OSystem_IPHONE::updateScreen() { - //printf("updateScreen(): %i dirty rects.\n", _dirtyRects.size()); - - if (_dirtyRects.size() == 0 && _dirtyOverlayRects.size() == 0 && !_mouseDirty) - return; - - internUpdateScreen(); - _mouseDirty = false; - _fullScreenIsDirty = false; - _fullScreenOverlayIsDirty = false; - - iPhone_updateScreen(_mouseX, _mouseY); -} - -void OSystem_IPHONE::internUpdateScreen() { - if (_mouseNeedTextureUpdate) { - updateMouseTexture(); - _mouseNeedTextureUpdate = false; - } - - while (_dirtyRects.size()) { - Common::Rect dirtyRect = _dirtyRects.remove_at(_dirtyRects.size() - 1); - - //printf("Drawing: (%i, %i) -> (%i, %i)\n", dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom); - drawDirtyRect(dirtyRect); - updateHardwareSurfaceForRect(dirtyRect); - } - - if (_overlayVisible) { - while (_dirtyOverlayRects.size()) { - Common::Rect dirtyRect = _dirtyOverlayRects.remove_at(_dirtyOverlayRects.size() - 1); - - //printf("Drawing: (%i, %i) -> (%i, %i)\n", dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom); - drawDirtyOverlayRect(dirtyRect); - } - } -} - -void OSystem_IPHONE::drawDirtyRect(const Common::Rect &dirtyRect) { - int h = dirtyRect.bottom - dirtyRect.top; - int w = dirtyRect.right - dirtyRect.left; - - byte *src = &_gameScreenRaw[dirtyRect.top * _screenWidth + dirtyRect.left]; - uint16 *dst = &_gameScreenConverted[dirtyRect.top * _screenWidth + dirtyRect.left]; - for (int y = h; y > 0; y--) { - for (int x = w; x > 0; x--) - *dst++ = _gamePalette[*src++]; - - dst += _screenWidth - w; - src += _screenWidth - w; - } -} - -void OSystem_IPHONE::drawDirtyOverlayRect(const Common::Rect &dirtyRect) { - iPhone_updateOverlayRect(_overlayBuffer, dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom); -} - -void OSystem_IPHONE::updateHardwareSurfaceForRect(const Common::Rect &updatedRect) { - iPhone_updateScreenRect(_gameScreenConverted, updatedRect.left, updatedRect.top, updatedRect.right, updatedRect.bottom); -} - -Graphics::Surface *OSystem_IPHONE::lockScreen() { - //printf("lockScreen()\n"); - - _framebuffer.pixels = _gameScreenRaw; - _framebuffer.w = _screenWidth; - _framebuffer.h = _screenHeight; - _framebuffer.pitch = _screenWidth; - _framebuffer.format = Graphics::PixelFormat::createFormatCLUT8(); - - return &_framebuffer; -} - -void OSystem_IPHONE::unlockScreen() { - //printf("unlockScreen()\n"); - dirtyFullScreen(); -} - -void OSystem_IPHONE::setShakePos(int shakeOffset) { - //printf("setShakePos(%i)\n", shakeOffset); - iPhone_setShakeOffset(shakeOffset); - // HACK: We use this to force a redraw. - _mouseDirty = true; -} - -void OSystem_IPHONE::showOverlay() { - //printf("showOverlay()\n"); - _overlayVisible = true; - dirtyFullOverlayScreen(); - updateScreen(); - iPhone_enableOverlay(true); -} - -void OSystem_IPHONE::hideOverlay() { - //printf("hideOverlay()\n"); - _overlayVisible = false; - _dirtyOverlayRects.clear(); - dirtyFullScreen(); - iPhone_enableOverlay(false); -} - -void OSystem_IPHONE::clearOverlay() { - //printf("clearOverlay()\n"); - bzero(_overlayBuffer, _overlayWidth * _overlayHeight * sizeof(OverlayColor)); - dirtyFullOverlayScreen(); -} - -void OSystem_IPHONE::grabOverlay(OverlayColor *buf, int pitch) { - //printf("grabOverlay()\n"); - int h = _overlayHeight; - OverlayColor *src = _overlayBuffer; - - do { - memcpy(buf, src, _overlayWidth * sizeof(OverlayColor)); - src += _overlayWidth; - buf += pitch; - } while (--h); -} - -void OSystem_IPHONE::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) { - //printf("copyRectToOverlay(buf, pitch=%i, x=%i, y=%i, w=%i, h=%i)\n", pitch, x, y, w, h); - - //Clip the coordinates - if (x < 0) { - w += x; - buf -= x; - x = 0; - } - - if (y < 0) { - h += y; - buf -= y * pitch; - y = 0; - } - - if (w > _overlayWidth - x) - w = _overlayWidth - x; - - if (h > _overlayHeight - y) - h = _overlayHeight - y; - - if (w <= 0 || h <= 0) - return; - - if (!_fullScreenOverlayIsDirty) { - _dirtyOverlayRects.push_back(Common::Rect(x, y, x + w, y + h)); - } - - OverlayColor *dst = _overlayBuffer + (y * _overlayWidth + x); - if (_overlayWidth == pitch && pitch == w) - memcpy(dst, buf, h * w * sizeof(OverlayColor)); - else { - do { - memcpy(dst, buf, w * sizeof(OverlayColor)); - buf += pitch; - dst += _overlayWidth; - } while (--h); - } -} - -int16 OSystem_IPHONE::getOverlayHeight() { - return _overlayHeight; -} - -int16 OSystem_IPHONE::getOverlayWidth() { - return _overlayWidth; -} - -bool OSystem_IPHONE::showMouse(bool visible) { - bool last = _mouseVisible; - _mouseVisible = visible; - iPhone_showCursor(visible); - _mouseDirty = true; - - return last; -} - -void OSystem_IPHONE::warpMouse(int x, int y) { - //printf("warpMouse()\n"); - - _mouseX = x; - _mouseY = y; - _mouseDirty = true; -} - -void OSystem_IPHONE::dirtyFullScreen() { - if (!_fullScreenIsDirty) { - _dirtyRects.clear(); - _dirtyRects.push_back(Common::Rect(0, 0, _screenWidth, _screenHeight)); - _fullScreenIsDirty = true; - } -} - -void OSystem_IPHONE::dirtyFullOverlayScreen() { - if (!_fullScreenOverlayIsDirty) { - _dirtyOverlayRects.clear(); - _dirtyOverlayRects.push_back(Common::Rect(0, 0, _overlayWidth, _overlayHeight)); - _fullScreenOverlayIsDirty = true; - } -} - -void OSystem_IPHONE::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) { - //printf("setMouseCursor(%i, %i, scale %u)\n", hotspotX, hotspotY, cursorTargetScale); - - if (_mouseBuf != NULL && (_mouseWidth != w || _mouseHeight != h)) { - free(_mouseBuf); - _mouseBuf = NULL; - } - - if (_mouseBuf == NULL) - _mouseBuf = (byte *)malloc(w * h); - - _mouseWidth = w; - _mouseHeight = h; - - _mouseHotspotX = hotspotX; - _mouseHotspotY = hotspotY; - - _mouseKeyColor = (byte)keycolor; - - memcpy(_mouseBuf, buf, w * h); - - _mouseDirty = true; - _mouseNeedTextureUpdate = true; -} - -void OSystem_IPHONE::setCursorPalette(const byte *colors, uint start, uint num) { - assert(start + num <= 256); - - for (uint i = start; i < start + num; ++i, colors += 3) - _mouseCursorPalette[i] = Graphics::RGBToColor<Graphics::ColorMasks<5551> >(colors[0], colors[1], colors[2]); - - // FIXME: This is just stupid, our client code seems to assume that this - // automatically enables the cursor palette. - _mouseCursorPaletteEnabled = true; - - if (_mouseCursorPaletteEnabled) - _mouseDirty = _mouseNeedTextureUpdate = true; -} - -void OSystem_IPHONE::updateMouseTexture() { - int texWidth = getSizeNextPOT(_mouseWidth); - int texHeight = getSizeNextPOT(_mouseHeight); - int bufferSize = texWidth * texHeight * sizeof(int16); - uint16 *mouseBuf = (uint16 *)malloc(bufferSize); - memset(mouseBuf, 0, bufferSize); - - const uint16 *palette; - if (_mouseCursorPaletteEnabled) - palette = _mouseCursorPalette; - else - palette = _gamePaletteRGBA5551; - - for (uint x = 0; x < _mouseWidth; ++x) { - for (uint y = 0; y < _mouseHeight; ++y) { - const byte color = _mouseBuf[y * _mouseWidth + x]; - if (color != _mouseKeyColor) - mouseBuf[y * texWidth + x] = palette[color] | 0x1; - else - mouseBuf[y * texWidth + x] = 0x0; - } - } - - iPhone_setMouseCursor(mouseBuf, _mouseWidth, _mouseHeight, _mouseHotspotX, _mouseHotspotY); -} diff --git a/backends/platform/iphone/osys_video.mm b/backends/platform/iphone/osys_video.mm new file mode 100644 index 0000000000..2b5e78bd35 --- /dev/null +++ b/backends/platform/iphone/osys_video.mm @@ -0,0 +1,485 @@ +/* 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. + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "osys_main.h" +#include "iphone_video.h" + +#include "graphics/conversion.h" + +void OSystem_IPHONE::initVideoContext() { + _videoContext = [g_iPhoneViewInstance getVideoContext]; +} + +const OSystem::GraphicsMode *OSystem_IPHONE::getSupportedGraphicsModes() const { + return s_supportedGraphicsModes; +} + +int OSystem_IPHONE::getDefaultGraphicsMode() const { + return kGraphicsModeLinear; +} + +bool OSystem_IPHONE::setGraphicsMode(int mode) { + switch (mode) { + case kGraphicsModeNone: + case kGraphicsModeLinear: + _videoContext->graphicsMode = (GraphicsModes)mode; + return true; + + default: + return false; + } +} + +int OSystem_IPHONE::getGraphicsMode() const { + return _videoContext->graphicsMode; +} + +#ifdef USE_RGB_COLOR +Common::List<Graphics::PixelFormat> OSystem_IPHONE::getSupportedFormats() const { + Common::List<Graphics::PixelFormat> list; + // RGB565 + list.push_back(Graphics::createPixelFormat<565>()); + // CLUT8 + list.push_back(Graphics::PixelFormat::createFormatCLUT8()); + return list; +} +#endif + +void OSystem_IPHONE::initSize(uint width, uint height, const Graphics::PixelFormat *format) { + //printf("initSize(%u, %u, %p)\n", width, height, (const void *)format); + + _videoContext->screenWidth = width; + _videoContext->screenHeight = height; + _videoContext->shakeOffsetY = 0; + + // In case we use the screen texture as frame buffer we reset the pixels + // pointer here to avoid freeing the screen texture. + if (_framebuffer.pixels == _videoContext->screenTexture.pixels) + _framebuffer.pixels = 0; + + // Create the screen texture right here. We need to do this here, since + // when a game requests hi-color mode, we actually set the framebuffer + // to the texture buffer to avoid an additional copy step. + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(createScreenTexture) withObject:nil waitUntilDone: YES]; + + if (!format || format->bytesPerPixel == 1) { + _framebuffer.create(width, height, Graphics::PixelFormat::createFormatCLUT8()); + } else { +#if 0 + printf("bytesPerPixel: %u RGBAlosses: %u,%u,%u,%u RGBAshifts: %u,%u,%u,%u\n", format->bytesPerPixel, + format->rLoss, format->gLoss, format->bLoss, format->aLoss, + format->rShift, format->gShift, format->bShift, format->aShift); +#endif + assert(_videoContext->screenTexture.format == *format); + // We directly draw on the screen texture in hi-color mode. Thus + // we copy over its settings here and just replace the width and + // height to avoid any problems. + _framebuffer = _videoContext->screenTexture; + _framebuffer.w = width; + _framebuffer.h = height; + } + + _fullScreenIsDirty = false; + dirtyFullScreen(); + _mouseCursorPaletteEnabled = false; +} + +void OSystem_IPHONE::beginGFXTransaction() { +} + +OSystem::TransactionError OSystem_IPHONE::endGFXTransaction() { + _screenChangeCount++; + updateOutputSurface(); + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(setGraphicsMode) withObject:nil waitUntilDone: YES]; + + // TODO: Can we return better error codes? + return kTransactionSuccess; +} + +void OSystem_IPHONE::updateOutputSurface() { + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(initSurface) withObject:nil waitUntilDone: YES]; +} + +int16 OSystem_IPHONE::getHeight() { + return _videoContext->screenHeight; +} + +int16 OSystem_IPHONE::getWidth() { + return _videoContext->screenWidth; +} + +void OSystem_IPHONE::setPalette(const byte *colors, uint start, uint num) { + assert(start + num <= 256); + const byte *b = colors; + + for (uint i = start; i < start + num; ++i) { + _gamePalette[i] = Graphics::RGBToColor<Graphics::ColorMasks<565> >(b[0], b[1], b[2]); + _gamePaletteRGBA5551[i] = Graphics::RGBToColor<Graphics::ColorMasks<5551> >(b[0], b[1], b[2]); + b += 3; + } + + dirtyFullScreen(); +} + +void OSystem_IPHONE::grabPalette(byte *colors, uint start, uint num) { + assert(start + num <= 256); + byte *b = colors; + + for (uint i = start; i < start + num; ++i) { + Graphics::colorToRGB<Graphics::ColorMasks<565> >(_gamePalette[i], b[0], b[1], b[2]); + b += 3; + } +} + +void OSystem_IPHONE::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { + //printf("copyRectToScreen(%i, %i, %i, %i)\n", x, y, w, h); + //Clip the coordinates + if (x < 0) { + w += x; + buf -= x; + x = 0; + } + + if (y < 0) { + h += y; + buf -= y * pitch; + y = 0; + } + + if (w > (int)_framebuffer.w - x) { + w = _framebuffer.w - x; + } + + if (h > (int)_framebuffer.h - y) { + h = _framebuffer.h - y; + } + + if (w <= 0 || h <= 0) + return; + + if (!_fullScreenIsDirty) { + _dirtyRects.push_back(Common::Rect(x, y, x + w, y + h)); + } + + byte *dst = (byte *)_framebuffer.getBasePtr(x, y); + if (_framebuffer.pitch == pitch && _framebuffer.w == w) { + memcpy(dst, buf, h * pitch); + } else { + do { + memcpy(dst, buf, w * _framebuffer.format.bytesPerPixel); + buf += pitch; + dst += _framebuffer.pitch; + } while (--h); + } +} + +void OSystem_IPHONE::updateScreen() { + //printf("updateScreen(): %i dirty rects.\n", _dirtyRects.size()); + + if (_dirtyRects.size() == 0 && _dirtyOverlayRects.size() == 0 && !_mouseDirty) + return; + + internUpdateScreen(); + _mouseDirty = false; + _fullScreenIsDirty = false; + _fullScreenOverlayIsDirty = false; + + iPhone_updateScreen(); +} + +void OSystem_IPHONE::internUpdateScreen() { + if (_mouseNeedTextureUpdate) { + updateMouseTexture(); + _mouseNeedTextureUpdate = false; + } + + while (_dirtyRects.size()) { + Common::Rect dirtyRect = _dirtyRects.remove_at(_dirtyRects.size() - 1); + + //printf("Drawing: (%i, %i) -> (%i, %i)\n", dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom); + drawDirtyRect(dirtyRect); + // TODO: Implement dirty rect code + //updateHardwareSurfaceForRect(dirtyRect); + } + + if (_videoContext->overlayVisible) { + // TODO: Implement dirty rect code + _dirtyOverlayRects.clear(); + /*while (_dirtyOverlayRects.size()) { + Common::Rect dirtyRect = _dirtyOverlayRects.remove_at(_dirtyOverlayRects.size() - 1); + + //printf("Drawing: (%i, %i) -> (%i, %i)\n", dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom); + drawDirtyOverlayRect(dirtyRect); + }*/ + } +} + +void OSystem_IPHONE::drawDirtyRect(const Common::Rect &dirtyRect) { + // We only need to do a color look up for CLUT8 + if (_framebuffer.format.bytesPerPixel != 1) + return; + + int h = dirtyRect.bottom - dirtyRect.top; + int w = dirtyRect.right - dirtyRect.left; + + const byte *src = (const byte *)_framebuffer.getBasePtr(dirtyRect.left, dirtyRect.top); + byte *dstRaw = (byte *)_videoContext->screenTexture.getBasePtr(dirtyRect.left, dirtyRect.top); + + // When we use CLUT8 do a color look up + for (int y = h; y > 0; y--) { + uint16 *dst = (uint16 *)dstRaw; + for (int x = w; x > 0; x--) + *dst++ = _gamePalette[*src++]; + + dstRaw += _videoContext->screenTexture.pitch; + src += _framebuffer.pitch - w; + } +} + +Graphics::Surface *OSystem_IPHONE::lockScreen() { + //printf("lockScreen()\n"); + return &_framebuffer; +} + +void OSystem_IPHONE::unlockScreen() { + //printf("unlockScreen()\n"); + dirtyFullScreen(); +} + +void OSystem_IPHONE::setShakePos(int shakeOffset) { + //printf("setShakePos(%i)\n", shakeOffset); + _videoContext->shakeOffsetY = shakeOffset; + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(setViewTransformation) withObject:nil waitUntilDone: YES]; + // HACK: We use this to force a redraw. + _mouseDirty = true; +} + +void OSystem_IPHONE::showOverlay() { + //printf("showOverlay()\n"); + _videoContext->overlayVisible = true; + dirtyFullOverlayScreen(); + updateScreen(); + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateMouseCursorScaling) withObject:nil waitUntilDone: YES]; + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(clearColorBuffer) withObject:nil waitUntilDone: YES]; +} + +void OSystem_IPHONE::hideOverlay() { + //printf("hideOverlay()\n"); + _videoContext->overlayVisible = false; + _dirtyOverlayRects.clear(); + dirtyFullScreen(); + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateMouseCursorScaling) withObject:nil waitUntilDone: YES]; + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(clearColorBuffer) withObject:nil waitUntilDone: YES]; +} + +void OSystem_IPHONE::clearOverlay() { + //printf("clearOverlay()\n"); + bzero(_videoContext->overlayTexture.getBasePtr(0, 0), _videoContext->overlayTexture.h * _videoContext->overlayTexture.pitch); + dirtyFullOverlayScreen(); +} + +void OSystem_IPHONE::grabOverlay(OverlayColor *buf, int pitch) { + //printf("grabOverlay()\n"); + int h = _videoContext->overlayHeight; + + const byte *src = (const byte *)_videoContext->overlayTexture.getBasePtr(0, 0); + do { + memcpy(buf, src, _videoContext->overlayWidth * sizeof(OverlayColor)); + src += _videoContext->overlayTexture.pitch; + buf += pitch; + } while (--h); +} + +void OSystem_IPHONE::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) { + //printf("copyRectToOverlay(buf, pitch=%i, x=%i, y=%i, w=%i, h=%i)\n", pitch, x, y, w, h); + + //Clip the coordinates + if (x < 0) { + w += x; + buf -= x; + x = 0; + } + + if (y < 0) { + h += y; + buf -= y * pitch; + y = 0; + } + + if (w > (int)_videoContext->overlayWidth - x) + w = _videoContext->overlayWidth - x; + + if (h > (int)_videoContext->overlayHeight - y) + h = _videoContext->overlayHeight - y; + + if (w <= 0 || h <= 0) + return; + + if (!_fullScreenOverlayIsDirty) { + _dirtyOverlayRects.push_back(Common::Rect(x, y, x + w, y + h)); + } + + byte *dst = (byte *)_videoContext->overlayTexture.getBasePtr(x, y); + do { + memcpy(dst, buf, w * sizeof(OverlayColor)); + buf += pitch; + dst += _videoContext->overlayTexture.pitch; + } while (--h); +} + +int16 OSystem_IPHONE::getOverlayHeight() { + return _videoContext->overlayHeight; +} + +int16 OSystem_IPHONE::getOverlayWidth() { + return _videoContext->overlayWidth; +} + +bool OSystem_IPHONE::showMouse(bool visible) { + bool last = _videoContext->mouseIsVisible; + _videoContext->mouseIsVisible = visible; + _mouseDirty = true; + + return last; +} + +void OSystem_IPHONE::warpMouse(int x, int y) { + //printf("warpMouse()\n"); + _videoContext->mouseX = x; + _videoContext->mouseY = y; + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(notifyMouseMove) withObject:nil waitUntilDone: YES]; + _mouseDirty = true; +} + +void OSystem_IPHONE::dirtyFullScreen() { + if (!_fullScreenIsDirty) { + _dirtyRects.clear(); + _dirtyRects.push_back(Common::Rect(0, 0, _videoContext->screenWidth, _videoContext->screenHeight)); + _fullScreenIsDirty = true; + } +} + +void OSystem_IPHONE::dirtyFullOverlayScreen() { + if (!_fullScreenOverlayIsDirty) { + _dirtyOverlayRects.clear(); + _dirtyOverlayRects.push_back(Common::Rect(0, 0, _videoContext->overlayWidth, _videoContext->overlayHeight)); + _fullScreenOverlayIsDirty = true; + } +} + +void OSystem_IPHONE::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) { + //printf("setMouseCursor(%i, %i, scale %u)\n", hotspotX, hotspotY, cursorTargetScale); + + const Graphics::PixelFormat pixelFormat = format ? *format : Graphics::PixelFormat::createFormatCLUT8(); +#if 0 + printf("bytesPerPixel: %u RGBAlosses: %u,%u,%u,%u RGBAshifts: %u,%u,%u,%u\n", pixelFormat.bytesPerPixel, + pixelFormat.rLoss, pixelFormat.gLoss, pixelFormat.bLoss, pixelFormat.aLoss, + pixelFormat.rShift, pixelFormat.gShift, pixelFormat.bShift, pixelFormat.aShift); +#endif + assert(pixelFormat.bytesPerPixel == 1 || pixelFormat.bytesPerPixel == 2); + + if (_mouseBuffer.w != w || _mouseBuffer.h != h || _mouseBuffer.format != pixelFormat || !_mouseBuffer.pixels) + _mouseBuffer.create(w, h, pixelFormat); + + _videoContext->mouseWidth = w; + _videoContext->mouseHeight = h; + + _videoContext->mouseHotspotX = hotspotX; + _videoContext->mouseHotspotY = hotspotY; + + _mouseKeyColor = keycolor; + + memcpy(_mouseBuffer.getBasePtr(0, 0), buf, h * _mouseBuffer.pitch); + + _mouseDirty = true; + _mouseNeedTextureUpdate = true; +} + +void OSystem_IPHONE::setCursorPalette(const byte *colors, uint start, uint num) { + assert(start + num <= 256); + + for (uint i = start; i < start + num; ++i, colors += 3) + _mouseCursorPalette[i] = Graphics::RGBToColor<Graphics::ColorMasks<5551> >(colors[0], colors[1], colors[2]); + + // FIXME: This is just stupid, our client code seems to assume that this + // automatically enables the cursor palette. + _mouseCursorPaletteEnabled = true; + + if (_mouseCursorPaletteEnabled) + _mouseDirty = _mouseNeedTextureUpdate = true; +} + +void OSystem_IPHONE::updateMouseTexture() { + uint texWidth = getSizeNextPOT(_videoContext->mouseWidth); + uint texHeight = getSizeNextPOT(_videoContext->mouseHeight); + + Graphics::Surface &mouseTexture = _videoContext->mouseTexture; + if (mouseTexture.w != texWidth || mouseTexture.h != texHeight) + mouseTexture.create(texWidth, texHeight, Graphics::createPixelFormat<5551>()); + + if (_mouseBuffer.format.bytesPerPixel == 1) { + const uint16 *palette; + if (_mouseCursorPaletteEnabled) + palette = _mouseCursorPalette; + else + palette = _gamePaletteRGBA5551; + + uint16 *mouseBuf = (uint16 *)mouseTexture.getBasePtr(0, 0); + for (uint x = 0; x < _videoContext->mouseWidth; ++x) { + for (uint y = 0; y < _videoContext->mouseHeight; ++y) { + const byte color = *(const byte *)_mouseBuffer.getBasePtr(x, y); + if (color != _mouseKeyColor) + mouseBuf[y * texWidth + x] = palette[color] | 0x1; + else + mouseBuf[y * texWidth + x] = 0x0; + } + } + } else { + if (crossBlit((byte *)mouseTexture.getBasePtr(0, 0), (const byte *)_mouseBuffer.getBasePtr(0, 0), mouseTexture.pitch, + _mouseBuffer.pitch, _mouseBuffer.w, _mouseBuffer.h, mouseTexture.format, _mouseBuffer.format)) { + if (!_mouseBuffer.format.aBits()) { + // Apply color keying since the original cursor had no alpha channel. + const uint16 *src = (const uint16 *)_mouseBuffer.getBasePtr(0, 0); + uint8 *dstRaw = (uint8 *)mouseTexture.getBasePtr(0, 0); + + for (uint y = 0; y < _mouseBuffer.h; ++y, dstRaw += mouseTexture.pitch) { + uint16 *dst = (uint16 *)dstRaw; + for (uint x = 0; x < _mouseBuffer.w; ++x, ++dst) { + if (*src++ == _mouseKeyColor) + *dst &= ~1; + else + *dst |= 1; + } + } + } + } else { + // TODO: Log this! + // Make the cursor all transparent... we really need a better fallback ;-). + memset(mouseTexture.getBasePtr(0, 0), 0, mouseTexture.h * mouseTexture.pitch); + } + } + + [g_iPhoneViewInstance performSelectorOnMainThread:@selector(updateMouseCursor) withObject:nil waitUntilDone: YES]; +} diff --git a/backends/platform/maemo/maemo-common.h b/backends/platform/maemo/maemo-common.h index 453c70c45f..0442b9c0ae 100644 --- a/backends/platform/maemo/maemo-common.h +++ b/backends/platform/maemo/maemo-common.h @@ -43,15 +43,6 @@ struct Model { bool hasMenuKey; }; -static const Model models[] = { - {"SU-18", kModelType770, "770", false, true}, - {"RX-34", kModelTypeN800, "N800", false, true}, - {"RX-44", kModelTypeN810, "N810", true, true}, - {"RX-48", kModelTypeN810, "N810W", true, true}, - {"RX-51", kModelTypeN900, "N900", true, false}, - {0, kModelTypeInvalid, 0, true, true} -}; - enum CustomEventType { kEventClickMode = 1, kEventInvalid = 0 diff --git a/backends/platform/maemo/maemo.cpp b/backends/platform/maemo/maemo.cpp index 209e527e3f..a127926eb0 100644 --- a/backends/platform/maemo/maemo.cpp +++ b/backends/platform/maemo/maemo.cpp @@ -156,10 +156,19 @@ void OSystem_SDL_Maemo::setWindowCaption(const char *caption) { setXWindowName(cap.c_str()); } +static const Model models[] = { + {"SU-18", kModelType770, "770", false, true}, + {"RX-34", kModelTypeN800, "N800", false, true}, + {"RX-44", kModelTypeN810, "N810", true, true}, + {"RX-48", kModelTypeN810, "N810W", true, true}, + {"RX-51", kModelTypeN900, "N900", true, false}, + {0, kModelTypeInvalid, 0, true, true} +}; + const Maemo::Model OSystem_SDL_Maemo::detectModel() { Common::String deviceHwId = Common::String(getenv("SCUMMVM_MAEMO_DEVICE")); const Model *model; - for (model = models; model->hwId; model++) { + for (model = models; model->hwId; ++model) { if (deviceHwId.equals(model->hwId)) return *model; } |