前言

OpenGL ES是Khronos Group创建的一系列API中的一种(官方组织是:http://www.khronos.org/)。在桌面计算机上有两套标准的 3DAPI:Direct3D和OpenGL。Direct3D实际上是运行在windows操作系统上的标准3DAPI,而OpenGL则是跨平台的, 适用于Linux、多种UNIX、MAC OS X和windows。由于OpenGL得到了广范围的认可,所以,基于嵌入式的3DAPI---OpenGL ES也就应运而生。
沃Phone使用的芯片高通7227,它能很好的提供对OpenGL ES的支持,了解OpenGL
ES的种种特性,不仅能开发出很好的适用于沃Phone的3D游戏、3D应用等。借助于OpenGL
ES的平台无关性,只要稍微修改EGL,理论上就可以将开发的3D游戏、3D应用移植到任何支持OpenGL ES的平台上去。
本篇文档就从零开始,深入简出,跟大家介绍一下OpenGL ES的原理和开发。

OpenGL ES简介

什么是OpenGL ES

OpenGL ES是一套适用于手持嵌入式设备的3DAPI。比如手机、PDA、汽车、航空等等上面都可以使用到OpenGL ES。OpenGL

ES是免授权费的、跨平台的、功能完善的2D和3D图形应用程序接口API,它是桌面OpenGL的子集,是从OpenGL裁剪定制而来的。由于手持设备
的相关局限性,OpenGL
ES相对于OpenGL不可避免的进行了相关的精简。去除了OpenGL中比如glBegin/glEnd,四边形(GL_QUADS)、多边形
(GL_POLYGONS)等复杂图元等许多非绝对必要的特性。但是OpenGL方面的很多知识,OpenGL ES都是可以借鉴的。
OpenGL ES其实是一个状态机(State machine),它保存一种状态直至其改变。每个状态都有本身默认的缺省值,可以通过相关的查询和设置函数进行相关的查询和设置。
大多数的OpenGL ES的应用都采用的是相同的操作顺序,这一系列的处理阶段被称作OpenGL ES的渲染管线(pipeline)。

OpenGL ES 2.0

看一下OpenGL ES的发展历程,如下图:


从图中我们可见,现在常用的OpenGL ES有两个版本,OpenGL ES1.1和OpenGL ES2.0。其中OpenGL
ES1.1是固定渲染管线的,而OpenGL
ES2.0是可编程渲染管线的。1.1版本现在多用于低成本的设备中,而2.0的版本的设备通常是兼容1.1的。这里说的渲染,就是根据模型创建图像的一
个过程。而模型是根据几何图元创建的,图元包括点、直线、多边形,他们是通过顶点(Vertex)定义的。

OpenGL ES的处理流程

1.        固定渲染管线流程:

上图为固定渲染管线流程图,这个渲染管线是OpenGL ES1.1使用的。所处理的流程如下
1)        Primitive Processing:
这一步是图元运算过程,所谓图元,其实就是一个点集。在OpenGL
ES中,所有的物体,几何元素最终都是以顶点的形式表述的。一般来说,这些顶点将会产生三角形、直线或点。它做的工作就是将顶点提供给顶点处理器进行处
理。顶点的数据包括顶点的位置(空间坐标)、大小、颜色、顶点的法向量(用于光照计算)、纹理坐标(可能有多个)等等。
2)        Transform and Lighting:
这一步是转换和光照过程。其中Transform是通过模型、视图、投影变换矩阵,将所有的顶点坐标变换成人眼坐标系下的一致坐标。变换矩阵同样会改变物
体的顶点法向量。如果激活了纹理,还可以进行纹理坐标转换,以及自动纹理坐标的生产。Lighting处理的就是光照部分,它会利用光源、材质、转换后的
顶点位置和法向量计算每个顶点的颜色值。
3)        Primitive Assembly:
图元装配过程。管线中这个流程是对所有的点数据进行点线面等基础图元的组装。这个过程会对所有的图元进行剪切和筛选。对于不在视区空间中的部分进行剪切,对于不可见的面进行筛选。
4)        Resterizar:
光栅化。光栅化的过程就是对所有的经过Primitive Assembly图元转换成屏幕上可以显示的二维Fragment(片元)。片元和将要显示的像素一一对应。
5)        Texture Environment:
纹理处理。利用纹理坐标来进行纹理的相关处理。
6)        Colour Sum:
颜色叠加。根据纹理颜色等相关属性确定最终的顶点颜色。
7)        Fog:
雾。雾化处理。
8)        Alpha Test:
Alpha测试。判断某些片元是否抛弃。比如可以规定Alpha小于0.2的片元就需要抛弃。
9)        Depth Stencil:
深度测试和模板测试。深度测试需要一个深度缓冲区,是在后面的会被在前的遮盖,需要抛弃。模板测试需要一个模板缓冲区,也就是模板缓冲区中为每个像素保存
了一个“模板值”,当像素需要进行模板测试时,将设定的模板参考值与该像素的“模板值”进行比较,符合条件的通过测试,不符合条件的则被丢弃,不进行绘
制。条件的设置与Alpha测试中的条件设置相似。但注意Alpha测试中是用浮点数来进行比较,而模板测试则是用整数来进行比较。
10)    Color Buffer blend:
跟颜色缓冲区进行混合。最终生成的片元颜色需要跟颜色缓冲区中本来的进行混合(也可以理解成为跟背景混合),以生成最终的颜色。
11)    Dither:
抖动。在可用颜色数量较少的系统中,可能需要对颜色值进行抖动,在适当损失颜色质量的情况下增加可使用的颜色数量。
12)    Frame Buffer:
最终结果就写进了Frame Buffer。一个流程就算结束了。
2.        可编程渲染管线流程:

对比固定渲染管线流程图和可编程渲染管线流程图,可以看出来,大部分的流程都是一样的,只是可编程将固定中的几个功能合并了,新增了两个新的流程,Vertex Shader和Fragment Shader。也就是着色器(shader)
作为OpenGL ES2.0的一部分,着色器允许应用程序显式地指定处理顶点和片断时候所执行的操作。
1)      Shader language简介:
编写OpenGL ES程序使用的着色器类似于使用基于编译器的语言(比如C语言)编写程序。我们需要用编译器来分析程序,检查它所存在的错误,并把它转换成为目标代码。接着,在链接阶段,链接器把一组目标文件组合在一起,形成一个可执行的程序。着色器的创建流程如下:

对于每个着色器对象:
1.      创建一个着色器对象。
2.      把着色器源代码编译为目标代码。
3.      验证这个着色器已经成功通过编译。
然后,为了把多个着色器对象链接到一个着色器程序中,需要:
1.      创建一个着色器程序。
2.      把适当的着色器对象连接到这个着色器程序中。
3.      链接着色器程序。
4.      验证着色器程序链接成功。
5.      使用着色器进行顶点或片段处理。
1)      Vertex Shader:
包含了固定渲染管线中的Transform and lighting的所有操作。
2)      Fragment Shader:
包含了固定渲染管线中的纹理处理、颜色叠加、雾、alpha测试等内容。
                     具体着色器语言和两个着色器的使用,可见后续的sample分析。

EGL简介

OpenGL实现跨平台的功能,在不同的操作系统上需要不同的类似适配层的内容,比如在Windows操作系统上需要WGL。同样的,OpenGL

ES是一个平台中立的图形库,在它能够工作前,需要与一个实际的窗口关联起来,但是,与OpenGL不一样的是,OpenGL是每个窗口系统需要一个与之
对应的适配层,Windows需要WGL,X-Window需要xgl,Mac OS需要agl。而OpenGL
ES的这层,是统一的一个标准。这个标准就是EGL。
(一)      初识EGL
EGL是介于RenderAPI(比如OpenGL ES和OpenVG)和本地基础系统的一套接口。里面涉及了OpenGL
ES和OpenVG的一些相关描述,所以需要和OpenGL
ES和OpenVG文档一起阅读。EGL使用OpenGLES的命名习惯来命名函数入口和宏定义。具体的接口和相关宏定义可以参见egl.h。
(二)      EGL的使用
1.      获取Display:
Display代表的是显示器,有的系统上有多个显示器,也就会有多个display。获得Display需要调用EGLDisplay
eglGetDisplay(EGLNativeDisplayType
display_id);,参数一般为EGL_DEFAULT_DISPLAY。该参数的实际意义是平台相关的,比如在windows平台上,一般返回的
就是DC。沃Phone上就是TDC。
2.      初始化egl:
获得了Display后,调用EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor);该函数会进行一些相关的内部初始化工作。我们可以通过这个函数获得egl的版本号。
3.      选择Config:
Config实际就是FrameBuffer的参数,在Windows下对应于PixelFormat,在X-Window下对应Visual。可以用函
数EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,
EGLConfig *configs, EGLint config_size, EGLint
*num_config);,其中attrib_list
是以EGL_NONE结束的参数数组,通常以id,value依次存放,对于个别标识性的属性可以只有id,没有value。另一个办法是用
EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint
config_size, EGLint *num_config);
来获得所有config。这两个函数都会返回不多于config_size个Config,结果保存在configs[]中,系统的总Config个数保
存在num_config中。可以利用eglGetConfig()中间两个参数为0来查询系统支持的Config总个数。Config有众多的
Attribute,这些Attribute决定FrameBuffer的格式和能力,通过eglGetConfigAttrib
()来读取,但不能修改。
4.      构造Surface:
有了Config,就可以开始构造Surface了。Surface实际上就是一个FrameBuffer。通过函数EGLSurface
eglCreateWindowSurface(EGLDisplay dpy, EGLConfig
config,EGLNativeWindowType win, const EGLint
*attrib_list)可以创建一个Surface。系统通常还支持另外两种Surface:PixmapSurface和
PBufferSurface,这两种都不是可显示的Surface,PixmapSurface是保存在系统内存中的位图,PBuffer则是保存在显
存中的帧。Surface也有一些attribute,基本上都可以故名思意,EGL_HEIGHT EGL_WIDTH
EGL_LARGEST_PBUFFER EGL_TEXTURE_FORMAT EGL_TEXTURE_TARGET
EGL_MIPMAP_TEXTURE
EGL_MIPMAP_LEVEL,通过eglSurfaceAttrib()设置、eglQuerySurface()读取。
5.      创建Context:
OpenGL
ES的pipeline从程序的角度看就是一个状态机,有当前的颜色、纹理坐标、变换矩阵、渲染模式等一大堆状态,这些状态作用于程序提交的顶点坐标等图
元从而形成帧缓冲内的像素。在OpenGL
ES的编程接口中,Context就代表这个状态机,程序的主要工作就是向Context提供图元、设置状态,偶尔也从Context里获取一些信息。用
EGLContext eglCreateContext(EGLDisplay dpy, EGLSurface write, EGLSurface
read, EGLContext * share_list)来创建一个Context。
6.      绘制:
应用程序通过OpenGL API进行绘制,一帧完成之后,调用eglSwapBuffers(EGLDisplay dpy, EGLContext ctx)来显示。

OpenGL ES的HelloWorld---Hello********

  1. // 头文件包含
  2. #include "TG3.h"
  3. #include
  4. #include
  5. #include "OGLES2Hello********.h"
  6. // 宏定义
  7. #define VERTEX_ARRAY 0
  8. // 定义Display、config、surface、context
  9. EGLDisplay eglDisplay = 0;
  10. EGLConfig eglConfig = 0;
  11. EGLSurface eglSurface = 0;
  12. EGLContext eglContext = 0;
  13. EGLNativeWindowType eglWindow = 0;
  14. // 沃Phone窗口指针
  15. extern TWindow *g_pThis;
  16. bool TestEGLError()
  17. {
  18. //eglGetError返回上一个egl中的错误,用户在每个egl函数调用结束都需要调用这个函数。
  19. EGLint iErr = eglGetError();
  20. if (iErr != EGL_SUCCESS)
  21. {
  22. return false;
  23. }
  24. return true;
  25. }
  26. bool CreateEGLContext()
  27. {
  28. // 第一步:获得或者创建一个可以用于OpenGL ES输出的EGLNativeWindowType
  29. eglWindow = (EGLNativeWindowType)g_pThis;
  30. //第二步:获得默认的Display。通常我们只有一块屏幕,参数传EGL_DEFAULT_DISPLAY就可以了。
  31. eglDisplay = eglGetDisplay((EGLNativeDisplayType) EGL_DEFAULT_DISPLAY);
  32. //第三步:初始化EGL,如果我们不想要版本号,后两个参数也可以传NULL进去。
  33. EGLint iMajorVersion, iMinorVersion;
  34. if (!eglInitialize(eglDisplay, &iMajorVersion, &iMinorVersion))
  35. {
  36. return false;
  37. }
  38. //第四步:指定需要的配置属性,一个EGL的配置描述了Surfaces上像素的格式信息。当前我们要的是Windows的surface,在屏幕上是可见的,以EGL_NONE结尾。
  39. const EGLint pi32ConfigAttribs[] =
  40. {
  41. EGL_LEVEL, 0,
  42. EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
  43. EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
  44. EGL_NATIVE_RENDERABLE, EGL_FALSE,
  45. EGL_DEPTH_SIZE, EGL_DONT_CARE,
  46. EGL_NONE
  47. };
  48. //第五步:寻找一个符合所有要求的配置,我们需要的只是其中一个,所以可以限制config的个数为1。
  49. int iConfigs;
  50. if (!eglChooseConfig(eglDisplay, pi32ConfigAttribs, &eglConfig, 1, &iConfigs) || (iConfigs != 1))
  51. {
  52. return false;
  53. }
  54. //第六步:创建一个可画的surface。这里创建时可见的windows surface。Pixmaps和pbuffers都是不可见的。
  55. eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, eglWindow, NULL);
  56. if(eglSurface == EGL_NO_SURFACE)
  57. {
  58. eglGetError(); // Clear error
  59. eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, NULL, NULL);
  60. }
  61. if (!TestEGLError())
  62. {
  63. return false;
  64. }
  65. //第七步:创建Context。我们OpenGL ES的资源,比如纹理只有在这个context里是可见的。
  66. // 绑定API (可以是OpenGLES或者 OpenVG)
  67. eglBindAPI(EGL_OPENGL_ES_API);
  68. EGLint ai32ContextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
  69. eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, ai32ContextAttribs);
  70. if (!TestEGLError())
  71. {
  72. return false;
  73. }
  74. //第八步:将创建的context绑定到当前的线程,使用我们创建的surface进行读和写。Context绑定到线程上,你就可以不用担心其他的进程影响你的OpenGL ES应用程序。
  75. eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
  76. if (!TestEGLError())
  77. {
  78. return false;
  79. }
  80. return true;
  81. }
  82. bool Render()
  83. {
  84. //第九步:使用OpenGL ES API画一些东西。到这里,所有的东西都已准备就绪,我们做好了往屏幕上画东西的准备。
  85. bool bRet = false;
  86. //单元矩阵,用于投影和模型变换
  87. float pfIdentity[] =
  88. {
  89. 1.0f,0.0f,0.0f,0.0f,
  90. 0.0f,1.0f,0.0f,0.0f,
  91. 0.0f,0.0f,1.0f,0.0f,
  92. 0.0f,0.0f,0.0f,1.0f
  93. };
  94. // Vertex和Fragment的shader
  95. // gl_FragColor指定了最终的像素颜色。
  96. // gl_position则指定了最终的点在人眼坐标中的位置。
  97. char szFragShaderSrc[] = {"\
  98. void main (void)\
  99. {\
  100. gl_FragColor = vec4(1.0, 1.0, 0.66 ,1.0);\
  101. }"};
  102. char szVertShaderSrc[] = {"\
  103. attribute highp vec4 myVertex;\
  104. uniform mediump mat4 myPMVMatrix;\
  105. void main(void)\
  106. {\
  107. gl_Position = myPMVMatrix * myVertex;\
  108. }"};
  109. char * pszFragShader = (char *)szFragShaderSrc;
  110. char * pszVertShader = (char *)szVertShaderSrc;
  111. GLuint uiFragShader = 0;
  112. GLuint uiVertShader = 0; /* 用来存放Vertex和Fragment shader的句柄 */
  113. GLuint uiProgramObject = 0; /* 用来存放创建的program的句柄*/
  114. GLint bShaderCompiled;
  115. GLint bLinked;
  116. // 我们要画一个三角形,所以,我们先创建一个顶点缓冲区
  117. GLuint ui32Vbo = 0; // 顶点缓冲区对象句柄
  118. //顶点数据 这9个数据分别为3个点的X、Y、Z坐标
  119. GLfloat afVertices[] = { -0.4f,-0.4f,0.0f, // Position
  120. 0.4f ,-0.4f,0.0f,
  121. 0.0f ,0.4f ,0.0f};
  122. int i32InfoLogLength, i32CharsWritten;
  123. char* pszInfoLog = NULL;
  124. int i32Location = 0;
  125. unsigned int uiSize = 0;
  126. //创建Fragment着色器对象
  127. uiFragShader = glCreateShader(GL_FRAGMENT_SHADER);
  128. // 将代码加载进来
  129. glShaderSource(uiFragShader, 1, (const char**)&pszFragShader, NULL);
  130. //编译代码
  131. glCompileShader(uiFragShader);
  132. //看编译是否成功进行
  133. glGetShaderiv(uiFragShader, GL_COMPILE_STATUS, &bShaderCompiled);
  134. if (!bShaderCompiled)
  135. {
  136. // 错误发生,首先获取错误的长度
  137. glGetShaderiv(uiFragShader, GL_INFO_LOG_LENGTH, &i32InfoLogLength);
  138. //开辟足够的空间来存储错误信息
  139. pszInfoLog = new char[i32InfoLogLength];
  140. glGetShaderInfoLog(uiFragShader, i32InfoLogLength, &i32CharsWritten, pszInfoLog);
  141. delete[] pszInfoLog;
  142. goto cleanup;
  143. }
  144. // 使用同样的方法加载Vertex Shader
  145. uiVertShader = glCreateShader(GL_VERTEX_SHADER);
  146. glShaderSource(uiVertShader, 1, (const char**)&pszVertShader, NULL);
  147. glCompileShader(uiVertShader);
  148. glGetShaderiv(uiVertShader, GL_COMPILE_STATUS, &bShaderCompiled);
  149. if (!bShaderCompiled)
  150. {
  151. glGetShaderiv(uiVertShader, GL_INFO_LOG_LENGTH, &i32InfoLogLength);
  152. pszInfoLog = new char[i32InfoLogLength];
  153. glGetShaderInfoLog(uiVertShader, i32InfoLogLength, &i32CharsWritten, pszInfoLog);
  154. delete[] pszInfoLog;
  155. goto cleanup;
  156. }
  157. // 创建着色器程序
  158. uiProgramObject = glCreateProgram();
  159. // 将Vertex和Fragment Shader绑定进去。
  160. glAttachShader(uiProgramObject, uiFragShader);
  161. glAttachShader(uiProgramObject, uiVertShader);
  162. //将用户自定义的顶点属性myVertex绑定到VERTEX_ARRAY。
  163. glBindAttribLocation(uiProgramObject, VERTEX_ARRAY, "myVertex");
  164. // 链接着色器程序
  165. glLinkProgram(uiProgramObject);
  166. // 判断链接是否成功的操作
  167. glGetProgramiv(uiProgramObject, GL_LINK_STATUS, &bLinked);
  168. if (!bLinked)
  169. {
  170. glGetProgramiv(uiProgramObject, GL_INFO_LOG_LENGTH, &i32InfoLogLength);
  171. pszInfoLog = new char[i32InfoLogLength];
  172. glGetProgramInfoLog(uiProgramObject, i32InfoLogLength, &i32CharsWritten, pszInfoLog);
  173. delete[] pszInfoLog;
  174. goto cleanup;
  175. }
  176. // 使用着色器程序
  177. glUseProgram(uiProgramObject);
  178. // 设置清除颜色,以RGBA的模式,每个分量的值从0.0到1.0
  179. glClearColor(0.6f, 0.8f, 1.0f, 1.0f);
  180. //生成一个顶点缓冲区对象
  181. glGenBuffers(1, &ui32Vbo);
  182. //绑定生成的缓冲区对象到GL_ARRAY_BUFFER
  183. glBindBuffer(GL_ARRAY_BUFFER, ui32Vbo);
  184. // 加载顶点数据
  185. uiSize = 3 * (sizeof(GLfloat) * 3); // Calc afVertices size (3 vertices * stride (3 GLfloats per vertex))
  186. glBufferData(GL_ARRAY_BUFFER, uiSize, afVertices, GL_STATIC_DRAW);
  187. // 画三角形
  188. {
  189. //清除颜色缓冲区。glClear同样也能清除深度缓冲区(GL_DEPTH_BUFFER)和模板缓冲区(GL_STENCIL_BUFFER_BIT)
  190. glClear(GL_COLOR_BUFFER_BIT);
  191. //获取myPMVMatrix在shader中的位置
  192. i32Location = glGetUniformLocation(uiProgramObject, "myPMVMatrix");
  193. //传值给获取到的位置,也就是将pfIdentity传给myPMVMatrix
  194. glUniformMatrix4fv( i32Location, 1, GL_FALSE, pfIdentity);
  195. //将VERTEX_ARRAY置为有效。
  196. glEnableVertexAttribArray(VERTEX_ARRAY);
  197. // 将定点数据传到VERTEX_ARRAY
  198. glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, 0, 0);
  199. //画一个三角形。
  200. glDrawArrays(GL_TRIANGLES, 0, 3);
  201. //SwapBuffers。就可以将三角形显示出来
  202. eglSwapBuffers(eglDisplay, eglSurface);
  203. }
  204. bRet = true;
  205. cleanup:
  206. // 释放资源
  207. if (uiProgramObject)
  208. glDeleteProgram(uiProgramObject);
  209. if (uiFragShader)
  210. glDeleteShader(uiFragShader);
  211. if (uiVertShader)
  212. glDeleteShader(uiVertShader);
  213. // Delete the VBO as it is no longer needed
  214. if (ui32Vbo)
  215. glDeleteBuffers(1, &ui32Vbo);
  216. return bRet;
  217. }
  218. bool DestroyEGLContext()
  219. {
  220. //第十步:结束
    OpenGL
    ES并删除创建的Windows(如果存在的话).eglminate已经负责清除context和surface。所以调用了eglTerminate
    后就无需再调用eglDestroySurface和eglDestroyContext了。
  221. if (eglDisplay != EGL_NO_DISPLAY)
  222. {
  223. eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  224. eglDestroyContext(eglDisplay, eglContext );
  225. eglDestroySurface(eglDisplay, eglSurface );
  226. eglTerminate(eglDisplay);
  227. eglDisplay = EGL_NO_DISPLAY;
  228. }
  229. //第十一步:删除已经创建的eglWindow。这个是跟具体平台有关的。
  230. eglWindow = NULL;
  231. return true;
  232. }
  233. //这样,有关OpenGL ES画一个三角形的步骤就走完了,剩下的,只是在沃Phone的平台上进行相关额外的操作,比如窗口的创建,消息循环的处理等。
  234. //根据工程向导新建一个新工程,工程新建完,在**MainForm.cpp中
  235. //新增定义:
  236. TWindow *g_pThis = NULL;
  237. //在TMainForm::TMainForm(TApplication * pApp):TWindow(pApp)中加入
  238. m_bGLESInit = FALSE;
  239. g_pThis = this;
  240. //在case EVENT_WinInit:中加入:
  241. if (CreateEGLContext())
  242. {
  243. m_bGLESInit = TRUE;
  244. Sys_PostMessage(MESSAGE_PRIOR_LOWEST, 0, &PID_SELF, EVENT_FirstUser, GetWindowHwndId(), 0, NULL, 0);
  245. }
  246. bHandled = TRUE;
  247. //新增:
  248. case EVENT_FirstUser:
  249. {
  250. if(m_bGLESInit)
  251. {
  252. Render();
  253. Sys_PostMessage(MESSAGE_PRIOR_LOWEST, 0, &PID_SELF, EVENT_FirstUser, GetWindowHwndId(), 0, NULL, 0);
  254. }
  255. bHandled = TRUE;
  256. }
  257. break;
  258. case EVENT_GlesUpdateNotify:
  259. {
  260. if(m_bGLESInit)
  261. {
  262. TRectangle rt;
  263. GetClientBounds(&rt);
  264. MarkUpdateRectangle(&rt);
  265. }
  266. bHandled = TRUE;
  267. }
  268. break;
  269. //在case EVENT_WinClose:中加入:
  270. if (m_bGLESInit)
  271. {
  272. DestroyEGLContext();
  273. m_bGLESInit = FALSE;
  274. }
  275. // Stop the application since the main form has been closed
  276. pApp->SendStopEvent();
 
 

这个是在模拟器上跑的时候的代码,如果是在真机下跑,同在模拟器上跑,有以下区别:

1.      模拟器上使用的是自己创建的windows窗口,使用ms window的消息机制。但在真机上传的是沃Phone的窗口句柄。
2.      在调用eglGetDisplay的时候,模拟器上传入的是hdc,真机上传入的是(EGLNativeDisplayType)EGL_DEFAULT_DISPLAY)。
3.      调用eglCreateWindowSurface的时候,模拟器上使用的是hWnd,但是真机上传入的是TWindows
4.      模拟器上的消息循环使用ms的机制,需要自己控制。真机上则需要加入EVENT_FirstUser、EVENT_GlesUpdateNotify等消息。具体可参见范例。

OpenGL ES的更多相关文章

  1. 【AR实验室】OpenGL ES绘制相机(OpenGL ES 1.0版本)

    0x00 - 前言 之前做一些移动端的AR应用以及目前看到的一些AR应用,基本上都是这样一个套路:手机背景显示现实场景,然后在该背景上进行图形学绘制.至于图形学绘制时,相机外参的解算使用的是V-SLA ...

  2. OpenGL ES 3.0: 图元重启(Primitive restart)

    [TOC] 背景概述 在OpenGL绘制图形时,可能需要绘制多个并不相连的图形.这样的情况下这几个图形没法被当做一个图形来处理.也就需要多次调用 DrawArrays 或 DrawElements. ...

  3. opengl es中不同的绘制方式

    opengl es中不同的绘制方式 转载请保留出处:http://xiaxveliang.blog.163.com/blog/static/297080342013467344263/ 1. GL_P ...

  4. OpenGL ES无法获取贴图数据原因

    最近在做一个项目,要从贴图中获取图像数据,查了很多资料,也琢磨很久,获取到的数据都是0.终于在一次偶然的机会,发现了端倪,成功了. 不得不说这"一分灵感"真的很重要 以下是在获取贴 ...

  5. OpenGL ES(一.概念)

    OpenGL ES是以手持和嵌入式设备为目标的高级3D图形应用程序编程接口,主要的支持平台是iOS,Android,Linux和Windows 1.顶点着色器 他可以用于通过矩阵变换位置,计算照明公式 ...

  6. IOS 中openGL使用教程1(openGL ES 入门篇 | 搭建openGL环境)

    OpenGL版本 iOS系统默认支持OpenGl ES1.0.ES2.0以及ES3.0 3个版本,三者之间并不是简单的版本升级,设计理念甚至完全不同,在开发OpenGL项目前,需要根据业务需求选择合适 ...

  7. OpenGL ES crash notes 01 - Nice to meet you

    这篇笔记完全参照<OpenGL.ES.3.0.Programming.Guide.2nd.Edition>,摘出部分内容只为学习参考. 为什么要用英文:无论是D3D的SDK还是OES的Sp ...

  8. android opengl es代码功能

    /* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Versi ...

  9. [cocos2d-x]OPENGL ES支持的像素格式

    OPENGL ES最多支持32位颜色值. 支持的像素格式有以下几种: 客户端格式 GL格式 GL数据类型 字节数 RGBA8888 GL_RGBA GL_UNSIGNED_BYTE 4 RGB888 ...

  10. 一篇通俗易懂的讲解OpenGL ES的文章

    电脑或者手机上做图像处理有很多方式,但是目前为止最高效的方法是有效地使用图形处理单元,或者叫 GPU.你的手机包含两个不同的处理单元,CPU 和 GPU.CPU 是个多面手,并且不得不处理所有的事情, ...

随机推荐

  1. UVALive 2403 77377解题报告(深搜)

    题意:给你一些固定的字符串,在给出数字,根据键盘的对应关系,输出所有的满足条件的字符串,输出顺序无所谓. 思路:因为题目说了,输出比较小,说明测试数据并不强,所以可以暴力回溯求出答案,将所有的给出的字 ...

  2. elasticsearch集群内部节点超时解决

    默认配置为:节点每隔1s同master发送1次心跳,超时时间为30s,测试次数为3次,超过3次,则认为该节点同master已经脱离了.以上为elasticsearch的默认配置.在实际生产环境中,每隔 ...

  3. javascript预编译

    刚学前端的小白,第一次写博客,难免有点幼稚.以后每周写两次博客,慢慢积累. 笨鸟不必先飞,但一定是最后一个留下的.加油! JS的预编译定义 在一段程序执行前,js会把var和function这两个关键 ...

  4. Effective java -- 4 泛型

    第二十三条:请不要在代码中使用原生态类型就是像Set这种待泛型的,就把泛型明确写出来. 第二十四条:消除非受检警告就是Set<String> sets = new HashSet();这种 ...

  5. 【转】Apache 关于 mod_rewrite 遇到 %2F或%5C (正反斜杠)等特殊符号导致URL重写失效出现404的问题

    .htaccess 文件 <IfModule mod_rewrite.c> RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-d Rew ...

  6. Struts2 语法--action

    xml的注释: <!--叨叨叨叨--> web.xml注释格式": <?xml version="1.0" encoding="UTF-8&q ...

  7. expdp.sh and impdp.sh

    ####expdp.sh ###### ------------- --   UAT   -- ------------- @D:\dba\change\UAT\eais\env\env_eaisua ...

  8. hibernate分页查询的实现

    在mysql中新建数据好USER表,字段有3个,分别是id.username.password,贴上脚本仅供参考     create table `ding`.`user`(         `id ...

  9. Beautiful Subarrays

    Beautiful Subarrays time limit per test 3 seconds memory limit per test 512 megabytes input standard ...

  10. C# devExpress BandedGridView属性 备忘

    BandedGridView属性备忘 StringBuilder sb = new StringBuilder(); DevExpress.XtraGrid.Views.BandedGrid.Band ...