Skip to content

Commit

Permalink
IPHONE: Rewrite video screen rotation.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Johannes Schickel committed Feb 21, 2012
1 parent f6edcbd commit 80b3439
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 114 deletions.
7 changes: 0 additions & 7 deletions backends/platform/iphone/iphone_video.h
Expand Up @@ -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;
Expand Down
248 changes: 141 additions & 107 deletions backends/platform/iphone/iphone_video.m
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
};

Expand All @@ -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();
Expand All @@ -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];
Expand All @@ -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();
Expand Down Expand Up @@ -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) {
Expand All @@ -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 {
Expand Down

0 comments on commit 80b3439

Please sign in to comment.