Home | History | Annotate | Download | only in OGLES2
      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  *******************************************************************************************************************************************/
    705 int main(int argc, char **argv)
    706 {
    707 	return NSApplicationMain(argc, (const char **)argv);
    708 }
    709 
    710