Problem at CEGUI GL3(OpenGLES2) Renderer

For help with general CEGUI usage:
- Questions about the usage of CEGUI and its features, if not explained in the documentation.
- Problems with the CMAKE configuration or problems occuring during the build process/compilation.
- Errors or unexpected behaviour.

Moderators: CEGUI MVP, CEGUI Team

YaronCT
CEGUI Team
Posts: 448
Joined: Fri Jun 19, 2015 12:18
Location: Kiryat-Bialik, Israel

Re: Problem at CEGUI GL3(OpenGLES2) Renderer

Postby YaronCT » Thu Jul 28, 2016 20:07

@sh.song: R u able to run it a see a blue window?

sh.song
Not too shy to talk
Not too shy to talk
Posts: 21
Joined: Fri Jul 17, 2015 01:35

Re: Problem at CEGUI GL3(OpenGLES2) Renderer

Postby sh.song » Fri Jul 29, 2016 08:09

Thanks for your kind
Question, When I run glfw3's sample code, _glfwInitEGL function not running. Is it not okay right? and sample doesn't use libEGL and GLES library. Maybe when i build glfw3 by cmake, something wrong.
Please tell me cmake option and setting when you build glfw3 by cmake.
And I'll test your test code, too. Thanks

YaronCT
CEGUI Team
Posts: 448
Joined: Fri Jun 19, 2015 12:18
Location: Kiryat-Bialik, Israel

Re: Problem at CEGUI GL3(OpenGLES2) Renderer

Postby YaronCT » Fri Jul 29, 2016 09:18

@sh.song: Your info is useful, thanx! I investigate. Leave my test program for now.

YaronCT
CEGUI Team
Posts: 448
Joined: Fri Jun 19, 2015 12:18
Location: Kiryat-Bialik, Israel

Re: Problem at CEGUI GL3(OpenGLES2) Renderer

Postby YaronCT » Fri Jul 29, 2016 11:43

@sh.song: Plz try with GLFW 3.1.2, with the same cmake options u used (-DGLFW_USE_EGL=ON -DGLFW_CLIENT_LIBRARY=glesv2).

YaronCT
CEGUI Team
Posts: 448
Joined: Fri Jun 19, 2015 12:18
Location: Kiryat-Bialik, Israel

Re: Problem at CEGUI GL3(OpenGLES2) Renderer

Postby YaronCT » Fri Jul 29, 2016 20:18

@sh.song: Forget that, I think I've found the problem. Plz, in cegui, in "CEGuiOpenGLES2BaseApplication::setGLFWWindowCreationHints", add, at the end:

Code: Select all

glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);


That wasn't necessary with GLFW 3.1.x, but it is with GLFW 3.2. Plz test with GLFW 3.2.x and tell me how it goes.

LordJonas
Not too shy to talk
Not too shy to talk
Posts: 32
Joined: Fri May 24, 2013 11:15

Re: Problem at CEGUI GL3(OpenGLES2) Renderer

Postby LordJonas » Fri Jul 29, 2016 20:53

Hi.

Did you tried this:

GLFW header option macros
These macros may be defined before the inclusion of the GLFW header and affect its behavior.
...
GLFW_INCLUDE_ES2 makes the GLFW header include the OpenGL ES 2.0 GLES2/gl2.h header instead of the regular OpenGL header.

sh.song
Not too shy to talk
Not too shy to talk
Posts: 21
Joined: Fri Jul 17, 2015 01:35

Re: Problem at CEGUI GL3(OpenGLES2) Renderer

Postby sh.song » Sun Jul 31, 2016 04:48

@LordJonas : Yeah I check that option at CMake. Thanks!
@YaronCT : OpenGLES2Application? For use OpenGLES2 renderer in CEGUI, am i should use OpenGL3Application?

YaronCT
CEGUI Team
Posts: 448
Joined: Fri Jun 19, 2015 12:18
Location: Kiryat-Bialik, Israel

Re: Problem at CEGUI GL3(OpenGLES2) Renderer

Postby YaronCT » Sun Jul 31, 2016 08:11

@LordJonas: Thanx but I don't think that is the problem.

@sh.song: I'm talking about the cegui sample framework, not the cegui renderer. Indeeed, the "OpenGL3Renderer" also handles OpenGL ES 2.0, but in the sample framework it uses different code to initialize GLFW with OpenGL ES 2.0. Plz make the changes I've told u in the file "samples_framework/src/CEGuiOpenGLES2BaseApplication.cpp" in cegui's source.

sh.song
Not too shy to talk
Not too shy to talk
Posts: 21
Joined: Fri Jul 17, 2015 01:35

Re: Problem at CEGUI GL3(OpenGLES2) Renderer

Postby sh.song » Sun Jul 31, 2016 17:12

@YaronCT
Ok I understand. Thanks! It seems almost solve! :P
1. I use GLFW 3.1.2 ver, and run your test code, I can see blue screen window! Thanks!
2. And when I run CEGUI sampleframework with GLFW 3.1.2, that run egl_context.c by glfw! But CEGUI throws error, "Failed to open GLFW window." Maybe I built CEGUI sampleframework by OpenGL3Application.
2. I'll test CEGUI sampleframework with OpenGLES2BaseApplication, and I checked document in homepage. But I can't find any info about OpenGLES2BaseApplication. Is it have any CMake Option?
Until you comment, I'll test OpenGLES2BaseApplication without CMake. Thank you!

YaronCT
CEGUI Team
Posts: 448
Joined: Fri Jun 19, 2015 12:18
Location: Kiryat-Bialik, Israel

Re: Problem at CEGUI GL3(OpenGLES2) Renderer

Postby YaronCT » Sun Jul 31, 2016 20:41

@sh.song: Good!

Now, there's nothing u need to do explicitly to build OpenGL ES 2.0 support in the cegui sample browser - it's supposed to b enabled automatically when u configure cegui with "-DCEGUI_USE_EPOXY=ON -DCEGUI_USE_GLEW=OFF". When u launch the cegui sample framework, does it ask u which renderer to use?

sh.song
Not too shy to talk
Not too shy to talk
Posts: 21
Joined: Fri Jul 17, 2015 01:35

Re: Problem at CEGUI GL3(OpenGLES2) Renderer

Postby sh.song » Mon Aug 01, 2016 13:30

@YaronCT
It seems solve! :D :D :D :D :D
First I add OpenGLES2Application cpp and header at CEGUISampleframework project file,
second, add option, CEGUI_SAMPLES_SUPPORT_RENDERER_OPENGLES2, in CEGUISampleframework project file's pre-processor.
It run egl_context.c at GLFW, initialize EGLDisplay and context! I'll test more, but it seems solve!
Thank you YaronCT, your kind make this. :P :P

sh.song
Not too shy to talk
Not too shy to talk
Posts: 21
Joined: Fri Jul 17, 2015 01:35

Re: Problem at CEGUI GL3(OpenGLES2) Renderer

Postby sh.song » Mon Aug 01, 2016 14:50

And I tested ANGLE, not PowerVR, It works! :D

YaronCT
CEGUI Team
Posts: 448
Joined: Fri Jun 19, 2015 12:18
Location: Kiryat-Bialik, Israel

Re: Problem at CEGUI GL3(OpenGLES2) Renderer

Postby YaronCT » Mon Aug 01, 2016 20:04

Great! :D

sh.song
Not too shy to talk
Not too shy to talk
Posts: 21
Joined: Fri Jul 17, 2015 01:35

Re: Problem at CEGUI GL3(OpenGLES2) Renderer

Postby sh.song » Wed Aug 03, 2016 05:30

@YaronCT
Hi! I testing CEGUI at PowerVR's HelloAPI sample. It use GLES 2.0.
But I have error, in glUniformMatrix4fv function;error code is "invalid operation". If i use CEGUI, all GLES function(ex. glUniformMatrix4fv) be substituted Epoxy's function, Is it right?
Can you give simple CEGUI code at GLES 2.0? Thanks.
Last edited by sh.song on Wed Aug 03, 2016 09:27, edited 3 times in total.

sh.song
Not too shy to talk
Not too shy to talk
Posts: 21
Joined: Fri Jul 17, 2015 01:35

Re: Problem at CEGUI GL3(OpenGLES2) Renderer

Postby sh.song » Wed Aug 03, 2016 10:33

sorry I solved this problem!
I'll upload my test code;using the PowerVR's sample! It works well! I hope that be good info for you!

Code: Select all

/*!*********************************************************************************************************************
\File         OGLESHelloAPI_Windows.cpp
\Title        OpenGL ES HelloAPI Tutorial
\Author       PowerVR by Imagination, Developer Technology Team
\Copyright    Copyright (c) Imagination Technologies Limited.
\brief        Basic Tutorial that shows step-by-step how to initialize OpenGL ES 2.0, use it for drawing a triangle and terminate it.
Entry Point: WinMain
***********************************************************************************************************************/

#include <windows.h>
#include <stdio.h>
#include <tchar.h>

#include "CEGUI/RendererModules/OpenGL/GL3Renderer.h"
#include "CEGUI/CEGUI.h"

#define GL_GLEXT_PROTOTYPES
#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include <vector>

// Windows class name to register
#define   WINDOW_CLASS_NAME _T("PVRShellClass")

// Name of the application
#define APPLICATION_NAME _T("HelloAPI")

// Title to display for errors.
#define ERROR_TITLE _T("Error")

// Width and height of the window
const unsigned int WindowWidth = 800;
const unsigned int WindowHeight = 600;

// Index to bind the attributes to vertex shaders
const unsigned int VertexArray = 0;

// Variable set by the message handler to finish the demo
bool HasUserQuit = false;

/*!*********************************************************************************************************************
\param         nativeWindow                Handle to the window
\param         message                     The message to handle
\param         windowParameters            Additional message information
\param         longWindowParameters        Additional message information
\return   Result code to send to the OS
\brief   Processes event messages for the main window
***********************************************************************************************************************/
LRESULT CALLBACK handleWindowMessages(HWND nativeWindow, UINT message, WPARAM windowParameters, LPARAM longWindowParameters)
{
   switch (message)
   {
   case WM_SYSCOMMAND:
      // Handle 2 system messages: screen saving and monitor power. We need to prevent them whilst we're rendering for a short time.
   {
                    switch (windowParameters)
                    {
                    case SC_SCREENSAVE:
                    case SC_MONITORPOWER:
                    {
                                      // Return 0 to let Windows know we don't want to sleep or turn the monitor off right now.
                                      return 0;
                    }
                    }
                    break;
   }
   case WM_CLOSE:
      // Handle the close message when a user clicks the quit icon of the window
   {
                // Tell the demo that it should stop rendering.
                HasUserQuit = true;

                // Post a quit message
                PostQuitMessage(0);

                // Return 1 to let Windows know the message has been successfully handled
                return 1;
   }
   }

   // Calls the default window procedure for messages we did not handle
   return DefWindowProc(nativeWindow, message, windowParameters, longWindowParameters);
}

/*!*********************************************************************************************************************
\param         nativeWindow                Handle to the window
\param         functionLastCalled          Function which triggered the error
\return   True if no EGL error was detected
\brief   Tests for an EGL error and prints it in a message box.
***********************************************************************************************************************/
bool testEGLError(HWND nativeWindow, const char* functionLastCalled)
{
   /*   eglGetError returns the last error that occurred using EGL, not necessarily the status of the last called function. The user has to
   check after every single EGL call or at least once every frame. Usually this would be for debugging only, but for this example
   it is enabled always.
   */
   EGLint lastError = eglGetError();
   if (lastError != EGL_SUCCESS)
   {
      TCHAR stringBuffer[256];
      _stprintf(stringBuffer, _T("%s failed (%x).\n"), functionLastCalled, lastError);
      MessageBox(nativeWindow, stringBuffer, ERROR_TITLE, MB_OK | MB_ICONEXCLAMATION);
      return false;
   }

   return true;
}

/*!*********************************************************************************************************************
\param         nativeWindow                Handle to the window
\param         functionLastCalled          Function which triggered the error
\return   True if no EGL error was detected
\brief   Tests for an EGL error and prints it in a message box.
***********************************************************************************************************************/
bool testGLError(HWND nativeWindow, const char* functionLastCalled)
{

   /*
   glGetError returns the last error that occurred using OpenGL ES, not necessarily the status of the last called function. The user
   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
   example it is enabled always
   */
   GLenum lastError = glGetError();
   if (lastError != GL_NO_ERROR)
   {
      TCHAR stringBuffer[256];
      _stprintf(stringBuffer, _T("%s failed (%x).\n"), functionLastCalled, lastError);
      MessageBox(nativeWindow, stringBuffer, ERROR_TITLE, MB_OK | MB_ICONEXCLAMATION);
      return false;
   }
   return true;
}

/*!*********************************************************************************************************************
\param      applicationInstance          Specific instance of the application
\param[out]   nativeWindow             Native window type to create
\param[out]   deviceContext             Native device context to create
\return   Whether the function succeeded or not.
\brief   Creates a native window and display for the application to render into.
***********************************************************************************************************************/
bool createWindowAndDisplay(HINSTANCE applicationInstance, HWND& nativeWindow, HDC& deviceContext)
{
   // Describe the native window in a window class structure
   WNDCLASS nativeWindowDescription;
   nativeWindowDescription.style = CS_HREDRAW | CS_VREDRAW;
   nativeWindowDescription.lpfnWndProc = handleWindowMessages;
   nativeWindowDescription.cbClsExtra = 0;
   nativeWindowDescription.cbWndExtra = 0;
   nativeWindowDescription.hInstance = applicationInstance;
   nativeWindowDescription.hIcon = 0;
   nativeWindowDescription.hCursor = 0;
   nativeWindowDescription.lpszMenuName = 0;
   nativeWindowDescription.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
   nativeWindowDescription.lpszClassName = WINDOW_CLASS_NAME;

   // Register the windows class with the OS.
   ATOM registerClass = RegisterClass(&nativeWindowDescription);
   if (!registerClass)
   {
      MessageBox(0, _T("Failed to register the window class"), ERROR_TITLE, MB_OK | MB_ICONEXCLAMATION);
   }

   // Create a rectangle describing the area of the window
   RECT windowRectangle;
   SetRect(&windowRectangle, 0, 0, WindowWidth, WindowHeight);
   AdjustWindowRectEx(&windowRectangle, WS_CAPTION | WS_SYSMENU, false, 0);

   // Create the window from the available information
   nativeWindow = CreateWindow(WINDOW_CLASS_NAME, APPLICATION_NAME, WS_VISIBLE | WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT,
      windowRectangle.right - windowRectangle.left, windowRectangle.bottom - windowRectangle.top,
      NULL, NULL, applicationInstance, NULL);
   if (!nativeWindow)
   {
      MessageBox(0, _T("Failed to create the window"), ERROR_TITLE, MB_OK | MB_ICONEXCLAMATION);
      return false;
   }

   // Get the associated device context from the window
   deviceContext = GetDC(nativeWindow);
   if (!deviceContext)
   {
      MessageBox(nativeWindow, _T("Failed to create the device context"), ERROR_TITLE, MB_OK | MB_ICONEXCLAMATION);
      return false;
   }
   return true;
}

/*!*********************************************************************************************************************
\param      deviceContext               The device context used by the application
\param[out]   eglDisplay                EGLDisplay created from deviceContext
\return   Whether the function succeeded or not.
\brief   Creates an EGLDisplay from a native device context, and initializes it.
***********************************************************************************************************************/
bool createEGLDisplay(HDC deviceContext, EGLDisplay& eglDisplay)
{
   //   Get an EGL display.
   //   EGL uses the concept of a "display" which in most environments corresponds to a single physical screen. After creating a native
   //   display for a given windowing system, EGL can use this handle to get a corresponding EGLDisplay handle to it for use in rendering.
   //   Should this fail, EGL is usually able to provide access to a default display.

   eglDisplay = eglGetDisplay(deviceContext);
   if (eglDisplay == EGL_NO_DISPLAY)
   {
      eglDisplay = eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY);
   }

   // If a display still couldn't be obtained, return an error.
   if (eglDisplay == EGL_NO_DISPLAY)
   {
      MessageBox(0, _T("Failed to get an EGLDisplay"), ERROR_TITLE, MB_OK | MB_ICONEXCLAMATION);
      return false;
   }

   //   Initialize EGL.
   //   EGL has to be initialized with the display obtained in the previous step. All EGL functions other than eglGetDisplay
   //   and eglGetError need an initialized EGLDisplay.
   //   If an application is not interested in the EGL version number it can just pass NULL for the second and third parameters, but they
   //   are queried here for illustration purposes.

   EGLint eglMajorVersion, eglMinorVersion;
   if (!eglInitialize(eglDisplay, &eglMajorVersion, &eglMinorVersion))
   {
      MessageBox(0, _T("Failed to initialize the EGLDisplay"), ERROR_TITLE, MB_OK | MB_ICONEXCLAMATION);
      return false;
   }
   return true;
}

/*!*********************************************************************************************************************
\param      eglDisplay                  The EGLDisplay used by the application
\param[out]   eglConfig                   The EGLConfig chosen by the function
\return   Whether the function succeeded or not.
\brief   Chooses an appropriate EGLConfig and return it.
***********************************************************************************************************************/
bool chooseEGLConfig(EGLDisplay eglDisplay, EGLConfig& eglConfig)
{

   //   Specify the required configuration attributes.
   //   An EGL "configuration" describes the capabilities an application requires and the type of surfaces that can be used for drawing.
   //   Each implementation exposes a number of different configurations, and an application needs to describe to EGL what capabilities it
   //   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
   //   of key/value pairs which describe particular capabilities requested. In this application nothing special is required so we can query
   //   the minimum of needing it to render to a window, and being OpenGL ES 2.0 capable.
   const EGLint configurationAttributes[] =
   {
      EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
      EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
      EGL_NONE
   };


   //   Find a suitable EGLConfig
   //   eglChooseConfig is provided by EGL to provide an easy way to select an appropriate configuration. It takes in the capabilities
   //   specified in the attribute list, and returns a list of available configurations that match or exceed the capabilities requested.
   //   Details of all the possible attributes and how they are selected for by this function are available in the EGL reference pages here:
   //   http://www.khronos.org/registry/egl/sdk/docs/man/xhtml/eglChooseConfig.html
   //   It is also possible to simply get the entire list of configurations and use a custom algorithm to choose a suitable one, as many
   //   advanced applications choose to do. For this application however, taking the first EGLConfig that the function returns suits
   //   its needs perfectly, so we limit it to returning a single EGLConfig.

   EGLint configsReturned;
   if (!eglChooseConfig(eglDisplay, configurationAttributes, &eglConfig, 1, &configsReturned) || (configsReturned != 1))
   {
      MessageBox(0, _T("eglChooseConfig() failed."), ERROR_TITLE, MB_OK | MB_ICONEXCLAMATION);
      return false;
   }
   return true;
}

/*!*********************************************************************************************************************
\param      nativeWindow                A native window that's been created
\param      eglDisplay                  The EGLDisplay used by the application
\param      eglConfig                   An EGLConfig chosen by the application
\param[out]   eglSurface               The EGLSurface created from the native window.
\return   Whether the function succeeds or not.
\brief   Creates an EGLSurface from a native window
***********************************************************************************************************************/
bool createEGLSurface(HWND nativeWindow, EGLDisplay eglDisplay, EGLConfig eglConfig, EGLSurface& eglSurface)
{

   //   Create an EGLSurface for rendering.
   //   Using a native window created earlier and a suitable eglConfig, a surface is created that can be used to render OpenGL ES calls to.
   //   There are three main surface types in EGL, which can all be used in the same way once created but work slightly differently:
   //    - Window Surfaces  - These are created from a native window and are drawn to the screen.
   //    - Pixmap Surfaces  - These are created from a native windowing system as well, but are offscreen and are not displayed to the user.
   //    - PBuffer Surfaces - These are created directly within EGL, and like Pixmap Surfaces are offscreen and thus not displayed.
   //   The offscreen surfaces are useful for non-rendering contexts and in certain other scenarios, but for most applications the main
   //   surface used will be a window surface as performed below.

   eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, nativeWindow, NULL);
   if (eglSurface == EGL_NO_SURFACE)
   {
      eglGetError(); // Clear error
      eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, NULL, NULL);
   }

   // Check for any EGL Errors
   if (!testEGLError(nativeWindow, "eglCreateWindowSurface")){ return false; }
   return true;
}

/*!*********************************************************************************************************************
\param         eglDisplay                  The EGLDisplay used by the application
\param         eglConfig                   An EGLConfig chosen by the application
\param         eglSurface               The EGLSurface created from the native window.
\param[out]    eglContext                  The EGLContext created by this function
\param         nativeWindow                A native window, used to display error messages
\return   Whether the function succeeds or not.
\brief   Sets up the EGLContext, creating it and then installing it to the current thread.
***********************************************************************************************************************/
bool setupEGLContext(EGLDisplay eglDisplay, EGLConfig eglConfig, EGLSurface eglSurface, EGLContext& eglContext, HWND nativeWindow)
{
   //   Make OpenGL ES the current API.
   //   EGL needs a way to know that any subsequent EGL calls are going to be affecting OpenGL ES,
   //   rather than any other API (such as OpenVG).

   eglBindAPI(EGL_OPENGL_ES_API);
   if (!testEGLError(nativeWindow, "eglBindAPI")){ return false; }

   //   Create a context.
   //   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
   //   resources and state. What appear to be "global" functions in OpenGL actually only operate on the current context. A context
   //   is required for any operations in OpenGL ES.
   //   Similar to an EGLConfig, a context takes in a list of attributes specifying some of its capabilities. However in most cases this
   //   is limited to just requiring the version of the OpenGL ES context required - In this case, OpenGL ES 2.0.
   EGLint contextAttributes[] =
   {
      EGL_CONTEXT_CLIENT_VERSION, 2,
      EGL_NONE
   };

   // Create the context with the context attributes supplied
   eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, contextAttributes);
   if (!testEGLError(nativeWindow, "eglCreateContext")){ return false; }

   //   Bind the context to the current thread.
   //   Due to the way OpenGL uses global functions, contexts need to be made current so that any function call can operate on the correct
   //   context. Specifically, make current will bind the context to the thread it's called from, and unbind it from any others. To use
   //   multiple contexts at the same time, users should use multiple threads and synchronise between them.

   eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
   if (!testEGLError(nativeWindow, "eglMakeCurrent")){ return false; }
   return true;
}

/*!*********************************************************************************************************************
\param[out]   vertexBuffer                Handle to a vertex buffer object
\param      nativeWindow                A native window, used to display error messages
\return   Whether the function succeeds or not.
\brief   Initializes shaders, buffers and other state required to begin rendering with OpenGL ES
***********************************************************************************************************************/
bool initializeBuffer(GLuint& vertexBuffer, HWND nativeWindow)
{
   //   Concept: Vertices
   //   When rendering a polygon or model to screen, OpenGL ES has to be told where to draw the object, and more fundamentally what shape
   //   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
   //   to render as triangles. Fundamentally, any advanced 3D shape in OpenGL ES is constructed from a series of these vertices - each
   //   vertex representing one corner of a polygon.


   //  Concept: Buffer Objects
   //   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
   //   of the CPU. Whilst on many embedded systems these are in the same physical memory, the distinction exists so that they can use and
   //   allocate memory without having to worry about synchronising with any other processors in the device.
   //   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
   //   a buffer and giving it some data we can tell the GPU how to render a triangle.


   // Vertex data containing the positions of each point of the triangle
   GLfloat vertexData[] = {
      -0.4f, -0.4f, 0.0f, // Bottom Left
      0.4f, -0.4f, 0.0f, // Bottom Right
      0.0f, 0.4f, 0.0f
   }; // Top Middle

   // Generate a buffer object
   glGenBuffers(1, &vertexBuffer);

   // Bind buffer as an vertex buffer so we can fill it with data
   glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);

   //   Set the buffer's size, data and usage
   //   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
   //   to modify the data until we're done with it.
   glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);

   if (!testGLError(nativeWindow, "glBufferData"))   { return false; }
   return true;
}

/*!*********************************************************************************************************************
\param[out]   fragmentShader   Handle to a fragment shader
\param[out]   vertexShader     Handle to a vertex shader
\param[out]   shaderProgram    Handle to a shader program containing the fragment and vertex shader
\param      nativeWindow     A native window, used to display error messages
\return   Whether the function succeeds or not.
\brief   Initializes shaders, buffers and other state required to begin rendering with OpenGL ES
***********************************************************************************************************************/
bool initializeShaders(GLuint& fragmentShader, GLuint& vertexShader, GLuint& shaderProgram, HWND nativeWindow)
{

   //   Concept: Shaders
   //   OpenGL ES 2.0 uses what are known as shaders to determine how to draw objects on the screen. Instead of the fixed function
   //   pipeline in early OpenGL or OpenGL ES 1.x, users can now programmatically define how vertices are transformed on screen, what
   //   data is used where, and how each pixel on the screen is colored.
   //   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
   //   which is usually abbreviated to simply "GLSL ES".
   //   Each shader is compiled on-device and then linked into a shader program, which combines a vertex and fragment shader into a form
   //   that the OpenGL ES implementation can execute.


   //   Concept: Fragment Shaders
   //   In a final buffer of image data, each individual point is referred to as a pixel. Fragment shaders are the part of the pipeline
   //   which determine how these final pixels are colored when drawn to the framebuffer. When data is passed through here, the positions
   //   of these pixels is already set, all that's left to do is set the final color based on any defined inputs.
   //   The reason these are called "fragment" shaders instead of "pixel" shaders is due to a small technical difference between the two
   //   concepts. When you color a fragment, it may not be the final color which ends up on screen. This is particularly true when
   //   performing blending, where multiple fragments can contribute to the final pixel color.

   const char* const fragmentShaderSource = "\
                                                                    void main (void)\
                                                                                                     {\
                                                                                                                                        gl_FragColor = vec4(1.0, 1.0, 0.66 ,1.0);\
                                                                                                                                                                         }";

   // Create a fragment shader object
   fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);

   // Load the source code into it
   glShaderSource(fragmentShader, 1, (const char**)&fragmentShaderSource, NULL);

   // Compile the source code
   glCompileShader(fragmentShader);

   // Check that the shader compiled
   GLint isShaderCompiled;
   glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &isShaderCompiled);
   if (!isShaderCompiled)
   {
      // If an error happened, first retrieve the length of the log message
      int infoLogLength, charactersWritten;
      glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &infoLogLength);

      // Allocate enough space for the message and retrieve it
      std::vector<char> infoLog; infoLog.resize(infoLogLength);
      glGetShaderInfoLog(fragmentShader, infoLogLength, &charactersWritten, infoLog.data());

      // Display the error in a dialog box
      MessageBox(nativeWindow, infoLogLength > 1 ? infoLog.data() : _T("Failed to compile fragment shader. (No information)"),
         ERROR_TITLE, MB_OK | MB_ICONEXCLAMATION);

      return false;
   }

   //   Concept: Vertex Shaders
   //   Vertex shaders primarily exist to allow a developer to express how to orient vertices in 3D space, through transformations like
   //   Scaling, Translation or Rotation. Using the same basic layout and structure as a fragment shader, these take in vertex data and
   //   output a fully transformed set of positions. Other inputs are also able to be used such as normals or texture coordinates, and can
   //   also be transformed and output alongside the position data.

   // Vertex shader code
   const char* const vertexShaderSource = "\
                                                                  attribute highp vec4   myVertex;\
                                                                                                uniform mediump mat4   transformationMatrix;\
                                                                                                                              void main(void)\
                                                                                                                                                            {\
                                                                                                                                                                                          gl_Position = transformationMatrix * myVertex;\
                                                                                                                                                                                                                        }";

   // Create a vertex shader object
   vertexShader = glCreateShader(GL_VERTEX_SHADER);

   // Load the source code into the shader
   glShaderSource(vertexShader, 1, (const char**)&vertexShaderSource, NULL);

   // Compile the shader
   glCompileShader(vertexShader);

   // Check the shader has compiled
   glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &isShaderCompiled);
   if (!isShaderCompiled)
   {
      // If an error happened, first retrieve the length of the log message
      int infoLogLength, charactersWritten;
      glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &infoLogLength);

      // Allocate enough space for the message and retrieve it
      char* infoLog = new char[infoLogLength];
      glGetShaderInfoLog(vertexShader, infoLogLength, &charactersWritten, infoLog);

      // Display the error in a dialog box
      MessageBox(nativeWindow, infoLogLength > 1 ? infoLog : _T("Failed to compile vertex shader. (No information)"),
         ERROR_TITLE, MB_OK | MB_ICONEXCLAMATION);

      delete[] infoLog;
      return false;
   }

   // Create the shader program
   shaderProgram = glCreateProgram();

   // Attach the fragment and vertex shaders to it
   glAttachShader(shaderProgram, fragmentShader);
   glAttachShader(shaderProgram, vertexShader);

   // Bind the vertex attribute "myVertex" to location VERTEX_ARRAY (0)
   glBindAttribLocation(shaderProgram, VertexArray, "myVertex");

   // Link the program
   glLinkProgram(shaderProgram);

   // Check if linking succeeded in the same way we checked for compilation success
   GLint isLinked;
   glGetProgramiv(shaderProgram, GL_LINK_STATUS, &isLinked);
   if (!isLinked)
   {
      // If an error happened, first retrieve the length of the log message
      int infoLogLength, charactersWritten;
      glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &infoLogLength);

      // Allocate enough space for the message and retrieve it
      char* infoLog = new char[infoLogLength];
      glGetProgramInfoLog(shaderProgram, infoLogLength, &charactersWritten, infoLog);

      // Display the error in a dialog box
      MessageBox(nativeWindow, infoLogLength > 1 ? infoLog : _T("Failed to link GL program object. (No information)"),
         ERROR_TITLE, MB_OK | MB_ICONEXCLAMATION);

      delete[] infoLog;
      return false;
   }

   //   Use the Program
   //   Calling glUseProgram tells OpenGL ES that the application intends to use this program for rendering. Now that it's installed into
   //   the current state, any further glDraw* calls will use the shaders contained within it to process scene data. Only one program can
   //   be active at once, so in a multi-program application this function would be called in the render loop. Since this application only
   //   uses one program it can be installed in the current state and left there.

   glUseProgram(shaderProgram);

   if (!testGLError(nativeWindow, "glUseProgram"))   { return false; }
   return true;
}

/*!*********************************************************************************************************************
\param   shaderProgram   The shader program used to render the scene
\param   eglDisplay      The EGLDisplay used by the application
\param   eglSurface      The EGLSurface created from the native window.
\param   nativeWindow    A native window, used to display error messages
\return   Whether the function succeeds or not.
\brief   Renders the scene to the framebuffer. Usually called within a loop.
***********************************************************************************************************************/
bool renderScene(GLuint shaderProgram, EGLDisplay eglDisplay, EGLSurface eglSurface, HWND nativeWindow)
{
   // The message handler setup for the window system will signal this variable when the window is closed, so close the application.
   if (HasUserQuit){ return false; }

   //   Set the clear color
   //   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
   //   draw a new frame. In order to do that however, OpenGL ES needs to know what color to set in the image's place. glClearColor
   //   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
   //   the intensity of the particular channel, with all 0.0 being transparent black, and all 1.0 being opaque white. Subsequent calls to
   //   glClear with the color bit will clear the frame buffer to this value.
   //   The functions glClearDepth and glClearStencil allow an application to do the same with depth and stencil values respectively.
   glClearColor(0.00, 0.70, 0.67, 1.0f);

   //   Clears the color buffer.
   //   glClear is used here with the Color Buffer to clear the color. It can also be used to clear the depth or stencil buffer using
   //   GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT, respectively.
   glClear(GL_COLOR_BUFFER_BIT);

   // Get the location of the transformation matrix in the shader using its name
   //int matrixLocation = glGetUniformLocation(shaderProgram, "transformationMatrix");

   //// Matrix used to specify the orientation of the triangle on screen.
   //const float transformationMatrix[] =
   //{
   //   1.0f, 0.0f, 0.0f, 0.0f,
   //   0.0f, 1.0f, 0.0f, 0.0f,
   //   0.0f, 0.0f, 1.0f, 0.0f,
   //   0.0f, 0.0f, 0.0f, 1.0f
   //};

   //// Pass the transformationMatrix to the shader using its location
   //glUniformMatrix4fv(matrixLocation, 1, GL_FALSE, transformationMatrix);
   //if (!testGLError(nativeWindow, "glUniformMatrix4fv"))
   //{
   //   return false;
   //}

   //// Enable the user-defined vertex array
   //glEnableVertexAttribArray(VertexArray);
/*
    Sets the vertex data to this attribute index, with the number of floats in each position
   glVertexAttribPointer(VertexArray, 3, GL_FLOAT, GL_FALSE, 0, 0);
   if (!testGLError(nativeWindow, "glVertexAttribPointer")){ return false; }*/

   //   Draw the triangle
   //   glDrawArrays is a draw call, and executes the shader program using the vertices and other state set by the user. Draw calls are the
   //   functions which tell OpenGL ES when to actually draw something to the framebuffer given the current state.
   //   glDrawArrays causes the vertices to be submitted sequentially from the position given by the "first" argument until it has processed
   //   "count" vertices. Other draw calls exist, notably glDrawElements which also accepts index data to allow the user to specify that
   //   some vertices are accessed multiple times, without copying the vertex multiple times.
   //   Others include versions of the above that allow the user to draw the same object multiple times with slightly different data, and
   //   a version of glDrawElements which allows a user to restrict the actual indices accessed.
   //glDrawArrays(GL_TRIANGLES, 0, 3);
   CEGUI::System::getSingleton().renderAllGUIContexts();
   //if (!testGLError(nativeWindow, "glDrawArrays")){ return false; }

   //   Present the display data to the screen.
   //   When rendering to a Window surface, OpenGL ES is double buffered. This means that OpenGL ES renders directly to one frame buffer,
   //   known as the back buffer, whilst the display reads from another - the front buffer. eglSwapBuffers signals to the windowing system
   //   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
   //   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
   //   buffers.
   if (!eglSwapBuffers(eglDisplay, eglSurface))
   {
      testEGLError(nativeWindow, "eglSwapBuffers");
      return false;
   }

   // Check for messages from the windowing system. These will pass through the callback registered earlier.
   MSG eventMessage;
   PeekMessage(&eventMessage, nativeWindow, NULL, NULL, PM_REMOVE);
   TranslateMessage(&eventMessage);
   DispatchMessage(&eventMessage);
   return true;
}

/*!*********************************************************************************************************************
\param         fragmentShader              Handle to a fragment shader
\param         vertexShader                Handle to a vertex shader
\param         shaderProgram               Handle to a shader program containing the fragment and vertex shader
\param         vertexBuffer                Handle to a vertex buffer object
\brief   Releases the resources created by "InitializeGLState"
***********************************************************************************************************************/
void deInitializeGLState(GLuint fragmentShader, GLuint vertexShader, GLuint shaderProgram, GLuint vertexBuffer)
{
   // Frees the OpenGL handles for the program and the 2 shaders
   glDeleteShader(fragmentShader);
   glDeleteShader(vertexShader);
   glDeleteProgram(shaderProgram);

   // Delete the VBO as it is no longer needed
   glDeleteBuffers(1, &vertexBuffer);
}

/*!*********************************************************************************************************************
\param         eglDisplay  The EGLDisplay used by the application
\brief   Releases all resources allocated by EGL
***********************************************************************************************************************/
void releaseEGLState(EGLDisplay eglDisplay)
{
   // To release the resources in the context, first the context has to be released from its binding with the current thread.
   eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);

   // Terminate the display, and any resources associated with it (including the EGLContext)
   eglTerminate(eglDisplay);
}

/*!*********************************************************************************************************************
\param         nativeWindow                The native window to release
\param         deviceContext               The native display to release
\brief   Releases all resources allocated by the windowing system
***********************************************************************************************************************/
void releaseWindowAndDisplay(HWND nativeWindow, HDC deviceContext)
{
   // Release the device context.
   if (deviceContext){ ReleaseDC(nativeWindow, deviceContext); }

   // Destroy the window
   if (nativeWindow){ DestroyWindow(nativeWindow); }
}

//----------------------------------------------------------------------------//
// setup default-default path
#ifndef CEGUI_SAMPLE_DATAPATH
#define CEGUI_SAMPLE_DATAPATH "datafiles"
#endif

// environment variable that overrides the location of the datafiles
#define DATAPATH_VAR_NAME "CEGUI_SAMPLE_DATAPATH"

//----------------------------------------------------------------------------//
void initialiseResourceGroupDirectories();
void initialiseDefaultResourceGroups();
const char* getDataPathPrefix();

//----------------------------------------------------------------------------//

//----------------------------------------------------------------------------//
void initialiseResourceGroupDirectories()
{
   // initialise the required dirs for the DefaultResourceProvider
   CEGUI::DefaultResourceProvider* rp =
      static_cast<CEGUI::DefaultResourceProvider*>
      (CEGUI::System::getSingleton().getResourceProvider());

   const char* dataPathPrefix = getDataPathPrefix();
   char resourcePath[100];

   // for each resource type, set a resource group directory
   sprintf(resourcePath, "%s/%s", dataPathPrefix, "schemes/");
   rp->setResourceGroupDirectory("schemes", resourcePath);
   sprintf(resourcePath, "%s/%s", dataPathPrefix, "imagesets/");
   rp->setResourceGroupDirectory("imagesets", resourcePath);
   sprintf(resourcePath, "%s/%s", dataPathPrefix, "fonts/");
   rp->setResourceGroupDirectory("fonts", resourcePath);
   sprintf(resourcePath, "%s/%s", dataPathPrefix, "layouts/");
   rp->setResourceGroupDirectory("layouts", resourcePath);
   sprintf(resourcePath, "%s/%s", dataPathPrefix, "looknfeel/");
   rp->setResourceGroupDirectory("looknfeels", resourcePath);
   sprintf(resourcePath, "%s/%s", dataPathPrefix, "lua_scripts/");
   rp->setResourceGroupDirectory("lua_scripts", resourcePath);
   sprintf(resourcePath, "%s/%s", dataPathPrefix, "xml_schemas/");
   rp->setResourceGroupDirectory("schemas", resourcePath);
   sprintf(resourcePath, "%s/%s", dataPathPrefix, "animations/");
   rp->setResourceGroupDirectory("animations", resourcePath);
}

//----------------------------------------------------------------------------//
void initialiseDefaultResourceGroups()
{
   // set the default resource groups to be used
   CEGUI::ImageManager::setImagesetDefaultResourceGroup("imagesets");
   CEGUI::Font::setDefaultResourceGroup("fonts");
   CEGUI::Scheme::setDefaultResourceGroup("schemes");
   CEGUI::WidgetLookManager::setDefaultResourceGroup("looknfeels");
   CEGUI::WindowManager::setDefaultResourceGroup("layouts");
   CEGUI::ScriptModule::setDefaultResourceGroup("lua_scripts");
   CEGUI::AnimationManager::setDefaultResourceGroup("animations");
   // setup default group for validation schemas
   CEGUI::XMLParser* parser = CEGUI::System::getSingleton().getXMLParser();
   if (parser->isPropertyPresent("SchemaDefaultResourceGroup"))
      parser->setProperty("SchemaDefaultResourceGroup", "schemas");
}

//----------------------------------------------------------------------------//
const char* getDataPathPrefix()
{
   static char dataPathPrefix[100];

   char* envDataPath = 0;

   // get data path from environment var
   envDataPath = getenv(DATAPATH_VAR_NAME);

   // set data path prefix / base directory.  This will
   // be either from an environment variable, or from
   // a compiled in default based on original configure
   // options
   if (envDataPath != 0)
      strcpy(dataPathPrefix, envDataPath);
   else
      strcpy(dataPathPrefix, CEGUI_SAMPLE_DATAPATH);

   return dataPathPrefix;
}

/*!*********************************************************************************************************************
\param         applicationInstance         Application instance created by the Operating System
\param         previousInstance            Always NULL
\param         commandLineString           Command line string passed from the Operating System, ignored.
\param         showCommand                 Specifies how the window is to be shown, ignored.
\return   Result code to send to the Operating System
\brief   Main function of the program, executes other functions.
***********************************************************************************************************************/
int WINAPI WinMain(HINSTANCE applicationInstance, HINSTANCE previousInstance, TCHAR* /*commandLineString*/, int /*showCommand*/)
{
   // Windows variables
   HWND            nativeWindow = NULL;
   HDC               deviceContext = NULL;

   // EGL variables
   EGLDisplay         eglDisplay = NULL;
   EGLConfig         eglConfig = NULL;
   EGLSurface         eglSurface = NULL;
   EGLContext         eglContext = NULL;

   // Handles for the two shaders used to draw the triangle, and the program handle which combines them.
   GLuint fragmentShader = 0, vertexShader = 0;
   GLuint shaderProgram = 0;

   // A vertex buffer object to store our model data.
   GLuint   vertexBuffer = 0;

   // Setup the windowing system, getting a window and a display
   if (!createWindowAndDisplay(applicationInstance, nativeWindow, deviceContext)){ goto cleanup; }

   // Create and Initialize an EGLDisplay from the native display
   if (!createEGLDisplay(deviceContext, eglDisplay)){ goto cleanup; }

   // Choose an EGLConfig for the application, used when setting up the rendering surface and EGLContext
   if (!chooseEGLConfig(eglDisplay, eglConfig)){ goto cleanup; }

   // Create an EGLSurface for rendering from the native window
   if (!createEGLSurface(nativeWindow, eglDisplay, eglConfig, eglSurface)){ goto cleanup; }

   // Setup the EGL Context from the other EGL constructs created so far, so that the application is ready to submit OpenGL ES commands
   if (!setupEGLContext(eglDisplay, eglConfig, eglSurface, eglContext, nativeWindow)){ goto cleanup; }

   // Initialize the vertex data in the application
   if (!initializeBuffer(vertexBuffer, nativeWindow)){ goto cleanup; }

   // Initialize the fragment and vertex shaders used in the application
   if (!initializeShaders(fragmentShader, vertexShader, shaderProgram, nativeWindow)){ goto cleanup; }

   // CEGUI setup
   CEGUI::OpenGL3Renderer::bootstrapSystem();
   initialiseResourceGroupDirectories();
   initialiseDefaultResourceGroups();


   CEGUI::SchemeManager::getSingleton().createFromFile("TaharezLook.scheme");
   CEGUI::System::getSingleton().getDefaultGUIContext().getMouseCursor().setDefaultImage("TaharezLook/MouseArrow");
   CEGUI::WindowManager& winMgr(CEGUI::WindowManager::getSingleton());
   CEGUI::Window* root = winMgr.createWindow("DefaultWindow", "root");
   CEGUI::Window* fw = root->createChild("TaharezLook/FrameWindow");
   fw->setPosition(CEGUI::UVector2(CEGUI::UDim(0.25, 0), CEGUI::UDim(0.25, 0)));
   fw->setSize(CEGUI::USize(CEGUI::UDim(0.5, 0), CEGUI::UDim(0.5, 0)));
   fw->setText("OpenGL ES 1 Test");

   
   CEGUI::System::getSingleton().getDefaultGUIContext().setRootWindow(root);
   


   // Renders a triangle for 800 frames using the state setup in the previous function
   for (int i = 0; i < 800; ++i)
   {
      if (!renderScene(shaderProgram, eglDisplay, eglSurface, nativeWindow))   { break; }
   }

   // Release any resources we created in the Initialize functions
   deInitializeGLState(fragmentShader, vertexShader, shaderProgram, vertexBuffer);

cleanup:
   // Release the EGL State
   releaseEGLState(eglDisplay);
   // Release the windowing system resources
   releaseWindowAndDisplay(nativeWindow, deviceContext);
   // Destroy the eglWindow
   return 0;
}


Return to “Help”

Who is online

Users browsing this forum: No registered users and 12 guests