comparison Classes/MySampleProjectViewController.m @ 0:5ec52341f221

Initial commit
author Eric Wing <ewing@anscamobile.com>
date Fri, 29 Jul 2011 18:18:15 -0700
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:5ec52341f221
1 //
2 // MySampleProjectViewController.m
3 // MySampleProject
4 //
5 // Created by Eric Wing on 7/29/11.
6 // Copyright 2011 __MyCompanyName__. All rights reserved.
7 //
8
9 #import <QuartzCore/QuartzCore.h>
10
11 #import "MySampleProjectViewController.h"
12 #import "EAGLView.h"
13
14 // Uniform index.
15 enum {
16 UNIFORM_TRANSLATE,
17 NUM_UNIFORMS
18 };
19 GLint uniforms[NUM_UNIFORMS];
20
21 // Attribute index.
22 enum {
23 ATTRIB_VERTEX,
24 ATTRIB_COLOR,
25 NUM_ATTRIBUTES
26 };
27
28 @interface MySampleProjectViewController ()
29 @property (nonatomic, retain) EAGLContext *context;
30 @property (nonatomic, assign) CADisplayLink *displayLink;
31 - (BOOL)loadShaders;
32 - (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file;
33 - (BOOL)linkProgram:(GLuint)prog;
34 - (BOOL)validateProgram:(GLuint)prog;
35 @end
36
37 @implementation MySampleProjectViewController
38
39 @synthesize animating, context, displayLink;
40
41 - (void)awakeFromNib
42 {
43 #if USE_OPENGLES2
44 EAGLContext* aContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
45 #else
46 EAGLContext* aContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
47 #endif
48
49 if (!aContext)
50 NSLog(@"Failed to create ES context");
51 else if (![EAGLContext setCurrentContext:aContext])
52 NSLog(@"Failed to set ES context current");
53
54 self.context = aContext;
55 [aContext release];
56
57 [(EAGLView *)self.view setContext:context];
58 [(EAGLView *)self.view setFramebuffer];
59
60 #if USE_OPENGLES2
61 if ([context API] == kEAGLRenderingAPIOpenGLES2)
62 [self loadShaders];
63 #endif
64
65 animating = FALSE;
66 animationFrameInterval = 1;
67 self.displayLink = nil;
68 }
69
70 - (void)dealloc
71 {
72 if (program)
73 {
74 glDeleteProgram(program);
75 program = 0;
76 }
77
78 // Tear down context.
79 if ([EAGLContext currentContext] == context)
80 [EAGLContext setCurrentContext:nil];
81
82 [context release];
83
84 [super dealloc];
85 }
86
87 - (void)viewWillAppear:(BOOL)animated
88 {
89 [self startAnimation];
90
91 [super viewWillAppear:animated];
92 }
93
94 - (void)viewWillDisappear:(BOOL)animated
95 {
96 [self stopAnimation];
97
98 [super viewWillDisappear:animated];
99 }
100
101 - (void)viewDidUnload
102 {
103 [super viewDidUnload];
104
105 if (program)
106 {
107 glDeleteProgram(program);
108 program = 0;
109 }
110
111 // Tear down context.
112 if ([EAGLContext currentContext] == context)
113 [EAGLContext setCurrentContext:nil];
114 self.context = nil;
115 }
116
117 - (NSInteger)animationFrameInterval
118 {
119 return animationFrameInterval;
120 }
121
122 - (void)setAnimationFrameInterval:(NSInteger)frameInterval
123 {
124 /*
125 Frame interval defines how many display frames must pass between each time the display link fires.
126 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.
127 */
128 if (frameInterval >= 1)
129 {
130 animationFrameInterval = frameInterval;
131
132 if (animating)
133 {
134 [self stopAnimation];
135 [self startAnimation];
136 }
137 }
138 }
139
140 - (void)startAnimation
141 {
142 if (!animating)
143 {
144 CADisplayLink *aDisplayLink = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(drawFrame)];
145 [aDisplayLink setFrameInterval:animationFrameInterval];
146 [aDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
147 self.displayLink = aDisplayLink;
148
149 animating = TRUE;
150 }
151 }
152
153 - (void)stopAnimation
154 {
155 if (animating)
156 {
157 [self.displayLink invalidate];
158 self.displayLink = nil;
159 animating = FALSE;
160 }
161 }
162
163 - (void)drawFrame
164 {
165 [(EAGLView *)self.view setFramebuffer];
166
167 // Replace the implementation of this method to do your own custom drawing.
168 static const GLfloat squareVertices[] = {
169 -0.5f, -0.33f,
170 0.5f, -0.33f,
171 -0.5f, 0.33f,
172 0.5f, 0.33f,
173 };
174
175 static const GLubyte squareColors[] = {
176 255, 255, 0, 255,
177 0, 255, 255, 255,
178 0, 0, 0, 0,
179 255, 0, 255, 255,
180 };
181
182 static float transY = 0.0f;
183
184 glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
185 glClear(GL_COLOR_BUFFER_BIT);
186
187 #if USE_OPENGLES2
188 // Use shader program.
189 glUseProgram(program);
190
191 // Update uniform value.
192 glUniform1f(uniforms[UNIFORM_TRANSLATE], (GLfloat)transY);
193 transY += 0.075f;
194
195 // Update attribute values.
196 glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
197 glEnableVertexAttribArray(ATTRIB_VERTEX);
198 glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, 1, 0, squareColors);
199 glEnableVertexAttribArray(ATTRIB_COLOR);
200
201 // Validate program before drawing. This is a good check, but only really necessary in a debug build.
202 // DEBUG macro must be defined in your debug configurations if that's not already the case.
203 #if defined(DEBUG)
204 if (![self validateProgram:program])
205 {
206 NSLog(@"Failed to validate program: %d", program);
207 return;
208 }
209 #endif
210 #else
211 glMatrixMode(GL_PROJECTION);
212 glLoadIdentity();
213 glMatrixMode(GL_MODELVIEW);
214 glLoadIdentity();
215 glTranslatef(0.0f, (GLfloat)(sinf(transY)/2.0f), 0.0f);
216 transY += 0.075f;
217
218 glVertexPointer(2, GL_FLOAT, 0, squareVertices);
219 glEnableClientState(GL_VERTEX_ARRAY);
220 glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);
221 glEnableClientState(GL_COLOR_ARRAY);
222 #endif
223
224 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
225
226 [(EAGLView *)self.view presentFramebuffer];
227 }
228
229 - (void)didReceiveMemoryWarning
230 {
231 // Releases the view if it doesn't have a superview.
232 [super didReceiveMemoryWarning];
233
234 // Release any cached data, images, etc. that aren't in use.
235 }
236
237 - (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file
238 {
239 GLint status;
240 const GLchar *source;
241
242 source = (GLchar *)[[NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil] UTF8String];
243 if (!source)
244 {
245 NSLog(@"Failed to load vertex shader");
246 return FALSE;
247 }
248
249 *shader = glCreateShader(type);
250 glShaderSource(*shader, 1, &source, NULL);
251 glCompileShader(*shader);
252
253 #if defined(DEBUG)
254 GLint logLength;
255 glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
256 if (logLength > 0)
257 {
258 GLchar *log = (GLchar *)malloc(logLength);
259 glGetShaderInfoLog(*shader, logLength, &logLength, log);
260 NSLog(@"Shader compile log:\n%s", log);
261 free(log);
262 }
263 #endif
264
265 glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
266 if (status == 0)
267 {
268 glDeleteShader(*shader);
269 return FALSE;
270 }
271
272 return TRUE;
273 }
274
275 - (BOOL)linkProgram:(GLuint)prog
276 {
277 GLint status;
278
279 glLinkProgram(prog);
280
281 #if defined(DEBUG)
282 GLint logLength;
283 glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
284 if (logLength > 0)
285 {
286 GLchar *log = (GLchar *)malloc(logLength);
287 glGetProgramInfoLog(prog, logLength, &logLength, log);
288 NSLog(@"Program link log:\n%s", log);
289 free(log);
290 }
291 #endif
292
293 glGetProgramiv(prog, GL_LINK_STATUS, &status);
294 if (status == 0)
295 return FALSE;
296
297 return TRUE;
298 }
299
300 - (BOOL)validateProgram:(GLuint)prog
301 {
302 GLint logLength, status;
303
304 glValidateProgram(prog);
305 glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
306 if (logLength > 0)
307 {
308 GLchar *log = (GLchar *)malloc(logLength);
309 glGetProgramInfoLog(prog, logLength, &logLength, log);
310 NSLog(@"Program validate log:\n%s", log);
311 free(log);
312 }
313
314 glGetProgramiv(prog, GL_VALIDATE_STATUS, &status);
315 if (status == 0)
316 return FALSE;
317
318 return TRUE;
319 }
320
321 - (BOOL)loadShaders
322 {
323 GLuint vertShader, fragShader;
324 NSString *vertShaderPathname, *fragShaderPathname;
325
326 // Create shader program.
327 program = glCreateProgram();
328
329 // Create and compile vertex shader.
330 vertShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"vsh"];
331 if (![self compileShader:&vertShader type:GL_VERTEX_SHADER file:vertShaderPathname])
332 {
333 NSLog(@"Failed to compile vertex shader");
334 return FALSE;
335 }
336
337 // Create and compile fragment shader.
338 fragShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"fsh"];
339 if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:fragShaderPathname])
340 {
341 NSLog(@"Failed to compile fragment shader");
342 return FALSE;
343 }
344
345 // Attach vertex shader to program.
346 glAttachShader(program, vertShader);
347
348 // Attach fragment shader to program.
349 glAttachShader(program, fragShader);
350
351 // Bind attribute locations.
352 // This needs to be done prior to linking.
353 glBindAttribLocation(program, ATTRIB_VERTEX, "position");
354 glBindAttribLocation(program, ATTRIB_COLOR, "color");
355
356 // Link program.
357 if (![self linkProgram:program])
358 {
359 NSLog(@"Failed to link program: %d", program);
360
361 if (vertShader)
362 {
363 glDeleteShader(vertShader);
364 vertShader = 0;
365 }
366 if (fragShader)
367 {
368 glDeleteShader(fragShader);
369 fragShader = 0;
370 }
371 if (program)
372 {
373 glDeleteProgram(program);
374 program = 0;
375 }
376
377 return FALSE;
378 }
379
380 // Get uniform locations.
381 uniforms[UNIFORM_TRANSLATE] = glGetUniformLocation(program, "translate");
382
383 // Release vertex and fragment shaders.
384 if (vertShader)
385 glDeleteShader(vertShader);
386 if (fragShader)
387 glDeleteShader(fragShader);
388
389 return TRUE;
390 }
391
392 @end