• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*******************************************************************************************************************************************
2
3 @File         OGLES2HelloAPI_OSX.mm
4
5 @Title        OpenGL ES 2.0 HelloAPI Tutorial
6
7 @Version
8
9 @Copyright    Copyright (c) Imagination Technologies Limited.
10
11 @Platform
12
13 @Description  Basic Tutorial that shows step-by-step how to initialize OpenGL ES 2.0, use it for drawing a triangle and terminate it.
14 Entry Point: main
15
16 *******************************************************************************************************************************************/
17/*******************************************************************************************************************************************
18 Include Files
19 *******************************************************************************************************************************************/
20#include <EGL/egl.h>
21#include <GLES2/gl2.h>
22#import <AppKit/NSApplication.h>
23#import <AppKit/NSWindow.h>
24#import <AppKit/NSScreen.h>
25#import <AppKit/NSView.h>
26
27/*******************************************************************************************************************************************
28 Defines
29 *******************************************************************************************************************************************/
30// Index to bind the attributes to vertex shaders
31#define VERTEX_ARRAY	0
32#define KFPS			120.0
33
34// Width and height of the window
35#define WIDTH  800
36#define HEIGHT 600
37
38/*!*****************************************************************************************************************************************
39 Class AppController
40 *******************************************************************************************************************************************/
41@class AppController;
42
43@interface AppController : NSObject <NSApplicationDelegate>
44{
45@private
46	NSTimer*         m_timer;		// timer for rendering our OpenGL content
47	NSWindow*        m_window;   	// Our window
48	NSView*          m_view;        // Our view
49
50    // Shaders
51    GLuint           m_fragShader;
52    GLuint           m_vertexShader;
53    GLuint           m_program;
54
55    // Vertex buffer objects
56    GLuint           m_vertexBuffer;
57
58    // EGL variables
59    EGLDisplay       m_Display;
60    EGLSurface       m_Surface;
61    EGLContext       m_Context;
62}
63@end
64
65@implementation AppController
66
67/*!*****************************************************************************************************************************************
68 @Function		testGLError
69 @Input			functionLastCalled          Function which triggered the error
70 @Return		True if no GL error was detected
71 @Description	Tests for an GL error and prints it in a message box.
72 *******************************************************************************************************************************************/
73- (BOOL) testGLError:(const char *)functionLastCalled
74{
75	/*	glGetError returns the last error that occurred using OpenGL ES, not necessarily the status of the last called function. The user
76	 has to check after every single OpenGL ES call or at least once every frame. Usually this would be for debugging only, but for this
77	 example it is enabled always
78	 */
79	GLenum lastError = glGetError();
80	if (lastError != GL_NO_ERROR)
81	{
82		NSLog(@"%s failed (%x).\n", functionLastCalled, lastError);
83		return FALSE;
84	}
85
86	return TRUE;
87}
88
89/*!*****************************************************************************************************************************************
90 @Function		testEGLError
91 @Input			functionLastCalled          Function which triggered the error
92 @Return		True if no EGL error was detected
93 @Description	Tests for an EGL error and prints it.
94 *******************************************************************************************************************************************/
95- (BOOL) testEGLError:(const char *)functionLastCalled
96{
97	/*	eglGetError returns the last error that occurred using EGL, not necessarily the status of the last called function. The user has to
98	 check after every single EGL call or at least once every frame. Usually this would be for debugging only, but for this example
99	 it is enabled always.
100	 */
101	EGLint lastError = eglGetError();
102	if (lastError != EGL_SUCCESS)
103	{
104		NSLog(@"%s failed (%x).\n", functionLastCalled, lastError);
105		return FALSE;
106	}
107
108	return TRUE;
109}
110
111/*!*****************************************************************************************************************************************
112 @Function		createEGLDisplay
113 @Output		eglDisplay				    EGLDisplay created
114 @Return		Whether the function succeeded or not.
115 @Description	Creates an EGLDisplay and initialises it.
116 *******************************************************************************************************************************************/
117- (BOOL) createEGLDisplay:(EGLDisplay &)eglDisplay
118{
119	/*	Get an EGL display.
120	 EGL uses the concept of a "display" which in most environments corresponds to a single physical screen. After creating a native
121	 display for a given windowing system, EGL can use this handle to get a corresponding EGLDisplay handle to it for use in rendering.
122	 Should this fail, EGL is usually able to provide access to a default display. For Null window systems, there is no display so NULL
123	 is passed the this function.
124	 */
125	eglDisplay = eglGetDisplay((EGLNativeDisplayType)0);
126	if (eglDisplay == EGL_NO_DISPLAY)
127	{
128		printf("Failed to get an EGLDisplay");
129		return FALSE;
130	}
131
132	/*	Initialize EGL.
133	 EGL has to be initialized with the display obtained in the previous step. All EGL functions other than eglGetDisplay
134	 and eglGetError need an initialised EGLDisplay.
135	 If an application is not interested in the EGL version number it can just pass NULL for the second and third parameters, but they
136	 are queried here for illustration purposes.
137	 */
138	EGLint eglMajorVersion, eglMinorVersion;
139	if (!eglInitialize(eglDisplay, &eglMajorVersion, &eglMinorVersion))
140	{
141		printf("Failed to initialise the EGLDisplay");
142		return FALSE;
143	}
144
145	return TRUE;
146}
147
148/*!*****************************************************************************************************************************************
149 @Function		chooseEGLConfig
150 @Output		eglConfig                   The EGLConfig chosen by the function
151 @Input			eglDisplay                  The EGLDisplay used by the application
152 @Return		Whether the function succeeded or not.
153 @Description	Chooses an appropriate EGLConfig and return it.
154 *******************************************************************************************************************************************/
155- (BOOL) chooseEGLConfig:(EGLConfig &)eglConfig fromDisplay:(EGLDisplay)eglDisplay
156{
157	/*	Specify the required configuration attributes.
158	 An EGL "configuration" describes the capabilities an application requires and the type of surfaces that can be used for drawing.
159	 Each implementation exposes a number of different configurations, and an application needs to describe to EGL what capabilities it
160	 requires so that an appropriate one can be chosen. The first step in doing this is to create an attribute list, which is an array
161	 of key/value pairs which describe particular capabilities requested. In this application nothing special is required so we can query
162	 the minimum of needing it to render to a window, and being OpenGL ES 2.0 capable.
163	 */
164	const EGLint configurationAttributes[] =
165	{
166		EGL_SURFACE_TYPE,		EGL_WINDOW_BIT,
167		EGL_RENDERABLE_TYPE,	EGL_OPENGL_ES2_BIT,
168		EGL_NONE
169	};
170
171	/*	Find a suitable EGLConfig
172	 eglChooseConfig is provided by EGL to provide an easy way to select an appropriate configuration. It takes in the capabilities
173	 specified in the attribute list, and returns a list of available configurations that match or exceed the capabilities requested.
174	 Details of all the possible attributes and how they are selected for by this function are available in the EGL reference pages here:
175	 http://www.khronos.org/registry/egl/sdk/docs/man/xhtml/eglChooseConfig.html
176	 It is also possible to simply get the entire list of configurations and use a custom algorithm to choose a suitable one, as many
177	 advanced applications choose to do. For this application however, taking the first EGLConfig that the function returns suits
178	 its needs perfectly, so we limit it to returning a single EGLConfig.
179	 */
180	EGLint configsReturned;
181	if (!eglChooseConfig(eglDisplay, configurationAttributes, &eglConfig, 1, &configsReturned) || (configsReturned != 1))
182	{
183		printf("Failed to choose a suitable config.");
184		return FALSE;
185	}
186
187	return TRUE;
188}
189
190/*!*****************************************************************************************************************************************
191 @Function		createEGLSurface
192 @Output		eglSurface					The EGLSurface created
193 @Input			eglDisplay                  The EGLDisplay used by the application
194 @Input			eglConfig                   An EGLConfig chosen by the application
195 @Input         view                        The NSView to render to
196 @Return		Whether the function succeeds or not.
197 @Description	Creates an EGLSurface for the screen
198 *******************************************************************************************************************************************/
199- (BOOL) createEGLSurface:(EGLSurface &)eglSurface fromDisplay:(EGLDisplay)eglDisplay withConfig:(EGLConfig)eglConfig
200				 withView:(NSView *)view
201{
202	/*	Create an EGLSurface for rendering.
203	 Using a native window created earlier and a suitable eglConfig, a surface is created that can be used to render OpenGL ES calls to.
204	 There are three main surface types in EGL, which can all be used in the same way once created but work slightly differently:
205	 - Window Surfaces  - These are created from a native window and are drawn to the screen.
206	 - Pixmap Surfaces  - These are created from a native windowing system as well, but are offscreen and are not displayed to the user.
207	 - PBuffer Surfaces - These are created directly within EGL, and like Pixmap Surfaces are offscreen and thus not displayed.
208	 The offscreen surfaces are useful for non-rendering contexts and in certain other scenarios, but for most applications the main
209	 surface used will be a window surface as performed below. For NULL window systems, there are no actual windows, so NULL is passed
210	 to this function.
211	 */
212	eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, (EGLNativeWindowType)view, NULL);
213	if (![self testEGLError:"eglCreateWindowSurface"])
214	{
215		return FALSE;
216	}
217
218	return TRUE;
219}
220
221/*!*****************************************************************************************************************************************
222 @Function		setupEGLContext
223 @Output		eglContext                  The EGLContext created by this function
224 @Input			eglDisplay                  The EGLDisplay used by the application
225 @Input			eglConfig                   An EGLConfig chosen by the application
226 @Input			eglSurface					The EGLSurface created by the application
227 @Return		Whether the function succeeds or not.
228 @Description	Sets up the EGLContext, creating it and then installing it to the current thread.
229 *******************************************************************************************************************************************/
230- (BOOL) setupEGLContext:(EGLContext &)eglContext fromDisplay:(EGLDisplay)eglDisplay withConfig:(EGLConfig)eglConfig
231			 withSurface:(EGLSurface)eglSurface
232{
233	/*	Make OpenGL ES the current API.
234	 EGL needs a way to know that any subsequent EGL calls are going to be affecting OpenGL ES,
235	 rather than any other API (such as OpenVG).
236	 */
237	eglBindAPI(EGL_OPENGL_ES_API);
238	if (![self testEGLError:"eglBindAPI"])
239	{
240		return FALSE;
241	}
242
243	/*	Create a context.
244	 EGL has to create what is known as a context for OpenGL ES. The concept of a context is OpenGL ES's way of encapsulating any
245	 resources and state. What appear to be "global" functions in OpenGL actually only operate on the current context. A context
246	 is required for any operations in OpenGL ES.
247	 Similar to an EGLConfig, a context takes in a list of attributes specifying some of its capabilities. However in most cases this
248	 is limited to just requiring the version of the OpenGL ES context required - In this case, OpenGL ES 2.0.
249	 */
250	EGLint contextAttributes[] =
251	{
252		EGL_CONTEXT_CLIENT_VERSION, 2,
253		EGL_NONE
254	};
255
256	// Create the context with the context attributes supplied
257	eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, contextAttributes);
258	if (![self testEGLError:"eglCreateContext"])
259	{
260		return FALSE;
261	}
262
263	/*	Bind the context to the current thread.
264	 Due to the way OpenGL uses global functions, contexts need to be made current so that any function call can operate on the correct
265	 context. Specifically, make current will bind the context to the thread it's called from, and unbind it from any others. To use
266	 multiple contexts at the same time, users should use multiple threads and synchronise between them.
267	 */
268	eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
269	if (![self testEGLError:"eglMakeCurrent"])
270	{
271		return FALSE;
272	}
273
274	return TRUE;
275}
276
277/*!*****************************************************************************************************************************************
278 @Function		initialiseBuffer
279 @Output		vertexBuffer                Handle to a vertex buffer object
280 @Return		Whether the function succeeds or not.
281 @Description	Initialises shaders, buffers and other state required to begin rendering with OpenGL ES
282 *******************************************************************************************************************************************/
283- (BOOL) initialiseBuffer:(GLuint &)vertexBuffer
284{
285	/*	Concept: Vertices
286	 When rendering a polygon or model to screen, OpenGL ES has to be told where to draw the object, and more fundamentally what shape
287	 it is. The data used to do this is referred to as vertices, points in 3D space which are usually collected into groups of three
288	 to render as triangles. Fundamentally, any advanced 3D shape in OpenGL ES is constructed from a series of these vertices - each
289	 vertex representing one corner of a polygon.
290	 */
291
292	/*	Concept: Buffer Objects
293	 To operate on any data, OpenGL first needs to be able to access it. The GPU maintains a separate pool of memory it uses independent
294	 of the CPU. Whilst on many embedded systems these are in the same physical memory, the distinction exists so that they can use and
295	 allocate memory without having to worry about synchronising with any other processors in the device.
296	 To this end, data needs to be uploaded into buffers, which are essentially a reserved bit of memory for the GPU to use. By creating
297	 a buffer and giving it some data we can tell the GPU how to render a triangle.
298	 */
299
300	// Vertex data containing the positions of each point of the triangle
301	GLfloat vertexData[] = {-0.4f,-0.4f, 0.0f,  // Bottom Left
302		                     0.4f,-0.4f, 0.0f,  // Bottom Right
303		                     0.0f, 0.4f, 0.0f}; // Top Middle
304
305	// Generate a buffer object
306	glGenBuffers(1, &vertexBuffer);
307
308	// Bind buffer as an vertex buffer so we can fill it with data
309	glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
310
311	/*	Set the buffer's size, data and usage
312	 Note the last argument - GL_STATIC_DRAW. This tells the driver that we intend to read from the buffer on the GPU, and don't intend
313	 to modify the data until we're done with it.
314	 */
315	glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
316
317	if (![self testGLError:"glBufferData"])
318	{
319		return FALSE;
320	}
321
322	return TRUE;
323}
324
325/*!*****************************************************************************************************************************************
326 @Function		initialiseShaders
327 @Output		fragmentShader              Handle to a fragment shader
328 @Output		vertexShader                Handle to a vertex shader
329 @Output		shaderProgram               Handle to a shader program containing the fragment and vertex shader
330 @Return		Whether the function succeeds or not.
331 @Description	Initialises shaders, buffers and other state required to begin rendering with OpenGL ES
332 *******************************************************************************************************************************************/
333-(BOOL) initialiseFragmentShader:(GLuint &)fragmentShader andVertexShader:(GLuint &)vertexShader withProgram:(GLuint &)shaderProgram
334{
335	/*	Concept: Shaders
336	 OpenGL ES 2.0 uses what are known as shaders to determine how to draw objects on the screen. Instead of the fixed function
337	 pipeline in early OpenGL or OpenGL ES 1.x, users can now programmatically define how vertices are transformed on screen, what
338	 data is used where, and how each pixel on the screen is coloured.
339	 These shaders are written in GL Shading Language ES: http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf
340	 which is usually abbreviated to simply "GLSL ES".
341	 Each shader is compiled on-device and then linked into a shader program, which combines a vertex and fragment shader into a form
342	 that the OpenGL ES implementation can execute.
343	 */
344
345	/*	Concept: Fragment Shaders
346	 In a final buffer of image data, each individual point is referred to as a pixel. Fragment shaders are the part of the pipeline
347	 which determine how these final pixels are coloured when drawn to the framebuffer. When data is passed through here, the positions
348	 of these pixels is already set, all that's left to do is set the final colour based on any defined inputs.
349	 The reason these are called "fragment" shaders instead of "pixel" shaders is due to a small technical difference between the two
350	 concepts. When you colour a fragment, it may not be the final colour which ends up on screen. This is particularly true when
351	 performing blending, where multiple fragments can contribute to the final pixel colour.
352	 */
353	const char* const fragmentShaderSource = "\
354	void main (void)\
355	{\
356	gl_FragColor = vec4(1.0, 1.0, 0.66 ,1.0);\
357	}";
358
359	// Create a fragment shader object
360	fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
361
362	// Load the source code into it
363	glShaderSource(fragmentShader, 1, (const char**)&fragmentShaderSource, NULL);
364
365	// Compile the source code
366	glCompileShader(fragmentShader);
367
368	// Check that the shader compiled
369	GLint isShaderCompiled;
370	glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &isShaderCompiled);
371	if (!isShaderCompiled)
372	{
373		// If an error happened, first retrieve the length of the log message
374		int infoLogLength, charactersWritten;
375		glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &infoLogLength);
376
377		// Allocate enough space for the message and retrieve it
378		char* infoLog = new char[infoLogLength];
379		glGetShaderInfoLog(fragmentShader, infoLogLength, &charactersWritten, infoLog);
380
381		// Display the error in a dialog box
382		infoLogLength>1 ? printf("%s", infoLog) : printf("Failed to compile fragment shader.");
383
384		delete[] infoLog;
385		return FALSE;
386	}
387
388	/*	Concept: Vertex Shaders
389	 Vertex shaders primarily exist to allow a developer to express how to orient vertices in 3D space, through transformations like
390	 Scaling, Translation or Rotation. Using the same basic layout and structure as a fragment shader, these take in vertex data and
391	 output a fully transformed set of positions. Other inputs are also able to be used such as normals or texture coordinates, and can
392	 also be transformed and output alongside the position data.
393	 */
394	// Vertex shader code
395	const char* const vertexShaderSource = "\
396	attribute highp vec4	myVertex;\
397	uniform mediump mat4	transformationMatrix;\
398	void main(void)\
399	{\
400	gl_Position = transformationMatrix * myVertex;\
401	}";
402
403	// Create a vertex shader object
404	vertexShader = glCreateShader(GL_VERTEX_SHADER);
405
406	// Load the source code into the shader
407	glShaderSource(vertexShader, 1, (const char**)&vertexShaderSource, NULL);
408
409	// Compile the shader
410	glCompileShader(vertexShader);
411
412	// Check the shader has compiled
413	glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &isShaderCompiled);
414	if (!isShaderCompiled)
415	{
416		// If an error happened, first retrieve the length of the log message
417		int infoLogLength, charactersWritten;
418		glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &infoLogLength);
419
420		// Allocate enough space for the message and retrieve it
421		char* infoLog = new char[infoLogLength];
422		glGetShaderInfoLog(vertexShader, infoLogLength, &charactersWritten, infoLog);
423
424		// Display the error in a dialog box
425		infoLogLength>1 ? printf("%s", infoLog) : printf("Failed to compile vertex shader.");
426
427		delete[] infoLog;
428		return FALSE;
429	}
430
431	// Create the shader program
432	shaderProgram = glCreateProgram();
433
434	// Attach the fragment and vertex shaders to it
435	glAttachShader(shaderProgram, fragmentShader);
436	glAttachShader(shaderProgram, vertexShader);
437
438	// Bind the vertex attribute "myVertex" to location VERTEX_ARRAY (0)
439	glBindAttribLocation(shaderProgram, VERTEX_ARRAY, "myVertex");
440
441	// Link the program
442	glLinkProgram(shaderProgram);
443
444	// Check if linking succeeded in the same way we checked for compilation success
445	GLint isLinked;
446	glGetProgramiv(shaderProgram, GL_LINK_STATUS, &isLinked);
447	if (!isLinked)
448	{
449		// If an error happened, first retrieve the length of the log message
450		int infoLogLength, charactersWritten;
451		glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &infoLogLength);
452
453		// Allocate enough space for the message and retrieve it
454		char* infoLog = new char[infoLogLength];
455		glGetProgramInfoLog(shaderProgram, infoLogLength, &charactersWritten, infoLog);
456
457		// Display the error in a dialog box
458		infoLogLength>1 ? printf("%s", infoLog) : printf("Failed to link shader program.");
459
460		delete[] infoLog;
461		return FALSE;
462	}
463
464	/*	Use the Program
465	 Calling glUseProgram tells OpenGL ES that the application intends to use this program for rendering. Now that it's installed into
466	 the current state, any further glDraw* calls will use the shaders contained within it to process scene data. Only one program can
467	 be active at once, so in a multi-program application this function would be called in the render loop. Since this application only
468	 uses one program it can be installed in the current state and left there.
469	 */
470	glUseProgram(shaderProgram);
471
472	if (![self testGLError:"glUseProgram"])
473	{
474		return FALSE;
475	}
476
477	return TRUE;
478}
479
480/*!*****************************************************************************************************************************************
481 @Function		applicationDidFinishLaunching
482 @Input 		notification
483 @Description	Called when the application has finished launching.
484 *******************************************************************************************************************************************/
485- (void) applicationDidFinishLaunching:(NSNotification *)notification
486{
487    // Create our window
488    NSRect frame = NSMakeRect(0,0,WIDTH, HEIGHT);
489    m_window = [[NSWindow alloc] initWithContentRect:frame styleMask:NSMiniaturizableWindowMask | NSTitledWindowMask | NSClosableWindowMask
490											 backing:NSBackingStoreBuffered defer:NO];
491
492    if(!m_window)
493    {
494        NSLog(@"Failed to allocated the window.");
495        [self terminateApp];
496    }
497
498    [m_window setTitle:@"OGLES2HelloAPI"];
499
500    // Create our view
501    m_view = [[NSView alloc] initWithFrame:frame];
502
503    // Now we have a view, add it to our window
504    [m_window setContentView:m_view];
505    [m_window makeKeyAndOrderFront:nil];
506
507    // Add an observer so when our window is closed we terminate the app
508    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(terminateApp) name:NSWindowWillCloseNotification
509											   object:m_window];
510
511    EGLConfig config;
512
513    // Create and Initialise an EGLDisplay
514    if(![self createEGLDisplay:m_Display])
515	{
516		[self terminateApp];
517	}
518
519	// Choose an EGLConfig for the application, used when setting up the rendering surface and EGLContext
520	if(![self chooseEGLConfig:config fromDisplay:m_Display])
521	{
522		[self terminateApp];
523	}
524
525	// Create an EGLSurface for rendering
526	if(![self createEGLSurface:m_Surface fromDisplay:m_Display withConfig:config withView:m_view])
527	{
528		[self terminateApp];
529	}
530
531	// Setup the EGL Context from the other EGL constructs created so far, so that the application is ready to submit OpenGL ES commands
532	if(![self setupEGLContext:m_Context fromDisplay:m_Display withConfig:config withSurface:m_Surface])
533	{
534		[self terminateApp];
535	}
536
537	// Initialise the vertex data in the application
538	if(![self initialiseBuffer:m_vertexBuffer])
539	{
540		[self terminateApp];
541	}
542
543	// Initialise the fragment and vertex shaders used in the application
544	if(![self initialiseFragmentShader:m_fragShader andVertexShader:m_vertexBuffer withProgram:m_program])
545	{
546		[self terminateApp];
547	}
548
549    // Setup a timer to redraw the view at a regular interval
550    m_timer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / KFPS) target:self selector:@selector(renderScene) userInfo:nil repeats:YES];
551}
552
553/*!*****************************************************************************************************************************************
554 @Function		RenderScene
555 @Input			eglDisplay                  The EGLDisplay used by the application
556 @Input			eglSurface					The EGLSurface created by the application
557 @Return		Whether the function succeeds or not.
558 @Description	Renders the scene to the framebuffer. Usually called within a loop.
559 *******************************************************************************************************************************************/
560- (BOOL) renderScene
561{
562	/*	Set the clear color
563	 At the start of a frame, generally you clear the image to tell OpenGL ES that you're done with whatever was there before and want to
564	 draw a new frame. In order to do that however, OpenGL ES needs to know what colour to set in the image's place. glClearColor
565	 sets this value as 4 floating point values between 0.0 and 1.0, as the Red, Green, Blue and Alpha channels. Each value represents
566	 the intensity of the particular channel, with all 0.0 being transparent black, and all 1.0 being opaque white. Subsequent calls to
567	 glClear with the colour bit will clear the frame buffer to this value.
568	 The functions glClearDepth and glClearStencil allow an application to do the same with depth and stencil values respectively.
569	 */
570	glClearColor(0.6f, 0.8f, 1.0f, 1.0f);
571
572	/*	Clears the color buffer.
573	 glClear is used here with the Colour Buffer to clear the colour. It can also be used to clear the depth or stencil buffer using
574	 GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT, respectively.
575	 */
576	glClear(GL_COLOR_BUFFER_BIT);
577
578	// Get the location of the transformation matrix in the shader using its name
579	int matrixLocation = glGetUniformLocation(m_program, "transformationMatrix");
580
581	// Matrix used to specify the orientation of the triangle on screen.
582	const float transformationMatrix[] =
583	{
584		1.0f,0.0f,0.0f,0.0f,
585		0.0f,1.0f,0.0f,0.0f,
586		0.0f,0.0f,1.0f,0.0f,
587		0.0f,0.0f,0.0f,1.0f
588	};
589
590	// Pass the transformationMatrix to the shader using its location
591	glUniformMatrix4fv( matrixLocation, 1, GL_FALSE, transformationMatrix);
592	if (![self testGLError:"glUniformMatrix4fv"])
593	{
594		return FALSE;
595	}
596
597	// Enable the user-defined vertex array
598	glEnableVertexAttribArray(VERTEX_ARRAY);
599
600	// Sets the vertex data to this attribute index, with the number of floats in each position
601	glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, 0, 0);
602	if (![self testGLError:"glVertexAttribPointer"])
603	{
604		return FALSE;
605	}
606
607	/*	Draw the triangle
608	 glDrawArrays is a draw call, and executes the shader program using the vertices and other state set by the user. Draw calls are the
609	 functions which tell OpenGL ES when to actually draw something to the framebuffer given the current state.
610	 glDrawArrays causes the vertices to be submitted sequentially from the position given by the "first" argument until it has processed
611	 "count" vertices. Other draw calls exist, notably glDrawElements which also accepts index data to allow the user to specify that
612	 some vertices are accessed multiple times, without copying the vertex multiple times.
613	 Others include versions of the above that allow the user to draw the same object multiple times with slightly different data, and
614	 a version of glDrawElements which allows a user to restrict the actual indices accessed.
615	 */
616	glDrawArrays(GL_TRIANGLES, 0, 3);
617	if (![self testGLError:"glDrawArrays"])
618	{
619		return FALSE;
620	}
621
622	/*	Present the display data to the screen.
623	 When rendering to a Window surface, OpenGL ES is double buffered. This means that OpenGL ES renders directly to one frame buffer,
624	 known as the back buffer, whilst the display reads from another - the front buffer. eglSwapBuffers signals to the windowing system
625	 that OpenGL ES 2.0 has finished rendering a scene, and that the display should now draw to the screen from the new data. At the same
626	 time, the front buffer is made available for OpenGL ES 2.0 to start rendering to. In effect, this call swaps the front and back
627	 buffers.
628	 */
629	if (!eglSwapBuffers(m_Display, m_Surface) )
630	{
631		[self testGLError:"eglSwapBuffers"];
632		return FALSE;
633	}
634
635	return TRUE;
636}
637
638/*!*****************************************************************************************************************************************
639 @Function		deInitialiseGLState
640 @Description	Releases the resources
641 *******************************************************************************************************************************************/
642- (void) deInitialiseGLState
643{
644	// Frees the OpenGL handles for the program and the 2 shaders
645	glDeleteShader(m_fragShader);
646	glDeleteShader(m_vertexShader);
647	glDeleteProgram(m_program);
648
649	// Delete the VBO as it is no longer needed
650	glDeleteBuffers(1, &m_vertexBuffer);
651}
652
653/*!*****************************************************************************************************************************************
654 @Function		releaseEGLState
655 @Input			eglDisplay                   The EGLDisplay used by the application
656 @Description	Releases all resources allocated by EGL
657 *******************************************************************************************************************************************/
658- (void) releaseEGLState:(EGLDisplay)eglDisplay
659{
660	// To release the resources in the context, first the context has to be released from its binding with the current thread.
661	eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
662
663	// Terminate the display, and any resources associated with it (including the EGLContext)
664	eglTerminate(eglDisplay);
665}
666
667/*!*****************************************************************************************************************************************
668 @Function		applicationWillTerminate
669 @Description   Called when the app is about to terminate.
670 *******************************************************************************************************************************************/
671- (void) applicationWillTerminate:(NSNotification *)notification
672{
673    // Release our timer
674    [m_timer invalidate];
675
676	[self deInitialiseGLState];
677	[self releaseEGLState:m_Display];
678
679    // Release our view and window
680    [m_view release];
681    m_view = nil;
682
683    [m_window release];
684    m_window = nil;
685}
686
687/*!*****************************************************************************************************************************************
688 @Function		terminateApp
689 @Description   Attempts to immediately terminate the application.
690 *******************************************************************************************************************************************/
691- (void) terminateApp
692{
693    [NSApp terminate:nil];
694}
695
696@end
697
698/*!*****************************************************************************************************************************************
699 @Function		main
700 @Input			argc           Number of arguments passed to the application, ignored.
701 @Input			argv           Command line strings passed to the application, ignored.
702 @Return		Result code to send to the Operating System
703 @Description	Main function of the program, executes other functions.
704 *******************************************************************************************************************************************/
705int main(int argc, char **argv)
706{
707	return NSApplicationMain(argc, (const char **)argv);
708}
709
710