《OpenGL ES 2.0 Programming Guide》第9章“最简单的MipMap”示例代码【C语言版】

举报
ShaderJoy 发表于 2021/12/30 01:15:48 2021/12/30
【摘要】 由于《OpenGL ES 2.0 Programming Guide》原书第9章的示例代码使用的纹理是程序生成的,作者还自己实现了Mipmap的过程,对于理解Mipmap的原理很有帮助,但是并不实用,遂自己实现了一份C语言版本的(加载本地纹理+调用glGenerateMipmap),希望能够帮助到同样喜欢OpenGL ES 2.0的同学...

由于《OpenGL ES 2.0 Programming Guide》原书第9章的示例代码使用的纹理是程序生成的,作者还自己实现了Mipmap的过程,对于理解Mipmap的原理很有帮助,但是并不实用,遂自己实现了一份C语言版本的(加载本地纹理+调用glGenerateMipmap),希望能够帮助到同样喜欢OpenGL ES 2.0的同学。
废话不多说,直接上代码:



  
  1. // MipMap2D.c
  2. //
  3. // This is a simple example that demonstrates generating a mipmap chain
  4. // and rendering with it
  5. //
  6. #include <stdlib.h>
  7. #include "esUtil.h"
  8. typedef struct
  9. {
  10. // Handle to a program object
  11. GLuint programObject;
  12. // Attribute locations
  13. GLint positionLoc;
  14. GLint texCoordLoc;
  15. // Sampler location
  16. GLint samplerLoc;
  17. // Offset location
  18. GLint offsetLoc;
  19. // Texture handle
  20. GLuint textureId;
  21. } UserData;
  22. ///
  23. // From an RGB8 source image, generate the next level mipmap
  24. //
  25. GLboolean GenMipMap2D( GLubyte *src, GLubyte **dst, int srcWidth, int srcHeight, int *dstWidth, int *dstHeight )
  26. {
  27. int x,
  28. y;
  29. int texelSize = 3;
  30. *dstWidth = srcWidth / 2;
  31. if ( *dstWidth <= 0 )
  32. *dstWidth = 1;
  33. *dstHeight = srcHeight / 2;
  34. if ( *dstHeight <= 0 )
  35. *dstHeight = 1;
  36. *dst = malloc ( sizeof(GLubyte) * texelSize * (*dstWidth) * (*dstHeight) );
  37. if ( *dst == NULL )
  38. return GL_FALSE;
  39. for ( y = 0; y < *dstHeight; y++ )
  40. {
  41. for( x = 0; x < *dstWidth; x++ )
  42. {
  43. int srcIndex[4];
  44. float r = 0.0f,
  45. g = 0.0f,
  46. b = 0.0f;
  47. int sample;
  48. // Compute the offsets for 2x2 grid of pixels in previous
  49. // image to perform box filter
  50. srcIndex[0] =
  51. (((y * 2) * srcWidth) + (x * 2)) * texelSize;
  52. srcIndex[1] =
  53. (((y * 2) * srcWidth) + (x * 2 + 1)) * texelSize;
  54. srcIndex[2] =
  55. ((((y * 2) + 1) * srcWidth) + (x * 2)) * texelSize;
  56. srcIndex[3] =
  57. ((((y * 2) + 1) * srcWidth) + (x * 2 + 1)) * texelSize;
  58. // Sum all pixels
  59. for ( sample = 0; sample < 4; sample++ )
  60. {
  61. r += src[srcIndex[sample]];
  62. g += src[srcIndex[sample] + 1];
  63. b += src[srcIndex[sample] + 2];
  64. }
  65. // Average results
  66. r /= 4.0;
  67. g /= 4.0;
  68. b /= 4.0;
  69. // Store resulting pixels
  70. (*dst)[ ( y * (*dstWidth) + x ) * texelSize ] = (GLubyte)( r );
  71. (*dst)[ ( y * (*dstWidth) + x ) * texelSize + 1] = (GLubyte)( g );
  72. (*dst)[ ( y * (*dstWidth) + x ) * texelSize + 2] = (GLubyte)( b );
  73. }
  74. }
  75. return GL_TRUE;
  76. }
  77. ///
  78. // Generate an RGB8 checkerboard image
  79. //
  80. GLubyte* GenCheckImage( int width, int height, int checkSize )
  81. {
  82. int x,
  83. y;
  84. GLubyte *pixels = malloc( width * height * 3 );
  85. if ( pixels == NULL )
  86. return NULL;
  87. for ( y = 0; y < height; y++ )
  88. for ( x = 0; x < width; x++ )
  89. {
  90. GLubyte rColor = 0;
  91. GLubyte bColor = 0;
  92. if ( ( x / checkSize ) % 2 == 0 )
  93. {
  94. rColor = 255 * ( ( y / checkSize ) % 2 );
  95. bColor = 255 * ( 1 - ( ( y / checkSize ) % 2 ) );
  96. }
  97. else
  98. {
  99. bColor = 255 * ( ( y / checkSize ) % 2 );
  100. rColor = 255 * ( 1 - ( ( y / checkSize ) % 2 ) );
  101. }
  102. pixels[(y * height + x) * 3] = rColor;
  103. pixels[(y * height + x) * 3 + 1] = 0;
  104. pixels[(y * height + x) * 3 + 2] = bColor;
  105. }
  106. return pixels;
  107. }
  108. ///
  109. // Load texture from disk
  110. //
  111. GLuint LoadTexture ( char *fileName )
  112. {
  113. int width, height;
  114. char *buffer = esLoadTGA ( fileName, &width, &height );
  115. GLuint texId;
  116. if ( buffer == NULL )
  117. {
  118. esLogMessage ( "Error loading (%s) image.\n", fileName );
  119. return 0;
  120. }
  121. glGenTextures ( 1, &texId );
  122. glBindTexture ( GL_TEXTURE_2D, texId );
  123. glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer );
  124. glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  125. glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  126. glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
  127. glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
  128. free ( buffer );
  129. return texId;
  130. }
  131. ///
  132. // Create a mipmapped 2D texture image
  133. //
  134. GLuint CreateMipMappedTexture2D( )
  135. {
  136. // Texture object handle
  137. GLuint textureId;
  138. #if 0
  139. int width = 256,
  140. height = 256;
  141. int level;
  142. GLubyte *pixels;
  143. pixels = GenCheckImage( width, height, 8 );
  144. if ( pixels == NULL )
  145. return 0;
  146. // Generate a texture object
  147. glGenTextures ( 1, &textureId );
  148. // Bind the texture object
  149. glBindTexture ( GL_TEXTURE_2D, textureId );
  150. // Load mipmap level 0
  151. glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGB, width, height,
  152. 0, GL_RGB, GL_UNSIGNED_BYTE, pixels );
  153. GLubyte *prevImage;
  154. GLubyte *newImage;
  155. level = 1;
  156. prevImage = &pixels[0];
  157. while ( width > 1 && height > 1 )
  158. {
  159. int newWidth,
  160. newHeight;
  161. // Generate the next mipmap level
  162. GenMipMap2D( prevImage, &newImage, width, height,
  163. &newWidth, &newHeight );
  164. // Load the mipmap level
  165. glTexImage2D( GL_TEXTURE_2D, level, GL_RGB,
  166. newWidth, newHeight, 0, GL_RGB,
  167. GL_UNSIGNED_BYTE, newImage );
  168. // Free the previous image
  169. free ( prevImage );
  170. // Set the previous image for the next iteration
  171. prevImage = newImage;
  172. level++;
  173. // Half the width and height
  174. width = newWidth;
  175. height = newHeight;
  176. }
  177. free ( newImage );
  178. #else
  179. char *fileName = "D:/Projects/Visual Studio 2012/OpenGL_Demo/opengles-book-samples-master/Windows/Chapter_9/Simple_Texture2D/Fieldstone.tga";
  180. textureId = LoadTexture (fileName);
  181. glGenerateMipmap(GL_TEXTURE_2D);
  182. #endif
  183. // Set the filtering mode
  184. glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST );
  185. glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  186. return textureId;
  187. }
  188. ///
  189. // Initialize the shader and program object
  190. //
  191. int Init ( ESContext *esContext )
  192. {
  193. UserData *userData = esContext->userData;
  194. GLbyte vShaderStr[] =
  195. "uniform float u_offset; \n"
  196. "attribute vec4 a_position; \n"
  197. "attribute vec2 a_texCoord; \n"
  198. "varying vec2 v_texCoord; \n"
  199. "void main() \n"
  200. "{ \n"
  201. " gl_Position = a_position; \n"
  202. " gl_Position.x += u_offset;\n"
  203. " v_texCoord = a_texCoord; \n"
  204. "} \n";
  205. GLbyte fShaderStr[] =
  206. "precision mediump float; \n"
  207. "varying vec2 v_texCoord; \n"
  208. "uniform sampler2D s_texture; \n"
  209. "void main() \n"
  210. "{ \n"
  211. " gl_FragColor = texture2D( s_texture, v_texCoord );\n"
  212. "} \n";
  213. // Load the shaders and get a linked program object
  214. userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
  215. // Get the attribute locations
  216. userData->positionLoc = glGetAttribLocation ( userData->programObject, "a_position" );
  217. userData->texCoordLoc = glGetAttribLocation ( userData->programObject, "a_texCoord" );
  218. // Get the sampler location
  219. userData->samplerLoc = glGetUniformLocation ( userData->programObject, "s_texture" );
  220. // Get the offset location
  221. userData->offsetLoc = glGetUniformLocation( userData->programObject, "u_offset" );
  222. // Load the texture
  223. userData->textureId = CreateMipMappedTexture2D ();
  224. glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
  225. return TRUE;
  226. }
  227. ///
  228. // Draw a triangle using the shader pair created in Init()
  229. //
  230. void Draw ( ESContext *esContext )
  231. {
  232. UserData *userData = esContext->userData;
  233. GLfloat vVertices[] = { -0.5f, 0.5f, 0.0f, 1.5f, // Position 0
  234. 0.0f, 0.0f, // TexCoord 0
  235. -0.5f, -0.5f, 0.0f, 0.75f, // Position 1
  236. 0.0f, 1.0f, // TexCoord 1
  237. 0.5f, -0.5f, 0.0f, 0.75f, // Position 2
  238. 1.0f, 1.0f, // TexCoord 2
  239. 0.5f, 0.5f, 0.0f, 1.5f, // Position 3
  240. 1.0f, 0.0f // TexCoord 3
  241. };
  242. GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
  243. // Set the viewport
  244. glViewport ( 0, 0, esContext->width, esContext->height );
  245. // Clear the color buffer
  246. glClear ( GL_COLOR_BUFFER_BIT );
  247. // Use the program object
  248. glUseProgram ( userData->programObject );
  249. // Load the vertex position
  250. glVertexAttribPointer ( userData->positionLoc, 4, GL_FLOAT,
  251. GL_FALSE, 6 * sizeof(GLfloat), vVertices ); // 偏移量 4+2
  252. // Load the texture coordinate
  253. glVertexAttribPointer ( userData->texCoordLoc, 2, GL_FLOAT,
  254. GL_FALSE, 6 * sizeof(GLfloat), &vVertices[4] );
  255. glEnableVertexAttribArray ( userData->positionLoc );
  256. glEnableVertexAttribArray ( userData->texCoordLoc );
  257. // Bind the texture
  258. glActiveTexture ( GL_TEXTURE0 ); // 激活 texture unit 0
  259. glBindTexture ( GL_TEXTURE_2D, userData->textureId );
  260. // Set the sampler texture unit to 0
  261. glUniform1i ( userData->samplerLoc, 0 );
  262. // Draw quad with nearest sampling (LEFT)
  263. glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
  264. glUniform1f ( userData->offsetLoc, -0.6f );
  265. glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );
  266. // Draw quad with trilinear filtering (RIGHT)
  267. glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
  268. glUniform1f ( userData->offsetLoc, 0.6f );
  269. glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );
  270. eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );
  271. }
  272. ///
  273. // Cleanup
  274. //
  275. void ShutDown ( ESContext *esContext )
  276. {
  277. UserData *userData = esContext->userData;
  278. // Delete texture object
  279. glDeleteTextures ( 1, &userData->textureId );
  280. // Delete program object
  281. glDeleteProgram ( userData->programObject );
  282. }
  283. int main ( int argc, char *argv[] )
  284. {
  285. ESContext esContext;
  286. UserData userData;
  287. esInitContext ( &esContext );
  288. esContext.userData = &userData;
  289. esCreateWindow ( &esContext, "MipMap 2D", 640, 480, ES_WINDOW_RGB );
  290. if ( !Init ( &esContext ) )
  291. return 0;
  292. esRegisterDrawFunc ( &esContext, Draw );
  293. esMainLoop ( &esContext );
  294. ShutDown ( &esContext );
  295. }

效果如图:


文章来源: panda1234lee.blog.csdn.net,作者:panda1234lee,版权归原作者所有,如需转载,请联系作者。

原文链接:panda1234lee.blog.csdn.net/article/details/52409090

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。