From 80b34398174973b6d70673fce94a8a1f670c3f4d Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Tue, 21 Feb 2012 18:51:16 +0100 Subject: [PATCH] IPHONE: Rewrite video screen rotation. Now it should be a little bit more sane. Formerly the width and height was swapped in rotation mode, which resulted in the x coordinate falling into the range 0..height in landscape mode for example. This also fixes the cursor offset in the modern theme. --- backends/platform/iphone/iphone_video.h | 7 - backends/platform/iphone/iphone_video.m | 248 ++++++++++++++---------- 2 files changed, 141 insertions(+), 114 deletions(-) diff --git a/backends/platform/iphone/iphone_video.h b/backends/platform/iphone/iphone_video.h index 02b9c8692dde..f2253f3e2172 100644 --- a/backends/platform/iphone/iphone_video.h +++ b/backends/platform/iphone/iphone_video.h @@ -38,16 +38,9 @@ NSMutableArray *_events; SoftKeyboard *_keyboardView; - int _widthOffset; - int _heightOffset; - EAGLContext *_context; GLuint _viewRenderbuffer; GLuint _viewFramebuffer; - GLint _renderBufferWidth; - GLint _renderBufferHeight; - GLint _visibleWidth; - GLint _visibleHeight; GLuint _screenTexture; GLuint _overlayTexture; GLuint _mouseCursorTexture; diff --git a/backends/platform/iphone/iphone_video.m b/backends/platform/iphone/iphone_video.m index f7b8edd7b9bd..5cd9534611a8 100644 --- a/backends/platform/iphone/iphone_video.m +++ b/backends/platform/iphone/iphone_video.m @@ -57,6 +57,9 @@ static int _mouseY = 0; static int _mouseCursorEnabled = 0; +static GLint _renderBufferWidth; +static GLint _renderBufferHeight; + #if 0 static long lastTick = 0; static int frames = 0; @@ -186,57 +189,64 @@ uint getSizeNextPOT(uint size) { return [documentsDirectory UTF8String]; } -static bool getMouseCoords(UIDeviceOrientation orientation, CGPoint point, int *x, int *y) { - if (_overlayIsEnabled) { - switch (orientation) { - case UIDeviceOrientationLandscapeLeft: - *x = (int)point.y; - *y = _overlayHeight - (int)point.x; - break; - - case UIDeviceOrientationLandscapeRight: - *x = _overlayWidth - (int)point.y; - *y = (int)point.x; - break; - - case UIDeviceOrientationPortrait: - *x = (int)point.x; - *y = (int)point.y; - break; - - default: - return false; - } - } else { - if (point.x < _gameScreenRect.origin.x || point.x >= _gameScreenRect.origin.x + _gameScreenRect.size.width || - point.y < _gameScreenRect.origin.y || point.y >= _gameScreenRect.origin.y + _gameScreenRect.size.height) { - return false; - } +/** + * 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; - point.x = (point.x - _gameScreenRect.origin.x) / _gameScreenRect.size.width; - point.y = (point.y - _gameScreenRect.origin.y) / _gameScreenRect.size.height; + case UIDeviceOrientationLandscapeRight: + result->x = _renderBufferHeight - point.y; + result->y = point.x; + return true; - switch (orientation) { - case UIDeviceOrientationLandscapeLeft: - *x = point.y * _width; - *y = (1.0f - point.x) * _height; - break; + case UIDeviceOrientationPortrait: + result->x = point.x; + result->y = point.y; + return true; + + default: + return false; + } +} + +static bool normalizeMouseCoords(CGPoint *point, CGRect area) { + if (point->x < CGRectGetMinX(area) || point->x > CGRectGetMaxX(area) || + point->y < CGRectGetMinY(area) || point->y > CGRectGetMaxY(area)) { + return false; + } + + point->x = (point->x - CGRectGetMinX(area)) / CGRectGetWidth(area); + point->y = (point->y - CGRectGetMinY(area)) / CGRectGetHeight(area); + return true; +} - case UIDeviceOrientationLandscapeRight: - *x = (1.0f - point.y) * _width; - *y = point.x * _height; - break; +static bool getMouseCoords(UIDeviceOrientation orientation, CGPoint point, int *x, int *y) { + if (!convertToRotatedCoords(orientation, point, &point)) + return false; - case UIDeviceOrientationPortrait: - *x = point.x * _width; - *y = point.y * _height; - break; + int width, height; + if (_overlayIsEnabled) { + if (!normalizeMouseCoords(&point, _overlayRect)) + return false; - default: + width = _overlayWidth; + height = _overlayHeight; + } else { + if (!normalizeMouseCoords(&point, _gameScreenRect)) return false; - } + + width = _width; + height = _height; } + *x = point.x * width; + *y = point.y * height; + return true; } @@ -311,7 +321,7 @@ - (void)createContext { // 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[0] = _overlayTexCoords[4] = _overlayWidth / (GLfloat)_overlayTexWidth; + _overlayTexCoords[2] = _overlayTexCoords[6] = _overlayWidth / (GLfloat)_overlayTexWidth; _overlayTexCoords[5] = _overlayTexCoords[7] = _overlayHeight / (GLfloat)_overlayTexHeight; int textureSize = _overlayTexWidth * _overlayTexHeight * 2; @@ -477,32 +487,43 @@ - (void)updateMouseSurface { int hotspotX = _mouseCursorHotspotX; int hotspotY = _mouseCursorHotspotY; + CGRect *rect; + int maxWidth, maxHeight; + if (!_overlayIsEnabled) { - const GLint gameWidth = (_visibleHeight - 2 * _widthOffset); - const GLint gameHeight = (_visibleWidth - 2 * _heightOffset); - - mouseX = (_width - mouseX) / (float)_width * gameHeight + _heightOffset; - mouseY = mouseY / (float)_height * gameWidth + _widthOffset; - hotspotX = hotspotX / (float)_width * gameHeight; - hotspotY = hotspotY / (float)_height * gameWidth; - width = width / (float)_width * gameHeight; - height = height / (float)_height * gameWidth; + rect = &_gameScreenRect; + maxWidth = _width; + maxHeight = _height; } else { - mouseX = (_overlayWidth - mouseX) / (float)_overlayWidth * _renderBufferWidth; - mouseY = mouseY / (float)_overlayHeight * _renderBufferHeight; - hotspotX = hotspotX / (float)_overlayWidth * _renderBufferWidth; - hotspotY = hotspotY / (float)_overlayHeight * _renderBufferHeight; - width = width / (float)_overlayWidth * _renderBufferWidth; - height = height / (float)_overlayHeight * _renderBufferHeight; + rect = &_overlayRect; + maxWidth = _overlayWidth; + maxHeight = _overlayHeight; } + const GLfloat scaleX = CGRectGetWidth(*rect) / (GLfloat)maxWidth; + const GLfloat scaleY = CGRectGetHeight(*rect) / (GLfloat)maxHeight; + + mouseX = mouseX * scaleX; + mouseY = mouseY * scaleY; + hotspotX = hotspotX * scaleX; + hotspotY = hotspotY * scaleY; + width = width * scaleX; + height = height * scaleY; + mouseX -= hotspotX; mouseY -= hotspotY; + mouseX += CGRectGetMinX(*rect); + mouseY += CGRectGetMinY(*rect); + GLfloat vertices[] = { + // Top left mouseX , mouseY, + // Top right mouseX + width, mouseY, + // Bottom left mouseX , mouseY + height, + // Bottom right mouseX + width, mouseY + height }; @@ -512,10 +533,14 @@ - (void)updateMouseSurface { float texHeight = _mouseCursorHeight / (float)getSizeNextPOT(_mouseCursorHeight); const GLfloat texCoords[] = { - texWidth, 0.0f, - 0.0f, 0.0f, - texWidth, texHeight, - 0.0f, texHeight + // Top left + 0 , 0, + // Top right + texWidth, 0, + // Bottom left + 0 , texHeight, + // Bottom right + texWidth, texHeight }; glVertexPointer(2, GL_FLOAT, 0, vertices); printOpenGLError(); @@ -529,7 +554,7 @@ - (void)initSurface { _gameScreenTextureWidth = getSizeNextPOT(_width); _gameScreenTextureHeight = getSizeNextPOT(_height); - _gameScreenTexCoords[0] = _gameScreenTexCoords[4] = _width / (GLfloat)_gameScreenTextureWidth; + _gameScreenTexCoords[2] = _gameScreenTexCoords[6] = _width / (GLfloat)_gameScreenTextureWidth; _gameScreenTexCoords[5] = _gameScreenTexCoords[7] = _height / (GLfloat)_gameScreenTextureHeight; _orientation = [[UIDevice currentDevice] orientation]; @@ -549,15 +574,27 @@ - (void)initSurface { glMatrixMode(GL_PROJECTION); glLoadIdentity(); + int screenWidth, screenHeight; + + // Set the origin (0,0) depending on the rotation mode. if (_orientation == UIDeviceOrientationLandscapeRight) { - glRotatef(-90, 0, 0, 1); printOpenGLError(); + glRotatef( 90, 0, 0, 1); printOpenGLError(); + glOrthof(0, _renderBufferHeight, _renderBufferWidth, 0, 0, 1); printOpenGLError(); + + screenWidth = _renderBufferHeight; + screenHeight = _renderBufferWidth; } else if (_orientation == UIDeviceOrientationLandscapeLeft) { - glRotatef(90, 0, 0, 1); printOpenGLError(); - } else { - glRotatef(180, 0, 0, 1); printOpenGLError(); - } + glRotatef(-90, 0, 0, 1); printOpenGLError(); + glOrthof(0, _renderBufferHeight, _renderBufferWidth, 0, 0, 1); printOpenGLError(); - glOrthof(0, _renderBufferWidth, 0, _renderBufferHeight, 0, 1); printOpenGLError(); + screenWidth = _renderBufferHeight; + screenHeight = _renderBufferWidth; + } else if (_orientation == UIDeviceOrientationPortrait) { + glOrthof(0, _renderBufferWidth, _renderBufferHeight, 0, 0, 1); printOpenGLError(); + + screenWidth = _renderBufferWidth; + screenHeight = _renderBufferHeight; + } if (_screenTexture > 0) { glDeleteTextures(1, &_screenTexture); printOpenGLError(); @@ -590,36 +627,39 @@ - (void)initSurface { float overlayPortraitRatio; if (_orientation == UIDeviceOrientationLandscapeLeft || _orientation == UIDeviceOrientationLandscapeRight) { - _visibleHeight = _renderBufferHeight; - _visibleWidth = _renderBufferWidth; + GLfloat gameScreenRatio = (GLfloat)_width / (GLfloat)_height; + GLfloat screenRatio = (GLfloat)screenWidth / (GLfloat)screenHeight; - float ratioDifference = ((float)_height / (float)_width) / ((float)_renderBufferWidth / (float)_renderBufferHeight); + // These are the width/height according to the portrait layout! int rectWidth, rectHeight; - if (ratioDifference < 1.0f) { - rectWidth = _renderBufferWidth * ratioDifference; - rectHeight = _renderBufferHeight; - _widthOffset = (_renderBufferWidth - rectWidth) / 2; - _heightOffset = 0; + int xOffset, yOffset; + + if (gameScreenRatio < screenRatio) { + // When the game screen ratio is less than the screen ratio + // we need to scale the width, since the game screen was higher + // compared to the width than our output screen is. + rectWidth = screenHeight * gameScreenRatio; + rectHeight = screenHeight; + xOffset = (screenWidth - rectWidth) / 2; + yOffset = 0; } else { - rectWidth = _renderBufferWidth; - rectHeight = _renderBufferHeight / ratioDifference; - _heightOffset = (_renderBufferHeight - rectHeight) / 2; - _widthOffset = 0; + // When the game screen ratio is bigger than the screen ratio + // we need to scale the height, since the game screen was wider + // compared to the height than our output screen is. + rectWidth = screenWidth; + rectHeight = screenWidth / gameScreenRatio; + xOffset = 0; + yOffset = (screenHeight - rectHeight) / 2; } - //printf("Rect: %i, %i, %i, %i\n", _widthOffset, _heightOffset, rectWidth, rectHeight); - _gameScreenRect = CGRectMake(_widthOffset, _heightOffset, rectWidth, rectHeight); + //printf("Rect: %i, %i, %i, %i\n", xOffset, yOffset, rectWidth, rectHeight); + _gameScreenRect = CGRectMake(xOffset, yOffset, rectWidth, rectHeight); overlayPortraitRatio = 1.0f; } else { float ratio = (float)_height / (float)_width; - int height = _renderBufferWidth * ratio; - //printf("Making rect (%u, %u)\n", _renderBufferWidth, height); - _gameScreenRect = CGRectMake(0, 0, _renderBufferWidth - 1, height - 1); - - _visibleHeight = height; - _visibleWidth = _renderBufferWidth; - _heightOffset = 0.0f; - _widthOffset = 0.0f; + int height = screenWidth * ratio; + //printf("Making rect (%u, %u)\n", screenWidth, height); + _gameScreenRect = CGRectMake(0, 0, screenWidth, height); CGRect keyFrame = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f); if (_keyboardView == nil) { @@ -633,21 +673,15 @@ - (void)initSurface { overlayPortraitRatio = (_overlayHeight * ratio) / _overlayWidth; } - _overlayRect = CGRectMake(0, 0, _renderBufferWidth, _renderBufferHeight * overlayPortraitRatio); - - _gameScreenVertCoords[0] = _heightOffset; - _gameScreenVertCoords[1] = _widthOffset; - _gameScreenVertCoords[2] = _visibleWidth - _heightOffset; - _gameScreenVertCoords[3] = _widthOffset; - _gameScreenVertCoords[4] = _heightOffset; - _gameScreenVertCoords[5] = _visibleHeight - _widthOffset; - _gameScreenVertCoords[6] = _visibleWidth - _heightOffset; - _gameScreenVertCoords[7] = _visibleHeight - _widthOffset; - - _overlayVertCoords[2] = _overlayHeight; - _overlayVertCoords[5] = _overlayWidth * _overlayPortraitRatio; - _overlayVertCoords[6] = _overlayHeight; - _overlayVertCoords[7] = _overlayWidth * _overlayPortraitRatio; + _overlayRect = CGRectMake(0, 0, screenWidth, screenHeight * overlayPortraitRatio); + + _gameScreenVertCoords[0] = _gameScreenVertCoords[4] = CGRectGetMinX(_gameScreenRect); + _gameScreenVertCoords[1] = _gameScreenVertCoords[3] = CGRectGetMinY(_gameScreenRect); + _gameScreenVertCoords[2] = _gameScreenVertCoords[6] = CGRectGetMaxX(_gameScreenRect); + _gameScreenVertCoords[5] = _gameScreenVertCoords[7] = CGRectGetMaxY(_gameScreenRect); + + _overlayVertCoords[2] = _overlayVertCoords[6] = CGRectGetMaxX(_overlayRect); + _overlayVertCoords[5] = _overlayVertCoords[7] = CGRectGetMaxY(_overlayRect); } - (void)clearColorBuffer {