0
|
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
|