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