aboutsummaryrefslogtreecommitdiff
path: root/backends/platform/iphone/iphone_video.mm
diff options
context:
space:
mode:
authorJohannes Schickel2012-02-22 02:30:44 +0100
committerJohannes Schickel2012-02-22 02:30:44 +0100
commite79f6a631474a49b9e92d3d0c8c5f2a7dc72d123 (patch)
treebc7d05bfeeccd1d2af2bd12193ae26565a3728f5 /backends/platform/iphone/iphone_video.mm
parent1b26346fc887ce2681b3a70c6b5af030542dc3f1 (diff)
downloadscummvm-rg350-e79f6a631474a49b9e92d3d0c8c5f2a7dc72d123.tar.gz
scummvm-rg350-e79f6a631474a49b9e92d3d0c8c5f2a7dc72d123.tar.bz2
scummvm-rg350-e79f6a631474a49b9e92d3d0c8c5f2a7dc72d123.zip
IPHONE: Move ObjC code files (.m) to ObjC++ files (.mm).
Diffstat (limited to 'backends/platform/iphone/iphone_video.mm')
-rw-r--r--backends/platform/iphone/iphone_video.mm931
1 files changed, 931 insertions, 0 deletions
diff --git a/backends/platform/iphone/iphone_video.mm b/backends/platform/iphone/iphone_video.mm
new file mode 100644
index 0000000000..2dcca3592c
--- /dev/null
+++ b/backends/platform/iphone/iphone_video.mm
@@ -0,0 +1,931 @@
+/* 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.
+ *
+ */
+
+#include "iphone_video.h"
+#include "iphone_common.h"
+
+static iPhoneView *sharedInstance = nil;
+static GraphicsModes _graphicsMode = kGraphicsModeLinear;
+static int _width = 0;
+static int _height = 0;
+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;
+#endif
+
+#define printOpenGLError() printOglError(__FILE__, __LINE__)
+
+int printOglError(const char *file, int line) {
+ int retCode = 0;
+
+ // returns 1 if an OpenGL error occurred, 0 otherwise.
+ GLenum glErr = glGetError();
+ while (glErr != GL_NO_ERROR) {
+ fprintf(stderr, "glError: %u (%s: %d)\n", glErr, file, line);
+ retCode = 1;
+ glErr = glGetError();
+ }
+ 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) {
+ //printf("Mouse: (%i, %i)\n", mouseX, mouseY);
+
+ _mouseX = mouseX;
+ _mouseY = mouseY;
+
+ if (!_needsScreenUpdate) {
+ _needsScreenUpdate = 1;
+ [sharedInstance performSelectorOnMainThread:@selector(updateSurface) withObject:nil waitUntilDone: NO];
+ }
+}
+
+void iPhone_updateScreenRect(unsigned short *screen, int x1, int y1, int x2, int y2) {
+ int y;
+ for (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) {
+ int y;
+ //printf("Overlaywidth: %u, fullwidth %u\n", _overlayWidth, _fullWidth);
+ for (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];
+ if (event == nil) {
+ return false;
+ }
+
+ id type = [event objectForKey:@"type"];
+
+ if (type == nil) {
+ printf("fetchEvent says: No type!\n");
+ return false;
+ }
+
+ *outEvent = [type intValue];
+ *outX = [[event objectForKey:@"x"] intValue];
+ *outY = [[event objectForKey:@"y"] intValue];
+ return true;
+}
+
+uint getSizeNextPOT(uint size) {
+ if ((size & (size - 1)) || !size) {
+ int log = 0;
+
+ while (size >>= 1)
+ ++log;
+
+ size = (2 << log);
+ }
+
+ return size;
+}
+
+const char *iPhone_getDocumentsDir() {
+ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+ NSString *documentsDirectory = [paths objectAtIndex:0];
+ 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 = point.x * width;
+ // offsetY describes the translation of the screen in the upward direction,
+ // thus we need to add it here.
+ *y = 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];
+}
+
+- (void)createContext {
+ CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
+
+ eaglLayer.opaque = YES;
+ eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGB565, kEAGLDrawablePropertyColorFormat, nil];
+
+ _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
+
+ // In case creating the OpenGL ES context failed, we will error out here.
+ if (_context == nil) {
+ fprintf(stderr, "Could not create OpenGL ES context\n");
+ exit(-1);
+ }
+
+ if ([EAGLContext setCurrentContext:_context]) {
+ glGenFramebuffersOES(1, &_viewFramebuffer); printOpenGLError();
+ glGenRenderbuffersOES(1, &_viewRenderbuffer); printOpenGLError();
+
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer); printOpenGLError();
+ glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError();
+ [_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id<EAGLDrawable>)self.layer];
+
+ glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError();
+
+ // Retrieve the render buffer size. This *should* match the frame size,
+ // i.e. _fullWidth and _fullHeight.
+ glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &_renderBufferWidth); printOpenGLError();
+ glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &_renderBufferHeight); printOpenGLError();
+
+ if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
+ NSLog(@"Failed to make complete framebuffer object %x.", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
+ return;
+ }
+
+ _overlayHeight = _renderBufferWidth;
+ _overlayWidth = _renderBufferHeight;
+ _overlayTexWidth = getSizeNextPOT(_overlayHeight);
+ _overlayTexHeight = getSizeNextPOT(_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;
+
+ int textureSize = _overlayTexWidth * _overlayTexHeight * 2;
+ _overlayTexBuffer = (char *)malloc(textureSize);
+ memset(_overlayTexBuffer, 0, textureSize);
+
+ glViewport(0, 0, _renderBufferWidth, _renderBufferHeight); printOpenGLError();
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f); printOpenGLError();
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glEnable(GL_TEXTURE_2D); printOpenGLError();
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY); printOpenGLError();
+ glEnableClientState(GL_VERTEX_ARRAY); printOpenGLError();
+ }
+}
+
+- (id)initWithFrame:(struct CGRect)frame {
+ self = [super initWithFrame: frame];
+
+ if ([[UIScreen mainScreen] respondsToSelector: NSSelectorFromString(@"scale")]) {
+ if ([self respondsToSelector: NSSelectorFromString(@"contentScaleFactor")]) {
+ //self.contentScaleFactor = [[UIScreen mainScreen] scale];
+ }
+ }
+
+ _fullWidth = frame.size.width;
+ _fullHeight = frame.size.height;
+
+ sharedInstance = self;
+
+ _keyboardView = nil;
+ _screenTexture = 0;
+ _overlayTexture = 0;
+ _mouseCursorTexture = 0;
+
+ _gameScreenVertCoords[0] = _gameScreenVertCoords[1] =
+ _gameScreenVertCoords[2] = _gameScreenVertCoords[3] =
+ _gameScreenVertCoords[4] = _gameScreenVertCoords[5] =
+ _gameScreenVertCoords[6] = _gameScreenVertCoords[7] = 0;
+
+ _gameScreenTexCoords[0] = _gameScreenTexCoords[1] =
+ _gameScreenTexCoords[2] = _gameScreenTexCoords[3] =
+ _gameScreenTexCoords[4] = _gameScreenTexCoords[5] =
+ _gameScreenTexCoords[6] = _gameScreenTexCoords[7] = 0;
+
+ _overlayVertCoords[0] = _overlayVertCoords[1] =
+ _overlayVertCoords[2] = _overlayVertCoords[3] =
+ _overlayVertCoords[4] = _overlayVertCoords[5] =
+ _overlayVertCoords[6] = _overlayVertCoords[7] = 0;
+
+ _overlayTexCoords[0] = _overlayTexCoords[1] =
+ _overlayTexCoords[2] = _overlayTexCoords[3] =
+ _overlayTexCoords[4] = _overlayTexCoords[5] =
+ _overlayTexCoords[6] = _overlayTexCoords[7] = 0;
+
+ // Initialize the OpenGL ES context
+ [self createContext];
+
+ return self;
+}
+
+- (void)dealloc {
+ [super dealloc];
+
+ if (_keyboardView != nil) {
+ [_keyboardView dealloc];
+ }
+
+ free(_gameScreenTextureBuffer);
+ free(_overlayTexBuffer);
+}
+
+- (void *)getSurface {
+ return _screenSurface;
+}
+
+- (void)drawRect:(CGRect)frame {
+#if 0
+ if (lastTick == 0) {
+ lastTick = time(0);
+ }
+
+ frames++;
+ if (time(0) > lastTick) {
+ lastTick = time(0);
+ printf("FPS: %i\n", frames);
+ frames = 0;
+ }
+#endif
+}
+
+- (void)setGraphicsMode {
+ setFilterModeForTexture(_screenTexture, _graphicsMode);
+ setFilterModeForTexture(_overlayTexture, _graphicsMode);
+ setFilterModeForTexture(_mouseCursorTexture, _graphicsMode);
+}
+
+- (void)updateSurface {
+ if (!_needsScreenUpdate) {
+ return;
+ }
+ _needsScreenUpdate = 0;
+
+ glClear(GL_COLOR_BUFFER_BIT); printOpenGLError();
+
+ [self updateMainSurface];
+
+ if (_overlayIsEnabled)
+ [self updateOverlaySurface];
+
+ if (_mouseCursorEnabled)
+ [self updateMouseSurface];
+
+ glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError();
+ [_context presentRenderbuffer:GL_RENDERBUFFER_OES];
+
+}
+
+- (void)updateMouseCursor {
+ if (_mouseCursorTexture == 0) {
+ glGenTextures(1, &_mouseCursorTexture); printOpenGLError();
+ setFilterModeForTexture(_mouseCursorTexture, _graphicsMode);
+ }
+
+ 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();
+
+ free(_mouseCursor);
+ _mouseCursor = NULL;
+}
+
+- (void)updateMainSurface {
+ glVertexPointer(2, GL_FLOAT, 0, _gameScreenVertCoords); printOpenGLError();
+ glTexCoordPointer(2, GL_FLOAT, 0, _gameScreenTexCoords); printOpenGLError();
+
+ glBindTexture(GL_TEXTURE_2D, _screenTexture); printOpenGLError();
+
+ // 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();
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError();
+}
+
+- (void)updateOverlaySurface {
+ glVertexPointer(2, GL_FLOAT, 0, _overlayVertCoords); printOpenGLError();
+ 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();
+ 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 = 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
+ };
+
+ //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();
+
+ 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;
+
+ _orientation = [[UIDevice currentDevice] orientation];
+
+ switch (_orientation) {
+ case UIDeviceOrientationLandscapeLeft:
+ case UIDeviceOrientationLandscapeRight:
+ case UIDeviceOrientationPortrait:
+ break;
+
+ default:
+ _orientation = UIDeviceOrientationPortrait;
+ }
+
+ //printf("Window: (%d, %d), Surface: (%d, %d), Texture(%d, %d)\n", _fullWidth, _fullHeight, _width, _height, _gameScreenTextureWidth, _gameScreenTextureHeight);
+
+ 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();
+ glOrthof(0, _renderBufferHeight, _renderBufferWidth, 0, 0, 1); printOpenGLError();
+
+ screenWidth = _renderBufferHeight;
+ screenHeight = _renderBufferWidth;
+ } else if (_orientation == UIDeviceOrientationLandscapeLeft) {
+ glRotatef(-90, 0, 0, 1); printOpenGLError();
+ glOrthof(0, _renderBufferHeight, _renderBufferWidth, 0, 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();
+ }
+
+ glGenTextures(1, &_screenTexture); printOpenGLError();
+ setFilterModeForTexture(_screenTexture, _graphicsMode);
+
+ 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);
+
+ glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError();
+
+ [self clearColorBuffer];
+
+ if (_keyboardView != nil) {
+ [_keyboardView removeFromSuperview];
+ [[_keyboardView inputView] removeFromSuperview];
+ }
+
+ float overlayPortraitRatio;
+
+ if (_orientation == UIDeviceOrientationLandscapeLeft || _orientation == UIDeviceOrientationLandscapeRight) {
+ GLfloat gameScreenRatio = (GLfloat)_width / (GLfloat)_height;
+ GLfloat screenRatio = (GLfloat)screenWidth / (GLfloat)screenHeight;
+
+ // These are the width/height according to the portrait layout!
+ int rectWidth, rectHeight;
+ 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 {
+ // 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", xOffset, yOffset, rectWidth, rectHeight);
+ _gameScreenRect = CGRectMake(xOffset, yOffset, rectWidth, rectHeight);
+ overlayPortraitRatio = 1.0f;
+ } else {
+ float ratio = (float)_height / (float)_width;
+ 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) {
+ _keyboardView = [[SoftKeyboard alloc] initWithFrame:keyFrame];
+ [_keyboardView setInputDelegate:self];
+ }
+
+ [self addSubview:[_keyboardView inputView]];
+ [self addSubview: _keyboardView];
+ [[_keyboardView inputView] becomeFirstResponder];
+ overlayPortraitRatio = (_overlayHeight * ratio) / _overlayWidth;
+ }
+
+ _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);
+
+ [self setViewTransformation];
+}
+
+- (void)setViewTransformation {
+ // Set the modelview matrix. This matrix will be used for the shake offset
+ // support.
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ // 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 = _shakeOffsetY / (GLfloat)_height * CGRectGetHeight(_overlayRect);
+
+ // Apply the shakeing to the output screen.
+ glTranslatef(0, -_scaledShakeOffsetY, 0);
+}
+
+- (void)clearColorBuffer {
+ // The color buffer is triple-buffered, so we clear it multiple times right away to avid doing any glClears later.
+ int clearCount = 5;
+ while (clearCount-- > 0) {
+ glClear(GL_COLOR_BUFFER_BIT); printOpenGLError();
+ [_context presentRenderbuffer:GL_RENDERBUFFER_OES];
+ }
+}
+
+- (id)getEvent {
+ if (_events == nil || [_events count] == 0) {
+ return nil;
+ }
+
+ id event = [_events objectAtIndex: 0];
+
+ [_events removeObjectAtIndex: 0];
+
+ return event;
+}
+
+- (void)addEvent:(NSDictionary *)event {
+ if (_events == nil)
+ _events = [[NSMutableArray alloc] init];
+
+ [_events addObject: event];
+}
+
+- (void)deviceOrientationChanged:(UIDeviceOrientation)orientation {
+ switch (orientation) {
+ case UIDeviceOrientationLandscapeLeft:
+ case UIDeviceOrientationLandscapeRight:
+ case UIDeviceOrientationPortrait:
+ _orientation = orientation;
+ break;
+
+ default:
+ return;
+ }
+
+ [self addEvent:
+ [[NSDictionary alloc] initWithObjectsAndKeys:
+ [NSNumber numberWithInt:kInputOrientationChanged], @"type",
+ [NSNumber numberWithInt:orientation], @"x",
+ [NSNumber numberWithInt:0], @"y",
+ nil
+ ]
+ ];
+}
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
+ NSSet *allTouches = [event allTouches];
+ int x, y;
+
+ switch ([allTouches count]) {
+ case 1: {
+ UITouch *touch = [touches anyObject];
+ CGPoint point = [touch locationInView:self];
+ if (!getMouseCoords(_orientation, point, &x, &y))
+ return;
+
+ _firstTouch = touch;
+ [self addEvent:
+ [[NSDictionary alloc] initWithObjectsAndKeys:
+ [NSNumber numberWithInt:kInputMouseDown], @"type",
+ [NSNumber numberWithInt:x], @"x",
+ [NSNumber numberWithInt:y], @"y",
+ nil
+ ]
+ ];
+ break;
+ }
+
+ case 2: {
+ UITouch *touch = [touches anyObject];
+ CGPoint point = [touch locationInView:self];
+ if (!getMouseCoords(_orientation, point, &x, &y))
+ return;
+
+ _secondTouch = touch;
+ [self addEvent:
+ [[NSDictionary alloc] initWithObjectsAndKeys:
+ [NSNumber numberWithInt:kInputMouseSecondDown], @"type",
+ [NSNumber numberWithInt:x], @"x",
+ [NSNumber numberWithInt:y], @"y",
+ nil
+ ]
+ ];
+ break;
+ }
+ }
+}
+
+- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
+ //NSSet *allTouches = [event allTouches];
+ int x, y;
+
+ for (UITouch *touch in touches) {
+ if (touch == _firstTouch) {
+ CGPoint point = [touch locationInView:self];
+ if (!getMouseCoords(_orientation, point, &x, &y))
+ return;
+
+ [self addEvent:
+ [[NSDictionary alloc] initWithObjectsAndKeys:
+ [NSNumber numberWithInt:kInputMouseDragged], @"type",
+ [NSNumber numberWithInt:x], @"x",
+ [NSNumber numberWithInt:y], @"y",
+ nil
+ ]
+ ];
+ } else if (touch == _secondTouch) {
+ CGPoint point = [touch locationInView:self];
+ if (!getMouseCoords(_orientation, point, &x, &y))
+ return;
+
+ [self addEvent:
+ [[NSDictionary alloc] initWithObjectsAndKeys:
+ [NSNumber numberWithInt:kInputMouseSecondDragged], @"type",
+ [NSNumber numberWithInt:x], @"x",
+ [NSNumber numberWithInt:y], @"y",
+ nil
+ ]
+ ];
+ }
+ }
+}
+
+- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
+ NSSet *allTouches = [event allTouches];
+ int x, y;
+
+ switch ([allTouches count]) {
+ case 1: {
+ UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
+ CGPoint point = [touch locationInView:self];
+ if (!getMouseCoords(_orientation, point, &x, &y))
+ return;
+
+ [self addEvent:
+ [[NSDictionary alloc] initWithObjectsAndKeys:
+ [NSNumber numberWithInt:kInputMouseUp], @"type",
+ [NSNumber numberWithInt:x], @"x",
+ [NSNumber numberWithInt:y], @"y",
+ nil
+ ]
+ ];
+ break;
+ }
+
+ case 2: {
+ UITouch *touch = [[allTouches allObjects] objectAtIndex:1];
+ CGPoint point = [touch locationInView:self];
+ if (!getMouseCoords(_orientation, point, &x, &y))
+ return;
+
+ [self addEvent:
+ [[NSDictionary alloc] initWithObjectsAndKeys:
+ [NSNumber numberWithInt:kInputMouseSecondUp], @"type",
+ [NSNumber numberWithInt:x], @"x",
+ [NSNumber numberWithInt:y], @"y",
+ nil
+ ]
+ ];
+ break;
+ }
+ }
+}
+
+- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
+}
+
+- (void)handleKeyPress:(unichar)c {
+ [self addEvent:
+ [[NSDictionary alloc] initWithObjectsAndKeys:
+ [NSNumber numberWithInt:kInputKeyPressed], @"type",
+ [NSNumber numberWithInt:c], @"x",
+ [NSNumber numberWithInt:0], @"y",
+ nil
+ ]
+ ];
+}
+
+- (BOOL)canHandleSwipes {
+ return TRUE;
+}
+
+- (int)swipe:(int)num withEvent:(struct __GSEvent *)event {
+ //printf("swipe: %i\n", num);
+
+ [self addEvent:
+ [[NSDictionary alloc] initWithObjectsAndKeys:
+ [NSNumber numberWithInt:kInputSwipe], @"type",
+ [NSNumber numberWithInt:num], @"x",
+ [NSNumber numberWithInt:0], @"y",
+ nil
+ ]
+ ];
+}
+
+- (void)applicationSuspend {
+ [self addEvent:
+ [[NSDictionary alloc] initWithObjectsAndKeys:
+ [NSNumber numberWithInt:kInputApplicationSuspended], @"type",
+ [NSNumber numberWithInt:0], @"x",
+ [NSNumber numberWithInt:0], @"y",
+ nil
+ ]
+ ];
+}
+
+- (void)applicationResume {
+ [self addEvent:
+ [[NSDictionary alloc] initWithObjectsAndKeys:
+ [NSNumber numberWithInt:kInputApplicationResumed], @"type",
+ [NSNumber numberWithInt:0], @"x",
+ [NSNumber numberWithInt:0], @"y",
+ nil
+ ]
+ ];
+}
+
+@end