Mercurial > xcodescriptingbridge
diff Classes/MySampleProjectViewController.m @ 0:5ec52341f221
Initial commit
author | Eric Wing <ewing@anscamobile.com> |
---|---|
date | Fri, 29 Jul 2011 18:18:15 -0700 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Classes/MySampleProjectViewController.m Fri Jul 29 18:18:15 2011 -0700 @@ -0,0 +1,392 @@ +// +// MySampleProjectViewController.m +// MySampleProject +// +// Created by Eric Wing on 7/29/11. +// Copyright 2011 __MyCompanyName__. All rights reserved. +// + +#import <QuartzCore/QuartzCore.h> + +#import "MySampleProjectViewController.h" +#import "EAGLView.h" + +// Uniform index. +enum { + UNIFORM_TRANSLATE, + NUM_UNIFORMS +}; +GLint uniforms[NUM_UNIFORMS]; + +// Attribute index. +enum { + ATTRIB_VERTEX, + ATTRIB_COLOR, + NUM_ATTRIBUTES +}; + +@interface MySampleProjectViewController () +@property (nonatomic, retain) EAGLContext *context; +@property (nonatomic, assign) CADisplayLink *displayLink; +- (BOOL)loadShaders; +- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file; +- (BOOL)linkProgram:(GLuint)prog; +- (BOOL)validateProgram:(GLuint)prog; +@end + +@implementation MySampleProjectViewController + +@synthesize animating, context, displayLink; + +- (void)awakeFromNib +{ +#if USE_OPENGLES2 + EAGLContext* aContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; +#else + EAGLContext* aContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; +#endif + + if (!aContext) + NSLog(@"Failed to create ES context"); + else if (![EAGLContext setCurrentContext:aContext]) + NSLog(@"Failed to set ES context current"); + + self.context = aContext; + [aContext release]; + + [(EAGLView *)self.view setContext:context]; + [(EAGLView *)self.view setFramebuffer]; + +#if USE_OPENGLES2 + if ([context API] == kEAGLRenderingAPIOpenGLES2) + [self loadShaders]; +#endif + + animating = FALSE; + animationFrameInterval = 1; + self.displayLink = nil; +} + +- (void)dealloc +{ + if (program) + { + glDeleteProgram(program); + program = 0; + } + + // Tear down context. + if ([EAGLContext currentContext] == context) + [EAGLContext setCurrentContext:nil]; + + [context release]; + + [super dealloc]; +} + +- (void)viewWillAppear:(BOOL)animated +{ + [self startAnimation]; + + [super viewWillAppear:animated]; +} + +- (void)viewWillDisappear:(BOOL)animated +{ + [self stopAnimation]; + + [super viewWillDisappear:animated]; +} + +- (void)viewDidUnload +{ + [super viewDidUnload]; + + if (program) + { + glDeleteProgram(program); + program = 0; + } + + // Tear down context. + if ([EAGLContext currentContext] == context) + [EAGLContext setCurrentContext:nil]; + self.context = nil; +} + +- (NSInteger)animationFrameInterval +{ + return animationFrameInterval; +} + +- (void)setAnimationFrameInterval:(NSInteger)frameInterval +{ + /* + Frame interval defines how many display frames must pass between each time the display link fires. + The display link will only fire 30 times a second when the frame internal is two on a display that refreshes 60 times a second. The default frame interval setting of one will fire 60 times a second when the display refreshes at 60 times a second. A frame interval setting of less than one results in undefined behavior. + */ + if (frameInterval >= 1) + { + animationFrameInterval = frameInterval; + + if (animating) + { + [self stopAnimation]; + [self startAnimation]; + } + } +} + +- (void)startAnimation +{ + if (!animating) + { + CADisplayLink *aDisplayLink = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(drawFrame)]; + [aDisplayLink setFrameInterval:animationFrameInterval]; + [aDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + self.displayLink = aDisplayLink; + + animating = TRUE; + } +} + +- (void)stopAnimation +{ + if (animating) + { + [self.displayLink invalidate]; + self.displayLink = nil; + animating = FALSE; + } +} + +- (void)drawFrame +{ + [(EAGLView *)self.view setFramebuffer]; + + // Replace the implementation of this method to do your own custom drawing. + static const GLfloat squareVertices[] = { + -0.5f, -0.33f, + 0.5f, -0.33f, + -0.5f, 0.33f, + 0.5f, 0.33f, + }; + + static const GLubyte squareColors[] = { + 255, 255, 0, 255, + 0, 255, 255, 255, + 0, 0, 0, 0, + 255, 0, 255, 255, + }; + + static float transY = 0.0f; + + glClearColor(0.5f, 0.5f, 0.5f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + +#if USE_OPENGLES2 + // Use shader program. + glUseProgram(program); + + // Update uniform value. + glUniform1f(uniforms[UNIFORM_TRANSLATE], (GLfloat)transY); + transY += 0.075f; + + // Update attribute values. + glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices); + glEnableVertexAttribArray(ATTRIB_VERTEX); + glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, 1, 0, squareColors); + glEnableVertexAttribArray(ATTRIB_COLOR); + + // Validate program before drawing. This is a good check, but only really necessary in a debug build. + // DEBUG macro must be defined in your debug configurations if that's not already the case. +#if defined(DEBUG) + if (![self validateProgram:program]) + { + NSLog(@"Failed to validate program: %d", program); + return; + } +#endif +#else + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.0f, (GLfloat)(sinf(transY)/2.0f), 0.0f); + transY += 0.075f; + + glVertexPointer(2, GL_FLOAT, 0, squareVertices); + glEnableClientState(GL_VERTEX_ARRAY); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors); + glEnableClientState(GL_COLOR_ARRAY); +#endif + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + [(EAGLView *)self.view presentFramebuffer]; +} + +- (void)didReceiveMemoryWarning +{ + // Releases the view if it doesn't have a superview. + [super didReceiveMemoryWarning]; + + // Release any cached data, images, etc. that aren't in use. +} + +- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file +{ + GLint status; + const GLchar *source; + + source = (GLchar *)[[NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil] UTF8String]; + if (!source) + { + NSLog(@"Failed to load vertex shader"); + return FALSE; + } + + *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 FALSE; + } + + return TRUE; +} + +- (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 FALSE; + + return TRUE; +} + +- (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 FALSE; + + return TRUE; +} + +- (BOOL)loadShaders +{ + 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 FALSE; + } + + // 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 FALSE; + } + + // 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, ATTRIB_VERTEX, "position"); + glBindAttribLocation(program, ATTRIB_COLOR, "color"); + + // 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 FALSE; + } + + // Get uniform locations. + uniforms[UNIFORM_TRANSLATE] = glGetUniformLocation(program, "translate"); + + // Release vertex and fragment shaders. + if (vertShader) + glDeleteShader(vertShader); + if (fragShader) + glDeleteShader(fragShader); + + return TRUE; +} + +@end