1 // 2 // Modified from Simple_Texture2D, found in: 3 // 4 // Book: OpenGL(R) ES 2.0 Programming Guide 5 // Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner 6 // ISBN-10: 0321502795 7 // ISBN-13: 9780321502797 8 // Publisher: Addison-Wesley Professional 9 // URLs: http://safari.informit.com/9780321563835 10 // http://www.opengles-book.com 11 // 12 13 // MultipleRenderTargets.c 14 // 15 // This is a simple example that shows how to use multiple render 16 // targets in GLES 2.0 using EXT_draw_buffers. The example 17 // draws to three render targets and displays 18 // them together in a final pass. 19 // 20 #include <stdlib.h> 21 #include "esUtil.h" 22 23 PFNGLDRAWBUFFERSEXTPROC glDrawBuffersEXT; 24 25 typedef struct 26 { 27 // Handle to a program object 28 GLuint programObjectMRT; 29 GLuint programObject; 30 31 // Attribute locations 32 GLint positionLoc; 33 GLint texCoordLoc; 34 35 // Sampler location 36 GLint samplerLoc; 37 38 // Texture handle 39 GLuint textureId; 40 41 // Framebuffer object handle 42 GLuint framebuffer; 43 44 // Framebuffer color attachments 45 GLuint framebufferTextures[4]; 46 47 } UserData; 48 49 /// 50 // Create a simple 2x2 texture image with four different colors 51 // 52 GLuint CreateSimpleTexture2D( ) 53 { 54 // Texture object handle 55 GLuint textureId; 56 57 // 2x2 Image, 3 bytes per pixel (R, G, B) 58 GLubyte pixels[4 * 3] = 59 { 60 255, 0, 0, // Red 61 0, 255, 0, // Green 62 0, 0, 255, // Blue 63 255, 255, 0 // Yellow 64 }; 65 66 // Use tightly packed data 67 glPixelStorei ( GL_UNPACK_ALIGNMENT, 1 ); 68 69 // Generate a texture object 70 glGenTextures ( 1, &textureId ); 71 72 // Bind the texture object 73 glBindTexture ( GL_TEXTURE_2D, textureId ); 74 75 // Load the texture 76 glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels ); 77 78 // Set the filtering mode 79 glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); 80 glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); 81 82 return textureId; 83 84 } 85 86 87 /// 88 // Initialize the shader and program object 89 // 90 int Init ( ESContext *esContext ) 91 { 92 UserData *userData = (UserData*)esContext->userData; 93 GLbyte vShaderStr[] = 94 "attribute vec4 a_position; \n" 95 "attribute vec2 a_texCoord; \n" 96 "varying vec2 v_texCoord; \n" 97 "void main() \n" 98 "{ \n" 99 " gl_Position = a_position; \n" 100 " v_texCoord = a_texCoord; \n" 101 "} \n"; 102 103 GLbyte fMultiShaderStr[] = 104 "#extension GL_EXT_draw_buffers : enable \n" 105 "precision mediump float; \n" 106 "varying vec2 v_texCoord; \n" 107 "uniform sampler2D s_texture; \n" 108 "void main() \n" 109 "{ \n" 110 " vec4 color = texture2D( s_texture, v_texCoord ); \n" 111 " gl_FragData[0] = color; \n" 112 " gl_FragData[1] = vec4(1.0, 1.0, 1.0, 1.0) - color.brga;\n" 113 " gl_FragData[2] = vec4(0.2, 1.0, 0.5, 1.0) * color.gbra;\n" 114 " gl_FragData[3] = color.rrra; \n" 115 "} \n"; 116 117 GLbyte fShaderStr[] = 118 "precision mediump float; \n" 119 "varying vec2 v_texCoord; \n" 120 "uniform sampler2D s_texture; \n" 121 "void main() \n" 122 "{ \n" 123 " vec4 color = texture2D( s_texture, v_texCoord ); \n" 124 " gl_FragColor = color; \n" 125 "} \n"; 126 127 int i; 128 129 // Check EXT_draw_buffers is supported 130 if (strstr(glGetString(GL_EXTENSIONS), "GL_EXT_draw_buffers") == 0) 131 { 132 return FALSE; 133 } 134 135 // Retrieve the address of glDrawBuffersEXT from EGL 136 glDrawBuffersEXT = (PFNGLDRAWBUFFERSEXTPROC)eglGetProcAddress("glDrawBuffersEXT"); 137 138 // Load the shaders and get a linked program object 139 userData->programObject = esLoadProgram ( (const char*)vShaderStr, (const char*)fShaderStr ); 140 141 userData->programObjectMRT = esLoadProgram ( (const char*)vShaderStr, (const char*)fMultiShaderStr ); 142 143 // Get the attribute locations 144 userData->positionLoc = glGetAttribLocation ( userData->programObject, "a_position" ); 145 userData->texCoordLoc = glGetAttribLocation ( userData->programObject, "a_texCoord" ); 146 147 // Get the sampler location 148 userData->samplerLoc = glGetUniformLocation ( userData->programObject, "s_texture" ); 149 150 // Load the texture 151 userData->textureId = CreateSimpleTexture2D (); 152 153 glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f ); 154 155 // Initialize the user framebuffer 156 glGenFramebuffers(1, &userData->framebuffer); 157 glGenTextures(4, userData->framebufferTextures); 158 159 glBindFramebuffer(GL_FRAMEBUFFER, userData->framebuffer); 160 161 for (i = 0; i < 4; i++) 162 { 163 // Create textures for the four color attachments 164 glBindTexture(GL_TEXTURE_2D, userData->framebufferTextures[i]); 165 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, esContext->width, esContext->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 166 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 167 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 168 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 169 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 170 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT + i, GL_TEXTURE_2D, userData->framebufferTextures[i], 0); 171 } 172 173 glBindTexture(GL_TEXTURE_2D, 0); 174 175 return TRUE; 176 } 177 178 /// 179 // Draw a triangle using the shader pair created in Init() 180 // 181 void Draw ( ESContext *esContext ) 182 { 183 UserData *userData = (UserData*)esContext->userData; 184 GLfloat vVertices[] = { -0.8f, 0.8f, 0.0f, // Position 0 185 0.0f, 0.0f, // TexCoord 0 186 -0.8f, -0.8f, 0.0f, // Position 1 187 0.0f, 1.0f, // TexCoord 1 188 0.8f, -0.8f, 0.0f, // Position 2 189 1.0f, 1.0f, // TexCoord 2 190 0.8f, 0.8f, 0.0f, // Position 3 191 1.0f, 0.0f // TexCoord 3 192 }; 193 GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; 194 195 GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_COLOR_ATTACHMENT3_EXT }; 196 197 // Enable drawing to the four color attachments of the user framebuffer 198 glBindFramebuffer(GL_FRAMEBUFFER, userData->framebuffer); 199 glDrawBuffersEXT(4, drawBuffers); 200 201 // Set the viewport 202 glViewport ( 0, 0, esContext->width, esContext->height ); 203 204 // Clear the color buffer 205 glClear ( GL_COLOR_BUFFER_BIT ); 206 207 // Use the program object 208 glUseProgram ( userData->programObjectMRT ); 209 210 // Load the vertex position 211 glVertexAttribPointer ( userData->positionLoc, 3, GL_FLOAT, 212 GL_FALSE, 5 * sizeof(GLfloat), vVertices ); 213 // Load the texture coordinate 214 glVertexAttribPointer ( userData->texCoordLoc, 2, GL_FLOAT, 215 GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3] ); 216 217 glEnableVertexAttribArray ( userData->positionLoc ); 218 glEnableVertexAttribArray ( userData->texCoordLoc ); 219 220 // Bind the texture 221 glActiveTexture ( GL_TEXTURE0 ); 222 glBindTexture ( GL_TEXTURE_2D, userData->textureId ); 223 224 // Set the sampler texture unit to 0 225 glUniform1i ( userData->samplerLoc, 0 ); 226 227 // Draw the textured quad to the four render targets 228 glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices ); 229 230 // Enable the default framebuffer and single textured drawing 231 glBindFramebuffer(GL_FRAMEBUFFER, 0); 232 glUseProgram ( userData->programObject ); 233 234 // Draw the four textured quads to a separate region in the viewport 235 glBindTexture( GL_TEXTURE_2D, userData->framebufferTextures[0]); 236 glViewport ( 0, 0, esContext->width/2, esContext->height/2 ); 237 glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices ); 238 239 glBindTexture( GL_TEXTURE_2D, userData->framebufferTextures[1]); 240 glViewport ( esContext->width/2, 0, esContext->width/2, esContext->height/2 ); 241 glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices ); 242 243 glBindTexture( GL_TEXTURE_2D, userData->framebufferTextures[2]); 244 glViewport ( 0, esContext->height/2, esContext->width/2, esContext->height/2 ); 245 glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices ); 246 247 glBindTexture( GL_TEXTURE_2D, userData->framebufferTextures[3]); 248 glViewport ( esContext->width/2, esContext->height/2, esContext->width/2, esContext->height/2 ); 249 glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices ); 250 251 eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface ); 252 } 253 254 /// 255 // Cleanup 256 // 257 void ShutDown ( ESContext *esContext ) 258 { 259 UserData *userData = (UserData*)esContext->userData; 260 261 glDeleteTextures(4, userData->framebufferTextures); 262 263 glDeleteFramebuffers(1, &userData->framebuffer); 264 265 // Delete texture object 266 glDeleteTextures ( 1, &userData->textureId ); 267 268 // Delete program object 269 glDeleteProgram ( userData->programObject ); 270 271 eglDestroyContext(esContext->eglDisplay, esContext->eglContext); 272 eglDestroySurface(esContext->eglDisplay, esContext->eglSurface); 273 eglTerminate(esContext->eglDisplay); 274 } 275 276 277 int main ( int argc, char *argv[] ) 278 { 279 ESContext esContext; 280 UserData userData; 281 282 esInitContext ( &esContext ); 283 esContext.userData = &userData; 284 285 esCreateWindow ( &esContext, TEXT("Multiple Render Targets"), 320, 240, ES_WINDOW_RGB ); 286 287 if ( !Init ( &esContext ) ) 288 return 0; 289 290 esRegisterDrawFunc ( &esContext, Draw ); 291 292 esMainLoop ( &esContext ); 293 294 ShutDown ( &esContext ); 295 } 296