Here you go, theres a lot of it and I'm not sure its all relevant. Surely theres a standard way to move your camera outside of ViewController.There must be an API call?
//
// ViewController.m
// Stragglers
//
// Created by Ian on 16/04/2014.
// Copyright (c) 2014 IanTierney. All rights reserved.
//
#import "ViewController.h"
#import "Game.h"
#import "StatePlay.h"
#import "StateLevelWin.h"
Game* game;
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
// Uniform index. //TODO DELETE
enum
{
UNIFORM_MODELVIEWPROJECTION_MATRIX,
UNIFORM_NORMAL_MATRIX,
NUM_UNIFORMS
};
GLint uniforms[NUM_UNIFORMS];
// Attribute index.
//todo delete
enum //TODO DELETE
{
ATTRIB_VERTEX,
ATTRIB_NORMAL,
NUM_ATTRIBUTES
};
@interface ViewController ()
{
GLuint _program;
GLKMatrix4 _modelViewProjectionMatrix;
GLKMatrix3 _normalMatrix;
float _rotation;
GLuint _vertexArray;
GLuint _vertexBuffer;
//todo Ian probably have these as cost as they wont change after you init
CGFloat screenWidth;
CGFloat screenHeight;
}
@property (strong, nonatomic) EAGLContext *context;
@property (strong, nonatomic) GLKBaseEffect *effect;
- (void)setupGL;
- (void)tearDownGL;
- (BOOL)loadShaders;
- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file;
- (BOOL)linkProgram:(GLuint)prog;
- (BOOL)validateProgram:(GLuint)prog;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!self.context) {
NSLog(@"Failed to create ES context");
}
GLKView *view = (GLKView *)self.view;
view.context = self.context;
[EAGLContext setCurrentContext:self.context];
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;//todo not sure what this is or why its needed. its not in
//[EAGLContext setCurrentContext:self.context]; this is done in setupGL;
[self setupGL];
}
- (void)dealloc
{
[self tearDownGL];
if ([EAGLContext currentContext] == self.context) {
[EAGLContext setCurrentContext:nil];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
if ([self isViewLoaded] && ([[self view] window] == nil)) {
self.view = nil;
[self tearDownGL];
if ([EAGLContext currentContext] == self.context) {
[EAGLContext setCurrentContext:nil];
}
self.context = nil;
}
// Dispose of any resources that can be recreated.
}
/*
converts window coordinates (half of actual pixels coordinates, with origin )
to opnGL coodinates
*/
void toPixel(CGPoint* p, CGFloat w, CGFloat h)
{
p->x= (2 * p->x);
p->y= (2 * p->y);
p->y = h - p->y;//flip the y coordinate
// NSLog(@"T X: %f, Y: %f \n", p->x ,p->y);
}
/*
Stores touch position in touchPos.
NOTE (0,0) is top Right of screen
*/
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//---get all touches on the screen---
NSSet *allTouches = [event allTouches];
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
//- (CGPoint)locationInView:(UIView *)view
game->touchPos = [touch locationInView:nil];
toPixel(&game->touchPos, screenWidth, screenHeight);
//printf("x:%f y:%f \n", touchPos.x ,touchPos.y );
//todo this should be in game code but I can't reset camera outside this class
if(game->touchPos.x <20 && game->touchPos.y <20)//can reset game pressing bottom corner
{
[self resetCamera];
game->resetLevel();
}
else
{
game->reactTouch();
}
}
/*
Stores touch position in touchPos.
NOTE (0,0) is top Right of screen
*/
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//---get all touches on the screen---
NSSet *allTouches = [event allTouches];
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
//- (CGPoint)locationInView:(UIView *)view
game->touchPos = [touch locationInView:nil];
toPixel(&game->touchPos, screenWidth, screenHeight);
printf("x:%f y:%f \n", game->touchPos.x ,game->touchPos.y );
game->reactTouchEnd();
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
//---get all touches on the screen---
NSSet *allTouches = [event allTouches];
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
//- (CGPoint)locationInView:(UIView *)view
game->touchPos = [touch locationInView:nil];
toPixel(&game->touchPos, screenWidth, screenHeight);
game->reactMove();
}
void iansSetup(GLKBaseEffect *effect, int screenW, int screenH)
//-(void) iansSetup (GLKBaseEffect*) effect (int) screenW (int) screenH
{
NSLog(@"new Game(");
game = new Game(effect, screenW, screenH);
game->ChangeState( StatePlay::Instance());
NSLog(@" END iansSetup(");
}
- (void)setupGL
{
/*
Ians setup of open gl from
http://www.raywenderlich.com/9743/how-to-create-a-simple-2d-iphone-game-with-opengl-es-2-0-and-glkit-part-1
*/
[super viewDidLoad];
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!self.context) {
NSLog(@"Failed to create ES context");
}
GLKView *view = (GLKView *)self.view;
view.context = self.context;
[EAGLContext setCurrentContext:self.context];
self.effect = [[GLKBaseEffect alloc] init];
//todo these should be constants I think..not sure why they are floats either as they are in pixels
//CGRect screenRect = [[UIScreen mainScreen] bounds];
float scaleFactor = [[UIScreen mainScreen] scale];
CGRect screen = [[UIScreen mainScreen] bounds];
screenWidth = screen.size.width * scaleFactor;
screenHeight = screen.size.height * scaleFactor;
GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(0, screenWidth, 0, screenHeight, -1024, 1024);
self.effect.transform.projectionMatrix = projectionMatrix;
iansSetup(self.effect,screenWidth, screenHeight);
}
- (void)tearDownGL
{
[EAGLContext setCurrentContext:self.context];
glDeleteBuffers(1, &_vertexBuffer);
glDeleteVertexArraysOES(1, &_vertexArray);
self.effect = nil;
if (_program) {
glDeleteProgram(_program);
_program = 0;
}
}
#pragma mark - GLKView and GLKViewController delegate methods
- (void)update
{
// Bothe of these should eb done within the respective state class
//I can only seem to move camera inside this class
State* curState = game->states.back();
if(curState== StatePlay::Instance() )
[self scrollCamera];
//todo move to StateLevelWin::Update()
/* this gives me a linker error
if(curState == StateLevelWin::Instance() //if you have completed the level
&& curState->timer>5)//and the timer is up
[self resetCamera];
*/
game->update(self.timeSinceLastUpdate,NULL);
//note render gets called via from drawInRect (in this file)
}
//TODO this should really be in the playState code or game objecy
- (void) scrollCamera
{
//TODO clean up, this is scrolling camera
if(game->scrollV)//if camera is moving
{
//this doesn't work, says projectionMatrix is temporary object
//game->update(self.timeSinceLastUpdate,&self.effect.transform.projectionMatrix);
int scrollDy = self.timeSinceLastUpdate * -game->scrollV;
game->scrollY -=scrollDy;
self.effect.transform.projectionMatrix = GLKMatrix4Translate(self.effect.transform.projectionMatrix, 0,scrollDy,0);
// printf("dt %f \n", self.timeSinceLastUpdate);
}
}
//TODO this should really be in the playState code or game objecy
- (void) resetCamera
//resetCamera
{
GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(0, screenWidth, 0, screenHeight, -1024, 1024);
self.effect.transform.projectionMatrix = projectionMatrix;
//self->_modelViewProjectionMatrix=projectionMatrix;// seems to have no effect
}
void drawRect(GLfloat left, GLfloat bottom, GLfloat right, GLfloat top, GLfloat R, GLfloat G, GLfloat B)
{
GLfloat rect[] = {
left, bottom,
right, bottom,
right, top,
left, top
};
//
// Enable vertex data to be fed down the graphics pipeline to be drawn
// Create an handle for a buffer object array
GLuint bufferObjectNameArray;
// Have OpenGL generate a buffer name and store it in the buffer object array
glGenBuffers(1, &bufferObjectNameArray);
// Bind the buffer object array to the GL_ARRAY_BUFFER target buffer
glBindBuffer(GL_ARRAY_BUFFER, bufferObjectNameArray);
glEnableVertexAttribArray(GLKVertexAttribPosition);
// Specify how the GPU looks up the data
glVertexAttribPointer(
GLKVertexAttribPosition, // the currently bound buffer holds the data
2, // number of coordinates per vertex
GL_FLOAT, // the data type of each component
GL_FALSE, // can the data be scaled
2*4, // how many bytes per vertex (2 floats per vertex)
NULL);
/////////////////////////////////////
glEnableClientState(GL_VERTEX_ARRAY);
glColor4f(R,G,B,1);
glVertexPointer(2, GL_FLOAT, 0, rect);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
void drawGrid(GLKBaseEffect* effect)
{
//glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Prepare the effect for rendering
[effect prepareToDraw];
glLineWidth(4);
const GLfloat line[] =
{
0.0f, 150.0f, //point A
100.0f, 150.0f, //point B
};
// Create an handle for a buffer object array
GLuint bufferObjectNameArray;
// Have OpenGL generate a buffer name and store it in the buffer object array
glGenBuffers(1, &bufferObjectNameArray);
// Bind the buffer object array to the GL_ARRAY_BUFFER target buffer
glBindBuffer(GL_ARRAY_BUFFER, bufferObjectNameArray);
// Send the line data over to the target buffer in GPU RAM
glBufferData(
GL_ARRAY_BUFFER, // the target buffer
sizeof(line), // the number of bytes to put into the buffer
line, // a pointer to the data being copied
GL_STATIC_DRAW); // the usage pattern of the data
// Enable vertex data to be fed down the graphics pipeline to be drawn
glEnableVertexAttribArray(GLKVertexAttribPosition);
// Specify how the GPU looks up the data
glVertexAttribPointer(
GLKVertexAttribPosition, // the currently bound buffer holds the data
2, // number of coordinates per vertex
GL_FLOAT, // the data type of each component
GL_FALSE, // can the data be scaled
2*4, // how many bytes per vertex (2 floats per vertex)
NULL); // offset to the first coordinate, in this case 0
glColor4f(0.5f, 0.5f, 0.5f, 1.0f);
glDrawArrays(GL_LINES, 0, 2); // render
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
game->render();
}
#pragma mark - OpenGL ES 2 shader compilation
- (BOOL)loadShaders
{
//todo remove
GLuint vertShader, fragShader;
NSString *vertShaderPathname, *fragShaderPathname;
// Create shader program.
_program = glCreateProgram();
// Create and compile vertex shader.
vertShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"vsh"];
if (![self compileShader:&vertShader type:GL_VERTEX_SHADER file:vertShaderPathname])
{
NSLog(@"Failed to compile vertex shader");
return NO;
}
// Create and compile fragment shader.
fragShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"fsh"];
if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:fragShaderPathname]) {
NSLog(@"Failed to compile fragment shader");
return NO;
}
// Attach vertex shader to program.
glAttachShader(_program, vertShader);
// Attach fragment shader to program.
glAttachShader(_program, fragShader);
// Bind attribute locations.
// This needs to be done prior to linking.
glBindAttribLocation(_program, GLKVertexAttribPosition, "position");
glBindAttribLocation(_program, GLKVertexAttribNormal, "normal");
// Link program.
if (![self linkProgram:_program]) {
NSLog(@"Failed to link program: %d", _program);
if (vertShader) {
glDeleteShader(vertShader);
vertShader = 0;
}
if (fragShader) {
glDeleteShader(fragShader);
fragShader = 0;
}
if (_program) {
glDeleteProgram(_program);
_program = 0;
}
return NO;
}
// Get uniform locations. TODO what is this?
uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX] = glGetUniformLocation(_program, "modelViewProjectionMatrix");
uniforms[UNIFORM_NORMAL_MATRIX] = glGetUniformLocation(_program, "normalMatrix");
// Release vertex and fragment shaders.
if (vertShader) {
glDetachShader(_program, vertShader);
glDeleteShader(vertShader);
}
if (fragShader) {
glDetachShader(_program, fragShader);
glDeleteShader(fragShader);
}
return YES;
}
- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file
{
//todo remove
GLint status;
const GLchar *source;
source = (GLchar *)[[NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil] UTF8String];
if (!source) {
NSLog(@"Failed to load vertex shader");
return NO;
}
*shader = glCreateShader(type);
glShaderSource(*shader, 1, &source, NULL);
glCompileShader(*shader);
#if defined(DEBUG)
GLint logLength;
glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)malloc(logLength);
glGetShaderInfoLog(*shader, logLength, &logLength, log);
NSLog(@"Shader compile log:\n%s", log);
free(log);
}
#endif
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
if (status == 0) {
glDeleteShader(*shader);
return NO;
}
return YES;
}
- (BOOL)linkProgram:(GLuint)prog
{
GLint status;
glLinkProgram(prog);
#if defined(DEBUG)
GLint logLength;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)malloc(logLength);
glGetProgramInfoLog(prog, logLength, &logLength, log);
NSLog(@"Program link log:\n%s", log);
free(log);
}
#endif
glGetProgramiv(prog, GL_LINK_STATUS, &status);
if (status == 0) {
return NO;
}
return YES;
}
- (BOOL)validateProgram:(GLuint)prog
{
GLint logLength, status;
glValidateProgram(prog);
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0)
{
GLchar *log = (GLchar *)malloc(logLength);
glGetProgramInfoLog(prog, logLength, &logLength, log);
NSLog(@"Program validate log:\n%s", log);
free(log);
}
glGetProgramiv(prog, GL_VALIDATE_STATUS, &status);
if (status == 0)
{
return NO;
}
return YES;
}
@end