如何使用OpenGL ES在S60上进行开发

                           1 简介

*                                       1.1 所需文件

*                               2 教程:如何开始OpenGL ES之旅

*                                       2.1 获得手机屏幕

*                                       2.2 初始化OpenGL ES

*                                       2.3 选择一个OpenGL ES配置

*                                       2.4 生成OpenGL ES context

*                                       2.5 激活context

*                                       2.6 关闭OpenGL ES

*                               3 OpenGLOpenGL ES的一些区别

*                               4 OpengL ES贴士

*                               5 附录:完整的类

简介

OpenGL ES是专为内嵌和移动设备设计的一个2D/3D轻量图形库,它是基于OpenGL API设计的。OpenGL ES 1.0版基于OpenGL 1.3,而OpenGL ES 1.1则是基于OpenGL 1.5的。现在主要由Khronos Group来负责管理OpenGL ES的开发维护。

OpenGL ES定义了一个概念,名为profile,它定义了基于原始OpenGL的一组子功能,以及针对OpenGL ES的增强功能,例

如:

*                      Common Profile: 这个profile在移动设备如电话或pda中完成;

*                      Common-Lite Profile: 这个限制较多,规定了运行3D图形程序所需最少的功能。这个主要针对安全性要求高的设备,它们的可靠性成了最需要考虑的东西。

OpenGL ES同样定义了和窗口系统(定义为EGL)的一个接口。这个EGL API是所有使用OpenGL ES的手机所需的,但是它的完成是硬件相关的。

所需文件

S60第二版FP2之后已经有了编写OpenGL ES 1.0应用程序所需的文件。OpenGL ES 1.1则在S60第三版FP1 SDK中出现下列头文件是运行OpenGL ES所需的:

#include <GLES/egl.h>
#include <GLES/gl.h>

OpenGL ES由一个DLL完成,因此程序需要这个链接库:

libgles_cm.lib
ws32.lib

第一个文件关系到OpenGL ESEGLCommon ProfileS60手机不支持Common-Lite Profile。第二个文件是关于Symbian OS

Window server的。在Carbide.c++中,当为手机编译时,这些文件应该有.dso后缀。

教程:如何开始OpenGL ES之旅

下面是开展OpenGL ES之旅的步骤:

1.     获得缺省的现实设备;

2.     初始化OpenGL ES;

3.     选择一个OpenGL ES配置

4.     生成一个OpenGL ES context

5.     生成一个可绘制的surface

6.     激活OpenGL ES context.

作为一个示例,我们使用如下定义的类来完成我们的目的:

#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
;
   
};

这里的iEglDisplay变量表示手机屏幕. OpenGL ES配置信息存放在iEglConfig. iEglContext变量则表示OpenGL EScontext。最后iEglSurface表示绘制surface

获得手机屏幕

iEglDisplay = eglGetDisplay (EGL_DEFAULT_DISPLAY);
if (iEglDisplay == EGL_NO_DISPLAY)
 User
::Panic (_L("Unable to find a  suitable EGLDisplay"), 0);

这里EGL_DEFAULT_DISPLAY指向缺省的手机屏幕(一般来说只有一个),如果程序运行失败,那么该函数将会返回

EGL_NO_DISPLAY.

初始化OpenGL ES

if (!eglInitialize (iEglDisplay, 0, 0) )
 User
::Panic (_L("Unable to initialize EGL"), 0);

最后两个参数是EGL完成的版本。如果你对此不需要,可以传递0进去。否则,他们将返回如下值:

EGLint major, minor;
 
eglInitialize
(iEglDisplay, & major, &minor);

例如版本1.0,则 major1,而minor0

选择一个OpenGL ES配置

接下来,需要指定一个程序所需最小配置

EGLint numConfigs;
 
if (!eglChooseConfig (iEglDisplay, attribList, &iEglConfig, 1, &numConfigs) )
         User
::Panic (_L("Unable to choose EGL config"), 0);

这里attribList参数指明了程序运行所需的属性列表,该函数将在iEglConfig参数中返回一个与属性列表配套的可用配置。这个列表的大小被第四个参数所限制(这里我们只需要一个配置),而numConfigs参数则在程序返回后告知有多少个匹配的配置。这个属性列表定义了一组[attribute, value]数组。EGL指定所有支持的属性。如,我们将选择color depthz-buffer大小:

// 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;

}

上述列表要以EGL_NONE常量结尾。

 

生成OpenGL ES context

iEglContext = eglCreateContext (iEglDisplay, iEglConfig, EGL_NO_CONTEXT, 0);
 
if (iEglContext == 0)
 User
::Panic (_L("Unable to create EGL context"), 0);

第三个参数表明用来共享texture对象的context。这里,我们使用了EGL_NO_CONTEXT,它表明没有context可用。最后一个函数表明映射到新context上的属性列表。但在这里没有这样的一个列表存在。

激活context

要让OpenGL ES命令生效,我们需要激活context,让它成为当前可使用的。在OpenGL ES,一次只能有一个context生效。

eglMakeCurrent (iEglDisplay, iEglSurface, iEglSurface, iEglContext);

关闭OpenGL ES

当我们使用OpenGL ES后,需要释放所有资源,记住,这个非常重要!

CGLRender::~CGLRender()
{
 eglMakeCurrent
(iEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
 eglDestroySurface
(iEglDisplay, iEglSurface);
 eglDestroyContext
(iEglDisplay, iEglContext);
 eglTerminate
(iEglDisplay);
}

第一行代码用来关闭当前context。这样surfacecontext就可以被释放。最后一行表明结束OpenGL ES

OpenGLOpenGL ES的一些区别

缺省,OpenGL ES使用双缓冲,这里是处理代码:

void CGLRender::SwapBuffers ()
{
  eglSwapBuffers
(iEglDisplay, iEglSurface);
}

因为内嵌设备的限制,OpenGL ES不能包括很多OpenGL的多余操作,如不能在OpenGL ES使用一个表明几何形式的临时模式。因此,如下代码在OpenGL ES是无效的:

glBegin (GL_TRIANGLES);
  glVertex3f
(0,1,0);
  glVertex3f
(-1,0,0);
  glVertex3f
(1,0,0);
glEnd
();

OpenGL ESvertex数组中渲染所有的几何模型。因此如果要在OpenGL ES中渲染一个三角形,需要如下代码:

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);

和大多数没有FPU(浮点运算处理器)的设备一样,OpenGL ES profile只定义了可以接收整型数值的函数。整型运算是将浮点数用整数表示的一种技巧。当我们使用整型数时,这个整数会被分成2个部分:一个用来存储真正的整数部分,而剩余的用来存储小数部分。OpenGL ES工作在16:1632位字节数上。它表明有16位是整数,而剩余的16位是小数。更多相关信息请参考here.

这里有是一个可接收整型或浮点型函数的示例:

glTranslatex (20 << 16, 0, 0, 1 << 16);
 
// same as
// glTranslatef (20.0f, 0.0f, 0.0f, 1.0f);

只能接收整型参数的函数,会有一个'x'后缀。此外,OpenGL ES还引进了GLfixed类型用来表示整型数。有一些值得一提的区别是:

*                      OpenGL ES中不存在哪些有所有的相同作用的,但有不同的缩写(如glVertex3{fsidv})的函数。但是有些如glColor4{fx}还是存在的;

*                      OpenGL ES只支持RGBA颜色模式(你不需要选择)

*                      OpenGL ES不绘制线框或点(只绘制实心填充);

*                      无需询问OpenGL ES 1.0中的动态属性(如当前颜色);

*                      没有GLU(OpenGL Utility Library),但可以找到GLU函数的内部完成,这些是OpenGL ES才有的;

*                      GL_QUADS, GL_QUAD_STRIPGL_POLYGON是不支持的。

OpengL ES贴士

*                      eglSwapBuffers函数不应该在View类的Draw方法中调用。实际的渲染将会被另一个方法处理。应该由一个timer类或活动对话来唤醒这个方法,如一个回调函数。

*                      建议使用全屏模式来显示OpenGL ES程序,因为如果不采用全屏,有时程序可能只能刷新一半(手机上)。我们用以通过在UI中生成view时传递ApplicationRect()参数指明全屏模式。

*                      使用整型数指明几何模型,因为很多手机都没有FPU的。

*                      要注意避免很多状态的改变,例如混合了有纹理映射和没有纹理映射的多边形将会降低性能,这种情况下,最好的解决方案是生成2组多边形,分别绘制。

*                      远距离物体不用进行透视矫正,因为这样效果并不明显。

*                      尽量减少或不要使用太远而不能被注意到的特效。

*                      光照很酷,但会增加处理负荷,所以要小心使用。

*                      如果有可能将多幅图片达到一个素材中,这样素材的变化将会最小。

*                      如果可能,尽量在一次单独调用中提交多个多边形,要比针多次调用好。

附录:完整的类

下面是完整的实现文件

#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);
}

Retrieved from "http://wiki.forum.nokia.com/index.php/OpenGL_ES%E7%AE%80%E4%BB%8B"a

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值