• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************************************************************************
2 
3  @File         OGLES2HelloAPI_LinuxX11.cpp
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 <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include "X11/Xlib.h"
24 #include "X11/Xutil.h"
25 
26 #include <EGL/egl.h>
27 #include <GLES2/gl2.h>
28 
29 /*******************************************************************************************************************************************
30  Defines
31 *******************************************************************************************************************************************/
32 // Name of the application
33 #define APPLICATION_NAME "HelloAPI"
34 
35 // Width and height of the window
36 #define WINDOW_WIDTH	800
37 #define WINDOW_HEIGHT	600
38 
39 // Index to bind the attributes to vertex shaders
40 #define VERTEX_ARRAY	0
41 
42 /*******************************************************************************************************************************************
43  Helper Functions
44 *******************************************************************************************************************************************/
45 
46 /*!*****************************************************************************************************************************************
47  @Function		TestEGLError
48  @Input			functionLastCalled          Function which triggered the error
49  @Return		True if no EGL error was detected
50  @Description	Tests for an EGL error and prints it.
51 *******************************************************************************************************************************************/
TestEGLError(const char * functionLastCalled)52 bool TestEGLError(const char* functionLastCalled)
53 {
54 	/*	eglGetError returns the last error that occurred using EGL, not necessarily the status of the last called function. The user has to
55 		check after every single EGL call or at least once every frame. Usually this would be for debugging only, but for this example
56 		it is enabled always.
57 	*/
58 	EGLint lastError = eglGetError();
59 	if (lastError != EGL_SUCCESS)
60 	{
61 		printf("%s failed (%x).\n", functionLastCalled, lastError);
62 		return false;
63 	}
64 
65 	return true;
66 }
67 
68 /*!*****************************************************************************************************************************************
69  @Function		HandleX11Errors
70  @Input			nativeDisplay               Handle to the display
71  @Input			error                       The error event to handle
72  @Return		Result code to send to the X window system
73  @Description	Processes event messages for the main window
74 *******************************************************************************************************************************************/
HandleX11Errors(Display * nativeDisplay,XErrorEvent * error)75 int HandleX11Errors(Display *nativeDisplay, XErrorEvent *error)
76 {
77 	// Get the X Error
78 	char errorStringBuffer[256];
79 	XGetErrorText(nativeDisplay, error->error_code, errorStringBuffer, 256);
80 
81 	// Print the error
82 	printf("%s", errorStringBuffer);
83 
84 	// Exit the application
85 	exit(-1);
86 
87 	return 0;
88 }
89 
90 /*!*****************************************************************************************************************************************
91  @Function		TestGLError
92  @Input			functionLastCalled          Function which triggered the error
93  @Return		True if no GL error was detected
94  @Description	Tests for an GL error and prints it in a message box.
95 *******************************************************************************************************************************************/
TestGLError(const char * functionLastCalled)96 bool TestGLError(const char* functionLastCalled)
97 {
98 	/*	glGetError returns the last error that occurred using OpenGL ES, not necessarily the status of the last called function. The user
99 		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
100 		example it is enabled always
101 	*/
102 	GLenum lastError = glGetError();
103 	if (lastError != GL_NO_ERROR)
104 	{
105 		printf("%s failed (%x).\n", functionLastCalled, lastError);
106 		return false;
107 	}
108 
109 	return true;
110 }
111 
112 /*******************************************************************************************************************************************
113  Application Functions
114 *******************************************************************************************************************************************/
115 
116 /*!*****************************************************************************************************************************************
117  @Function		CreateNativeDisplay
118  @Output		nativeDisplay				Native display to create
119  @Return		Whether the function succeeded or not.
120  @Description	Creates a native isplay for the application to render into.
121 *******************************************************************************************************************************************/
CreateNativeDisplay(Display ** nativeDisplay)122 bool CreateNativeDisplay(Display** nativeDisplay)
123 {
124 	// Check for a valid display
125 	if (!nativeDisplay)
126 	{
127 		return false;
128 	}
129 
130 	// Open the display
131 	*nativeDisplay = XOpenDisplay( 0 );
132 	if (!*nativeDisplay)
133 	{
134 		printf("Error: Unable to open X display\n");
135 		return false;
136 	}
137 
138 	return true;
139 }
140 
141 /*!*****************************************************************************************************************************************
142  @Function		CreateNativeWindow
143  @Input			nativeDisplay				Native display used by the application
144  @Output		nativeWindow			    Native window type to create
145  @Return		Whether the function succeeded or not.
146  @Description	Creates a native window for the application to render into.
147 *******************************************************************************************************************************************/
CreateNativeWindow(Display * nativeDisplay,Window * nativeWindow)148 bool CreateNativeWindow(Display* nativeDisplay, Window* nativeWindow)
149 {
150 	// Get the default screen for the display
151 	int defaultScreen = XDefaultScreen(nativeDisplay);
152 
153 	// Get the default depth of the display
154 	int defaultDepth = DefaultDepth(nativeDisplay, defaultScreen);
155 
156 	// Select a visual info
157 	XVisualInfo* visualInfo = new XVisualInfo;
158 	XMatchVisualInfo( nativeDisplay, defaultScreen, defaultDepth, TrueColor, visualInfo);
159 	if (!visualInfo)
160 	{
161 		printf("Error: Unable to acquire visual\n");
162 		return false;
163 	}
164 
165 	// Get the root window for the display and default screen
166 	Window rootWindow = RootWindow(nativeDisplay, defaultScreen);
167 
168 	// Create a colour map from the display, root window and visual info
169 	Colormap colourMap = XCreateColormap(nativeDisplay, rootWindow, visualInfo->visual, AllocNone);
170 
171 	// Now setup the final window by specifying some attributes
172 	XSetWindowAttributes windowAttributes;
173 
174 	// Set the colour map that was just created
175 	windowAttributes.colormap = colourMap;
176 
177 	// Set events that will be handled by the app, add to these for other events.
178 	windowAttributes.event_mask = StructureNotifyMask | ExposureMask | ButtonPressMask;
179 
180 	// Create the window
181 	*nativeWindow =XCreateWindow(nativeDisplay,               // The display used to create the window
182 	                             rootWindow,                   // The parent (root) window - the desktop
183 						  		 0,                            // The horizontal (x) origin of the window
184 								 0,                            // The vertical (y) origin of the window
185 								 WINDOW_WIDTH,                 // The width of the window
186 								 WINDOW_HEIGHT,                // The height of the window
187 								 0,                            // Border size - set it to zero
188 	                             visualInfo->depth,            // Depth from the visual info
189 								 InputOutput,                  // Window type - this specifies InputOutput.
190 								 visualInfo->visual,           // Visual to use
191 								 CWEventMask | CWColormap,     // Mask specifying these have been defined in the window attributes
192 								 &windowAttributes);           // Pointer to the window attribute structure
193 
194 	// Make the window viewable by mapping it to the display
195 	XMapWindow(nativeDisplay, *nativeWindow);
196 
197 	// Set the window title
198 	XStoreName(nativeDisplay, *nativeWindow, APPLICATION_NAME);
199 
200 	// Setup the window manager protocols to handle window deletion events
201 	Atom windowManagerDelete = XInternAtom(nativeDisplay, "WM_DELETE_WINDOW", True);
202 	XSetWMProtocols(nativeDisplay, *nativeWindow, &windowManagerDelete , 1);
203 
204 	// Delete the visual info
205 	delete visualInfo;
206 
207 	return true;
208 }
209 
210 /*!*****************************************************************************************************************************************
211  @Function		CreateEGLDisplay
212  @Input			nativeDisplay               The native display used by the application
213  @Output		eglDisplay				    EGLDisplay created from nativeDisplay
214  @Return		Whether the function succeeded or not.
215  @Description	Creates an EGLDisplay from a native native display, and initialises it.
216 *******************************************************************************************************************************************/
CreateEGLDisplay(Display * nativeDisplay,EGLDisplay & eglDisplay)217 bool CreateEGLDisplay( Display* nativeDisplay, EGLDisplay &eglDisplay )
218 {
219 	/*	Get an EGL display.
220 		EGL uses the concept of a "display" which in most environments corresponds to a single physical screen. After creating a native
221 		display for a given windowing system, EGL can use this handle to get a corresponding EGLDisplay handle to it for use in rendering.
222 		Should this fail, EGL is usually able to provide access to a default display.
223 	*/
224 	eglDisplay = eglGetDisplay((EGLNativeDisplayType)nativeDisplay);
225 	// If a display couldn't be obtained, return an error.
226 	if (eglDisplay == EGL_NO_DISPLAY)
227 	{
228 		printf("Failed to get an EGLDisplay");
229 		return false;
230 	}
231 
232 	/*	Initialize EGL.
233 		EGL has to be initialized with the display obtained in the previous step. All EGL functions other than eglGetDisplay
234 		and eglGetError need an initialised EGLDisplay.
235 		If an application is not interested in the EGL version number it can just pass NULL for the second and third parameters, but they
236 		are queried here for illustration purposes.
237 	*/
238 	EGLint eglMajorVersion, eglMinorVersion;
239 	if (!eglInitialize(eglDisplay, &eglMajorVersion, &eglMinorVersion))
240 	{
241 		printf("Failed to initialise the EGLDisplay");
242 		return false;
243 	}
244 
245 	return true;
246 }
247 
248 /*!*****************************************************************************************************************************************
249  @Function		ChooseEGLConfig
250  @Input			eglDisplay                  The EGLDisplay used by the application
251  @Output		eglConfig                   The EGLConfig chosen by the function
252  @Return		Whether the function succeeded or not.
253  @Description	Chooses an appropriate EGLConfig and return it.
254 *******************************************************************************************************************************************/
ChooseEGLConfig(EGLDisplay eglDisplay,EGLConfig & eglConfig)255 bool ChooseEGLConfig( EGLDisplay eglDisplay, EGLConfig& eglConfig )
256 {
257 	/*	Specify the required configuration attributes.
258 		An EGL "configuration" describes the capabilities an application requires and the type of surfaces that can be used for drawing.
259 		Each implementation exposes a number of different configurations, and an application needs to describe to EGL what capabilities it
260 		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
261 		of key/value pairs which describe particular capabilities requested. In this application nothing special is required so we can query
262 		the minimum of needing it to render to a window, and being OpenGL ES 2.0 capable.
263 	*/
264 	const EGLint configurationAttributes[] =
265 	{
266 		EGL_SURFACE_TYPE,		EGL_WINDOW_BIT,
267 		EGL_RENDERABLE_TYPE,	EGL_OPENGL_ES2_BIT,
268 		EGL_NONE
269 	};
270 
271 	/*	Find a suitable EGLConfig
272 		eglChooseConfig is provided by EGL to provide an easy way to select an appropriate configuration. It takes in the capabilities
273 		specified in the attribute list, and returns a list of available configurations that match or exceed the capabilities requested.
274 		Details of all the possible attributes and how they are selected for by this function are available in the EGL reference pages here:
275 		http://www.khronos.org/registry/egl/sdk/docs/man/xhtml/eglChooseConfig.html
276 		It is also possible to simply get the entire list of configurations and use a custom algorithm to choose a suitable one, as many
277 		advanced applications choose to do. For this application however, taking the first EGLConfig that the function returns suits
278 		its needs perfectly, so we limit it to returning a single EGLConfig.
279 	*/
280 	EGLint configsReturned;
281 	if (!eglChooseConfig(eglDisplay, configurationAttributes, &eglConfig, 1, &configsReturned) || (configsReturned != 1))
282 	{
283 		printf("Failed to choose a suitable config.");
284 		return false;
285 	}
286 
287 	return true;
288 }
289 
290 /*!*****************************************************************************************************************************************
291  @Function		CreateEGLSurface
292  @Input			nativeWindow                A native window that's been created
293  @Input			eglDisplay                  The EGLDisplay used by the application
294  @Input			eglConfig                   An EGLConfig chosen by the application
295  @Output		eglSurface					The EGLSurface created from the native window.
296  @Return		Whether the function succeeds or not.
297  @Description	Creates an EGLSurface from a native window
298 *******************************************************************************************************************************************/
CreateEGLSurface(Window nativeWindow,EGLDisplay eglDisplay,EGLConfig eglConfig,EGLSurface & eglSurface)299 bool CreateEGLSurface( Window nativeWindow, EGLDisplay eglDisplay, EGLConfig eglConfig, EGLSurface& eglSurface)
300 {
301 	/*	Create an EGLSurface for rendering.
302 		Using a native window created earlier and a suitable eglConfig, a surface is created that can be used to render OpenGL ES calls to.
303 		There are three main surface types in EGL, which can all be used in the same way once created but work slightly differently:
304 		 - Window Surfaces  - These are created from a native window and are drawn to the screen.
305 		 - Pixmap Surfaces  - These are created from a native windowing system as well, but are offscreen and are not displayed to the user.
306 		 - PBuffer Surfaces - These are created directly within EGL, and like Pixmap Surfaces are offscreen and thus not displayed.
307 		The offscreen surfaces are useful for non-rendering contexts and in certain other scenarios, but for most applications the main
308 		surface used will be a window surface as performed below.
309 	*/
310 	eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, (EGLNativeWindowType)nativeWindow, NULL);
311 	if (!TestEGLError("eglCreateWindowSurface"))
312 	{
313 		return false;
314 	}
315 
316 	return true;
317 }
318 
319 /*!*****************************************************************************************************************************************
320  @Function		SetupEGLContext
321  @Input			eglDisplay                  The EGLDisplay used by the application
322  @Input			eglConfig                   An EGLConfig chosen by the application
323  @Input			eglSurface					The EGLSurface created from the native window.
324  @Output		eglContext                  The EGLContext created by this function
325  @Input			nativeWindow                A native window, used to display error messages
326  @Return		Whether the function succeeds or not.
327  @Description	Sets up the EGLContext, creating it and then installing it to the current thread.
328 *******************************************************************************************************************************************/
SetupEGLContext(EGLDisplay eglDisplay,EGLConfig eglConfig,EGLSurface eglSurface,EGLContext & eglContext)329 bool SetupEGLContext( EGLDisplay eglDisplay, EGLConfig eglConfig, EGLSurface eglSurface, EGLContext& eglContext )
330 {
331 	/*	Create a context.
332 		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
333 		resources and state. What appear to be "global" functions in OpenGL actually only operate on the current context. A context
334 		is required for any operations in OpenGL ES.
335 		Similar to an EGLConfig, a context takes in a list of attributes specifying some of its capabilities. However in most cases this
336 		is limited to just requiring the version of the OpenGL ES context required - In this case, OpenGL ES 2.0.
337 	*/
338 	EGLint contextAttributes[] =
339 	{
340 		EGL_CONTEXT_CLIENT_VERSION, 2,
341 		EGL_NONE
342 	};
343 
344 	// Create the context with the context attributes supplied
345 	eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, contextAttributes);
346 	if (!TestEGLError("eglCreateContext"))
347 	{
348 		return false;
349 	}
350 
351 	/*	Make OpenGL ES the current API.
352 		After creating the context, EGL needs a way to know that any subsequent EGL calls are going to be affecting OpenGL ES,
353 		rather than any other API (such as OpenVG).
354 	*/
355 	eglBindAPI(EGL_OPENGL_ES_API);
356 	if (!TestEGLError("eglBindAPI"))
357 	{
358 		return false;
359 	}
360 
361 	/*	Bind the context to the current thread.
362 		Due to the way OpenGL uses global functions, contexts need to be made current so that any function call can operate on the correct
363 		context. Specifically, make current will bind the context to the thread it's called from, and unbind it from any others. To use
364 		multiple contexts at the same time, users should use multiple threads and synchronise between them.
365 	*/
366 	eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
367 	if (!TestEGLError("eglMakeCurrent"))
368 	{
369 		return false;
370 	}
371 
372 	return true;
373 }
374 
375 /*!*****************************************************************************************************************************************
376  @Function		InitialiseBuffer
377  @Output		vertexBuffer                Handle to a vertex buffer object
378  @Return		Whether the function succeeds or not.
379  @Description	Initialises shaders, buffers and other state required to begin rendering with OpenGL ES
380 *******************************************************************************************************************************************/
InitialiseBuffer(GLuint & vertexBuffer)381 bool InitialiseBuffer(GLuint &vertexBuffer)
382 {
383 	/*	Concept: Vertices
384 		When rendering a polygon or model to screen, OpenGL ES has to be told where to draw the object, and more fundamentally what shape
385 		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
386 		to render as triangles. Fundamentally, any advanced 3D shape in OpenGL ES is constructed from a series of these vertices - each
387 		vertex representing one corner of a polygon.
388 	*/
389 
390 	/*	Concept: Buffer Objects
391 		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
392 		of the CPU. Whilst on many embedded systems these are in the same physical memory, the distinction exists so that they can use and
393 		allocate memory without having to worry about synchronising with any other processors in the device.
394 		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
395 		a buffer and giving it some data we can tell the GPU how to render a triangle.
396 	*/
397 
398 	// Vertex data containing the positions of each point of the triangle
399 	GLfloat vertexData[] = {-0.4f,-0.4f, 0.0f,  // Bottom Left
400 	                         0.4f,-0.4f, 0.0f,  // Bottom Right
401 	                         0.0f, 0.4f, 0.0f}; // Top Middle
402 
403 	// Generate a buffer object
404 	glGenBuffers(1, &vertexBuffer);
405 
406 	// Bind buffer as an vertex buffer so we can fill it with data
407 	glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
408 
409 	/*	Set the buffer's size, data and usage
410 		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
411 		to modify the data until we're done with it.
412 	*/
413 	glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
414 
415 	if (!TestGLError("glBufferData"))
416 	{
417 		return false;
418 	}
419 
420 	return true;
421 }
422 
423 /*!*****************************************************************************************************************************************
424  @Function		InitialiseShaders
425  @Output		fragmentShader              Handle to a fragment shader
426  @Output		vertexShader                Handle to a vertex shader
427  @Output		shaderProgram               Handle to a shader program containing the fragment and vertex shader
428  @Return		Whether the function succeeds or not.
429  @Description	Initialises shaders, buffers and other state required to begin rendering with OpenGL ES
430 *******************************************************************************************************************************************/
InitialiseShaders(GLuint & fragmentShader,GLuint & vertexShader,GLuint & shaderProgram)431 bool InitialiseShaders( GLuint &fragmentShader, GLuint &vertexShader, GLuint &shaderProgram)
432 {
433 	/*	Concept: Shaders
434 		OpenGL ES 2.0 uses what are known as shaders to determine how to draw objects on the screen. Instead of the fixed function
435 		pipeline in early OpenGL or OpenGL ES 1.x, users can now programmatically define how vertices are transformed on screen, what
436 		data is used where, and how each pixel on the screen is coloured.
437 		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
438 		which is usually abbreviated to simply "GLSL ES".
439 		Each shader is compiled on-device and then linked into a shader program, which combines a vertex and fragment shader into a form
440 		that the OpenGL ES implementation can execute.
441 	*/
442 
443 	/*	Concept: Fragment Shaders
444 		In a final buffer of image data, each individual point is referred to as a pixel. Fragment shaders are the part of the pipeline
445 		which determine how these final pixels are coloured when drawn to the framebuffer. When data is passed through here, the positions
446 		of these pixels is already set, all that's left to do is set the final colour based on any defined inputs.
447 		The reason these are called "fragment" shaders instead of "pixel" shaders is due to a small technical difference between the two
448 		concepts. When you colour a fragment, it may not be the final colour which ends up on screen. This is particularly true when
449 		performing blending, where multiple fragments can contribute to the final pixel colour.
450 	*/
451 	const char* const fragmentShaderSource = "\
452 											 void main (void)\
453 											 {\
454 											 gl_FragColor = vec4(1.0, 1.0, 0.66 ,1.0);\
455 											 }";
456 
457 	// Create a fragment shader object
458 	fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
459 
460 	// Load the source code into it
461 	glShaderSource(fragmentShader, 1, (const char**)&fragmentShaderSource, NULL);
462 
463 	// Compile the source code
464 	glCompileShader(fragmentShader);
465 
466 	// Check that the shader compiled
467 	GLint isShaderCompiled;
468 	glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &isShaderCompiled);
469 	if (!isShaderCompiled)
470 	{
471 		// If an error happened, first retrieve the length of the log message
472 		int infoLogLength, charactersWritten;
473 		glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &infoLogLength);
474 
475 		// Allocate enough space for the message and retrieve it
476 		char* infoLog = new char[infoLogLength];
477 		glGetShaderInfoLog(fragmentShader, infoLogLength, &charactersWritten, infoLog);
478 
479 		// Display the error in a dialog box
480 		infoLogLength>1 ? printf("%s", infoLog) : printf("Failed to compile fragment shader.");
481 
482 		delete[] infoLog;
483 		return false;
484 	}
485 
486 	/*	Concept: Vertex Shaders
487 		Vertex shaders primarily exist to allow a developer to express how to orient vertices in 3D space, through transformations like
488 		Scaling, Translation or Rotation. Using the same basic layout and structure as a fragment shader, these take in vertex data and
489 		output a fully transformed set of positions. Other inputs are also able to be used such as normals or texture coordinates, and can
490 		also be transformed and output alongside the position data.
491 	*/
492 	// Vertex shader code
493 	const char* const vertexShaderSource = "\
494 										   attribute highp vec4	myVertex;\
495 										   uniform mediump mat4	transformationMatrix;\
496 										   void main(void)\
497 										   {\
498 										   gl_Position = transformationMatrix * myVertex;\
499 										   }";
500 
501 	// Create a vertex shader object
502 	vertexShader = glCreateShader(GL_VERTEX_SHADER);
503 
504 	// Load the source code into the shader
505 	glShaderSource(vertexShader, 1, (const char**)&vertexShaderSource, NULL);
506 
507 	// Compile the shader
508 	glCompileShader(vertexShader);
509 
510 	// Check the shader has compiled
511 	glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &isShaderCompiled);
512 	if (!isShaderCompiled)
513 	{
514 		// If an error happened, first retrieve the length of the log message
515 		int infoLogLength, charactersWritten;
516 		glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &infoLogLength);
517 
518 		// Allocate enough space for the message and retrieve it
519 		char* infoLog = new char[infoLogLength];
520 		glGetShaderInfoLog(vertexShader, infoLogLength, &charactersWritten, infoLog);
521 
522 		// Display the error in a dialog box
523 		infoLogLength>1 ? printf("%s", infoLog) : printf("Failed to compile vertex shader.");
524 
525 		delete[] infoLog;
526 		return false;
527 	}
528 
529 	// Create the shader program
530 	shaderProgram = glCreateProgram();
531 
532 	// Attach the fragment and vertex shaders to it
533 	glAttachShader(shaderProgram, fragmentShader);
534 	glAttachShader(shaderProgram, vertexShader);
535 
536 	// Bind the vertex attribute "myVertex" to location VERTEX_ARRAY (0)
537 	glBindAttribLocation(shaderProgram, VERTEX_ARRAY, "myVertex");
538 
539 	// Link the program
540 	glLinkProgram(shaderProgram);
541 
542 	// Check if linking succeeded in the same way we checked for compilation success
543 	GLint isLinked;
544 	glGetProgramiv(shaderProgram, GL_LINK_STATUS, &isLinked);
545 	if (!isLinked)
546 	{
547 		// If an error happened, first retrieve the length of the log message
548 		int infoLogLength, charactersWritten;
549 		glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &infoLogLength);
550 
551 		// Allocate enough space for the message and retrieve it
552 		char* infoLog = new char[infoLogLength];
553 		glGetProgramInfoLog(shaderProgram, infoLogLength, &charactersWritten, infoLog);
554 
555 		// Display the error in a dialog box
556 		infoLogLength>1 ? printf("%s", infoLog) : printf("Failed to link shader program.");
557 
558 		delete[] infoLog;
559 		return false;
560 	}
561 
562 	/*	Use the Program
563 		Calling glUseProgram tells OpenGL ES that the application intends to use this program for rendering. Now that it's installed into
564 		the current state, any further glDraw* calls will use the shaders contained within it to process scene data. Only one program can
565 		be active at once, so in a multi-program application this function would be called in the render loop. Since this application only
566 		uses one program it can be installed in the current state and left there.
567 	*/
568 	glUseProgram(shaderProgram);
569 
570 	if (!TestGLError("glUseProgram"))
571 	{
572 		return false;
573 	}
574 
575 	return true;
576 }
577 
578 /*!*****************************************************************************************************************************************
579  @Function		RenderScene
580  @Input			shaderProgram               The shader program used to render the scene
581  @Input			eglDisplay                  The EGLDisplay used by the application
582  @Input			eglSurface					The EGLSurface created from the native window.
583  @Input			nativeDisplay				The native display used by the application
584  @Return		Whether the function succeeds or not.
585  @Description	Renders the scene to the framebuffer. Usually called within a loop.
586 *******************************************************************************************************************************************/
RenderScene(GLuint shaderProgram,EGLDisplay eglDisplay,EGLSurface eglSurface,Display * nativeDisplay)587 bool RenderScene( GLuint shaderProgram, EGLDisplay eglDisplay, EGLSurface eglSurface, Display* nativeDisplay )
588 {
589 	/*	Set the clear color
590 		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
591 		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
592 		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
593 		the intensity of the particular channel, with all 0.0 being transparent black, and all 1.0 being opaque white. Subsequent calls to
594 		glClear with the colour bit will clear the frame buffer to this value.
595 		The functions glClearDepth and glClearStencil allow an application to do the same with depth and stencil values respectively.
596 	*/
597 	glClearColor(0.6f, 0.8f, 1.0f, 1.0f);
598 
599 	/*	Clears the color buffer.
600 		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
601 		GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT, respectively.
602 	*/
603 	glClear(GL_COLOR_BUFFER_BIT);
604 
605 	// Get the location of the transformation matrix in the shader using its name
606 	int matrixLocation = glGetUniformLocation(shaderProgram, "transformationMatrix");
607 
608 	// Matrix used to specify the orientation of the triangle on screen.
609 	const float transformationMatrix[] =
610 	{
611 		1.0f,0.0f,0.0f,0.0f,
612 		0.0f,1.0f,0.0f,0.0f,
613 		0.0f,0.0f,1.0f,0.0f,
614 		0.0f,0.0f,0.0f,1.0f
615 	};
616 
617 	// Pass the transformationMatrix to the shader using its location
618 	glUniformMatrix4fv( matrixLocation, 1, GL_FALSE, transformationMatrix);
619 	if (!TestGLError("glUniformMatrix4fv"))
620 	{
621 		return false;
622 	}
623 
624 	// Enable the user-defined vertex array
625 	glEnableVertexAttribArray(VERTEX_ARRAY);
626 
627 	// Sets the vertex data to this attribute index, with the number of floats in each position
628 	glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, 0, 0);
629 	if (!TestGLError("glVertexAttribPointer"))
630 	{
631 		return false;
632 	}
633 
634 	/*	Draw the triangle
635 		glDrawArrays is a draw call, and executes the shader program using the vertices and other state set by the user. Draw calls are the
636 		functions which tell OpenGL ES when to actually draw something to the framebuffer given the current state.
637 		glDrawArrays causes the vertices to be submitted sequentially from the position given by the "first" argument until it has processed
638 		"count" vertices. Other draw calls exist, notably glDrawElements which also accepts index data to allow the user to specify that
639 		some vertices are accessed multiple times, without copying the vertex multiple times.
640 		Others include versions of the above that allow the user to draw the same object multiple times with slightly different data, and
641 		a version of glDrawElements which allows a user to restrict the actual indices accessed.
642 	*/
643 	glDrawArrays(GL_TRIANGLES, 0, 3);
644 	if (!TestGLError("glDrawArrays"))
645 	{
646 		return false;
647 	}
648 
649 	/*	Present the display data to the screen.
650 		When rendering to a Window surface, OpenGL ES is double buffered. This means that OpenGL ES renders directly to one frame buffer,
651 		known as the back buffer, whilst the display reads from another - the front buffer. eglSwapBuffers signals to the windowing system
652 		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
653 		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
654 		buffers.
655 	*/
656 	if (!eglSwapBuffers(eglDisplay, eglSurface) )
657 	{
658 		TestEGLError("eglSwapBuffers");
659 		return false;
660 	}
661 
662 	// Check for messages from the windowing system.
663 	int numberOfMessages = XPending(nativeDisplay);
664 	for( int i = 0; i < numberOfMessages; i++ )
665 	{
666 		XEvent event;
667 		XNextEvent(nativeDisplay, &event);
668 
669 		switch( event.type )
670 		{
671 			// Exit on window close
672 		case ClientMessage:
673 			// Exit on mouse click
674 		case ButtonPress:
675 		case DestroyNotify:
676 			return false;
677 		default:
678 			break;
679 		}
680 	}
681 
682 	return true;
683 }
684 
685 /*!*****************************************************************************************************************************************
686  @Function		DeInitialiseGLState
687  @Input			fragmentShader              Handle to a fragment shader
688  @Input			vertexShader                Handle to a vertex shader
689  @Input			shaderProgram               Handle to a shader program containing the fragment and vertex shader
690  @Input			vertexBuffer                Handle to a vertex buffer object
691  @Description	Releases the resources created by "InitialiseGLState"
692 *******************************************************************************************************************************************/
DeInitialiseGLState(GLuint fragmentShader,GLuint vertexShader,GLuint shaderProgram,GLuint vertexBuffer)693 void DeInitialiseGLState( GLuint fragmentShader, GLuint vertexShader, GLuint shaderProgram, GLuint vertexBuffer )
694 {
695 	// Frees the OpenGL handles for the program and the 2 shaders
696 	glDeleteShader(fragmentShader);
697 	glDeleteShader(vertexShader);
698 	glDeleteProgram(shaderProgram);
699 
700 	// Delete the VBO as it is no longer needed
701 	glDeleteBuffers(1, &vertexBuffer);
702 }
703 
704 /*!*****************************************************************************************************************************************
705  @Function		ReleaseEGLState
706  @Input			eglDisplay                   The EGLDisplay used by the application
707  @Description	Releases all resources allocated by EGL
708 *******************************************************************************************************************************************/
ReleaseEGLState(EGLDisplay eglDisplay)709 void ReleaseEGLState(EGLDisplay eglDisplay)
710 {
711 	if(eglDisplay != NULL)
712 	{
713 		// To release the resources in the context, first the context has to be released from its binding with the current thread.
714 		eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
715 
716 		// Terminate the display, and any resources associated with it (including the EGLContext)
717 		eglTerminate(eglDisplay);
718 	}
719 }
720 
721 /*!*****************************************************************************************************************************************
722  @Function		ReleaseWindowAndDisplay
723  @Input			nativeDisplay               The native display to release
724  @Input			nativeWindow                The native window to destroy
725  @Description	Releases all resources allocated by the windowing system
726 *******************************************************************************************************************************************/
ReleaseNativeResources(Display * nativeDisplay,Window nativeWindow)727 void ReleaseNativeResources(Display* nativeDisplay, Window nativeWindow)
728 {
729 	// Destroy the window
730 	if (nativeWindow)
731 	{
732 		XDestroyWindow(nativeDisplay, nativeWindow);
733 	}
734 
735 	// Release the display.
736 	if (nativeDisplay)
737 	{
738 		XCloseDisplay(nativeDisplay);
739 	}
740 }
741 
742 /*!*****************************************************************************************************************************************
743  @Function		main
744  @Input			argc                        Number of arguments passed to the application, ignored.
745  @Input			argv           Command line strings passed to the application, ignored.
746  @Return		Result code to send to the Operating System
747  @Description	Main function of the program, executes other functions.
748 *******************************************************************************************************************************************/
main(int,char **)749 int main(int /*argc*/, char **/*argv*/)
750 {
751 	// X11 variables
752 	Display* nativeDisplay = NULL;
753 	Window nativeWindow = 0;
754 
755 	// EGL variables
756 	EGLDisplay			eglDisplay = NULL;
757 	EGLConfig			eglConfig = NULL;
758 	EGLSurface			eglSurface = NULL;
759 	EGLContext			eglContext = NULL;
760 
761 	// Handles for the two shaders used to draw the triangle, and the program handle which combines them.
762 	GLuint fragmentShader = 0, vertexShader = 0;
763 	GLuint shaderProgram = 0;
764 
765 	// A vertex buffer object to store our model data.
766 	GLuint vertexBuffer = 0;
767 
768 	// Get access to a native display
769 	if (!CreateNativeDisplay(&nativeDisplay))
770 	{
771 		goto cleanup;
772 	}
773 
774 	// Setup the windowing system, create a window
775 	if (!CreateNativeWindow(nativeDisplay, &nativeWindow))
776 	{
777 		goto cleanup;
778 	}
779 
780 	// Create and Initialise an EGLDisplay from the native display
781 	if (!CreateEGLDisplay(nativeDisplay, eglDisplay))
782 	{
783 		goto cleanup;
784 	}
785 
786 	// Choose an EGLConfig for the application, used when setting up the rendering surface and EGLContext
787 	if (!ChooseEGLConfig(eglDisplay, eglConfig))
788 	{
789 		goto cleanup;
790 	}
791 
792 	// Create an EGLSurface for rendering from the native window
793 	if (!CreateEGLSurface(nativeWindow, eglDisplay, eglConfig, eglSurface))
794 	{
795 		goto cleanup;
796 	}
797 
798 	// Setup the EGL Context from the other EGL constructs created so far, so that the application is ready to submit OpenGL ES commands
799 	if (!SetupEGLContext(eglDisplay, eglConfig, eglSurface, eglContext))
800 	{
801 		goto cleanup;
802 	}
803 
804 	// Initialise the vertex data in the application
805 	if (!InitialiseBuffer(vertexBuffer))
806 	{
807 		goto cleanup;
808 	}
809 
810 	// Initialise the fragment and vertex shaders used in the application
811 	if (!InitialiseShaders(fragmentShader, vertexShader, shaderProgram))
812 	{
813 		goto cleanup;
814 	}
815 
816 	// Renders a triangle for 800 frames using the state setup in the previous function
817 	for (int i = 0; i < 800; ++i)
818 	{
819 		if (!RenderScene(shaderProgram, eglDisplay, eglSurface, nativeDisplay))
820 		{
821 			break;
822 		}
823 	}
824 
825 	// Release any resources we created in the Initialise functions
826 	DeInitialiseGLState(fragmentShader, vertexShader, shaderProgram, vertexBuffer);
827 
828 cleanup:
829 	// Release the EGL State
830 	ReleaseEGLState(eglDisplay);
831 
832 	// Release the windowing system resources
833 	ReleaseNativeResources(nativeDisplay, nativeWindow);
834 
835 	// Destroy the eglWindow
836 	return 0;
837 }
838 
839 /*******************************************************************************************************************************************
840  End of file (OGLES2HelloAPI_LinuxX11.cpp)
841 *******************************************************************************************************************************************/
842