| Introduction to OpenGL ES |
|
|
|
|
Part 1: Introduction to OpenGL ES
This article aims at providing an introduction to OpenGL ES for someone who is already experienced with desktop OpenGL, and shows how to use it with S60.
OpenGL ES is a lightweight 2D/3D graphics library designed for embedded and mobile devices, based on the original OpenGL API. OpenGL ES version 1.0 is based on OpenGL 1.3, whereas OpenGL ES 1.1 is based on OpenGL 1.5. Currently, the Khronos Group is responsible for maintaining the OpenGL ES specifications. OpenGL ES defines a concept named profile, that defines a subset of functionalities from the original OpenGL, plus features specific to OpenGL ES, such as extensions. Here they are:
OpenGL ES also features an interface with the window system defined as EGL. The EGL API is common for all devices using OpenGL ES, but its implementation is hardware-dependent. Required FilesSDKs from S60 2nd Edition FP2 onwards already have the required files to write OpenGL ES 1.0 applications. OpenGL ES 1.1 is available in the S60 3rd Edition FP1 SDK. The header files for OpenGL ES are: #include <GLES/egl.h> #include <GLES/gl.h> OpenGL ES is implemented as a DLL, so it is necessary to use these import library files (Carbide.vs): libgles_cm.lib ws32.lib The first file corresponds to OpenGL ES and EGL, Common Profile. The Common-Lite Profiles is not supported in S60 devices. The second file relates to the Symbian OS window server. For Carbide.c++, these files should have the .dso extension when building for the phone. The following steps are required to start up OpenGL ES:
As an example, we could use a class like the following one to accomplish these tasks: #include <e32base.h> #include <w32std.h> #include "GLES/egl.h" #include "GLES/gl.h" class CGLRender: public CBase { public: // method to create an instance of this class static CGLRender* NewL (RWindow & aWindow); public: // destructor ~CGLRender (); // double buffering, more on this later void SwapBuffers (); private: // constructor CGLRender (RWindow& aWindow); // second part of the two-phase constructor, where // OpenGL ES is initialized void ConstructL(); private: RWindow iWindow; EGLDisplay iEglDisplay; EGLConfig iEglConfig; EGLContext iEglContext; EGLSurface iEglSurface; }; The iEglDisplay variable represents the device screen. The OpenGL ES configuration is stored in iEglConfig. The iEglContext variable represents the OpenGL ES context. Finally, iEglSurface represents the drawing surface. Retrieving the device screeniEglDisplay = eglGetDisplay (EGL_DEFAULT_DISPLAY); if (iEglDisplay == EGL_NO_DISPLAY) User::Panic (_L("Unable to find a suitable EGLDisplay"), 0); The EGL_DEFAULT_DISPLAY constant refers to the default device screen (in most cases there is only one). If the operation fails, the function returns EGL_NO_DISPLAY. Initializing OpenGL ESif (!eglInitialize (iEglDisplay, 0, 0) ) User::Panic (_L("Unable to initialize EGL"), 0); The last two parameters in this function correspond to the EGL implementation version. If you are not interested in it, just leave them as zeros. Otherwise, they are retrieved as this: EGLint major, minor; eglInitialize (iEglDisplay, & major, &minor); For example, if the version is 1.0, major would be 1 and minor, 0. Choosing an OpenGL ES configurationNext, it is necessary to specify the minimum required configuration for the application. EGLint numConfigs; if (!eglChooseConfig (iEglDisplay, attribList, &iEglConfig, 1, &numConfigs) ) User::Panic (_L("Unable to choose EGL config"), 0); The attribList parameter represents an attribute list that the application requires. The function will return in the iEglConfig parameter a list of all the available configurations that match the attribute list. The size of this list is limited by the fourth parameter (in this case, we want only one configuration). The numConfigs parameter will inform the number of matching configurations, after the function returns. The attribute list defines a sequence of [attribute, value] pairs, as an array. The EGL specification defines constants for all supported attributes. For example, we will choose the color depth and z-buffer size: // attribute list EGLint attribList [] = { EGL_BUFFER_SIZE, 0, // color depth EGL_DEPTH_SIZE, 15, // z-buffer EGL_NONE }; // here we use the same color depth as the device // iWindow is a RWindow object switch (iWindow.DisplayMode() ) { case EColor4K: attribList [1] = 12; break; case EColor64K: attribList [1] = 16; break; case EColor16M: attribList [1] = 24; break; default: attribList [1] = 32; } The list should end with the EGL_NONE constant. Creating the OpenGL ES contextiEglContext = eglCreateContext (iEglDisplay, iEglConfig, EGL_NO_CONTEXT, 0); if (iEglContext == 0) User::Panic (_L("Unable to create EGL context"), 0); The third parameter indicates a context to share texture objects. Here, we use EGL_NO_CONTEXT stating that there is no such context. The last parameter represents an attribute list to be mapped to the new context, and in this case there is no such list. Activating the contextFor OpenGL ES commands to take effect, it is necessary to activate the context, making it current. In OpenGL ES, only one context can be current at a time. eglMakeCurrent (iEglDisplay, iEglSurface, iEglSurface, iEglContext); Shuting down OpenGL ESAfter using OpenGL ES, it is necessary to release all resources. Remember, this is very important! CGLRender::~CGLRender() { eglMakeCurrent (iEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface (iEglDisplay, iEglSurface); eglDestroyContext (iEglDisplay, iEglContext); eglTerminate (iEglDisplay); } The first line deactivates the current context. Then, the surface and the context are destroyed. The last line finishes OpenGL ES. By default, OpenGL ES uses double buffering. Here is how to perform this: void CGLRender::SwapBuffers () { eglSwapBuffers (iEglDisplay, iEglSurface); } Due to limitations of embedded devices, OpenGL ES does not include many redundant operations from OpenGL. For example, it is not possible to use immediate mode for specifying geometry in OpenGL ES. Hence, code like this one is not valid in OpenGL ES: glBegin (GL_TRIANGLES); glVertex3f (0,1,0); glVertex3f (-1,0,0); glVertex3f (1,0,0); glEnd(); OpenGL ES renders all geometry from vertex arrays. So, this is the way to render a triangle in OpenGL ES, for example: const GLbyte KVertices []= { 0,1,0, -1,0,0, 1,0,0 }; ... glEnableClientState (GL_VERTEX_ARRAY); glVertexPointer (3, GL_BYTE , 0, KVertices); glDrawArrays (GL_TRIANGLES, 0, 3); As many devices do not have a FPU (floating point unit), OpenGL ES profiles define functions that accept fixed-point values. Fixed-point math is a technique to encode floating point numbers using only integers. When using fixed-point numbers, a integer is divided in two parts: a bit range is used for storing the integer part, and the remaining bit range is used to store the real part. OpenGL ES works with 16:16 fixed-point numbers, which means that it uses 16 bits to represent the integer part and other 16 to represent the fractional part. More information can be found here. An example of using the translation function as fixed-point: glTranslatex (20 << 16, 0, 0, 1 << 16); // same as // glTranslatef (20.0f, 0.0f, 0.0f, 1.0f); The functions that accept fixed-point parameters have a 'x' suffix. Additionally, OpenGL ES introduces the GLfixed type to represent fixed-point numbers. Some other differences worth to mention:
Here is the implementation file. #include "CGLRender.h" //_____________________________________________________________________________ CGLRender::CGLRender (RWindow & aWindow) : iWindow (aWindow) {} //_____________________________________________________________________________ CGLRender::~CGLRender() { eglMakeCurrent (iEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface (iEglDisplay, iEglSurface); eglDestroyContext (iEglDisplay, iEglContext); eglTerminate (iEglDisplay); } //_____________________________________________________________________________ CGLRender* CGLRender::NewL (RWindow & aWindow) { CGLRender* instance = new (ELeave) CGLRender (aWindow); CleanupStack::PushL (instance); instance->ConstructL(); CleanupStack::Pop(); return instance; } //_____________________________________________________________________________ void CGLRender::ConstructL() { // attribute list EGLint attribList [] = { EGL_BUFFER_SIZE, 0, EGL_DEPTH_SIZE, 15, EGL_NONE }; // get device color depth switch (iWindow.DisplayMode() ) { case EColor4K: attribList [1] = 12; break; case EColor64K: attribList [1] = 16; break; case EColor16M: attribList [1] = 24; break; default: attribList [1] = 32; } // step 1 iEglDisplay = eglGetDisplay (EGL_DEFAULT_DISPLAY); if (iEglDisplay == EGL_NO_DISPLAY) User::Panic (_L("Unable to find a suitable EGLDisplay"), 0); // step 2 if (!eglInitialize (iEglDisplay, 0, 0) ) User::Panic (_L("Unable to initialize EGL"), 0); // step 3 EGLint numConfigs; if (!eglChooseConfig (iEglDisplay, attribList, &iEglConfig, 1, &numConfigs) ) User::Panic (_L("Unable to choose EGL config"), 0); // step 4 iEglContext = eglCreateContext (iEglDisplay, iEglConfig, EGL_NO_CONTEXT, 0); if (iEglContext == 0) User::Panic (_L("Unable to create EGL context"), 0); // step 5 iEglSurface = eglCreateWindowSurface (iEglDisplay, iEglConfig, &iWindow, 0); if (iEglSurface == NULL) User::Panic (_L("Unable to create EGL surface"), 0); // step 6 eglMakeCurrent (iEglDisplay, iEglSurface, iEglSurface, iEglContext); } //_____________________________________________________________________________ void CGLRender::EnforceContext () { eglMakeCurrent (iEglDisplay, iEglSurface, iEglSurface, iEglContext); } //_____________________________________________________________________________ void CGLRender::SwapBuffers () { eglSwapBuffers (iEglDisplay, iEglSurface); }
Set as favorite
Bookmark
Email This
Hits: 8287 Comments (8)
![]() shi
written by fiwedding , June 30, 2010 contests administered by SUN, ACM, and IBM. He also had co-authored U.S.
report abuse
vote down
vote up
Votes: +0
timberland mens roll top
written by timberland mens roll top , July 27, 2010 Here was someone immersed in a search for truth and beauty. Words had been cheap timberland boots treasured, words that were beautiful. And I felt as if the words timberland waterproof boots somehow delighted in being discovered, for they were obviously very generous to the as yet anonymous writer of the notes. And now this person was in turn learning the secret of sharing them. Beauty so shines when given away.
report abuse
vote down
vote up
Votes: +0
abercrombie london
written by abercrombie london , July 31, 2010 Thanks a lot for sharing. You have done a brilliant job. Your article is truly relevant to my study at this moment, and I am really happy I discovered your website. However, I would like to see more details about this topic. I'm going to keep coming back here.
report abuse
vote down
vote up
Votes: +0
abercrombie
written by abercrombie , August 04, 2010 Thank you for taking the time to publish this information very useful!
I’m still waiting for some interesting thoughts from your side in your next post thanks report abuse
vote down
vote up
Votes: +0
Good post
written by end of tenancy cleaning , August 11, 2010 I liked the post very much. It is so much helpful for me.
report abuse
vote down
vote up
Votes: +0
juicy couture outlet
written by juicy couture outlet , August 19, 2010
report abuse
vote down
vote up
Votes: +0
reply
written by natural fat burner , August 22, 2010 That's very interesting post! I was looking for it! Thanks
report abuse
vote down
vote up
Votes: +0
HI written by Insurance , August 26, 2010 I’m still waiting for some interesting thoughts from your side in your next post thanks
report abuse
vote down
vote up
Votes: +0
Write comment
|