1/* 2 * Test GL_ARB_draw_buffers2, GL_ARB_draw_buffers, GL_EXT_framebuffer_object 3 * and GLSL's gl_FragData[]. 4 * 5 * We draw to two color buffers and show the left half of the first 6 * color buffer on the left side of the window, and show the right 7 * half of the second color buffer on the right side of the window. 8 * 9 * Different color masks are used for the two color buffers. 10 * Blending is enabled for the second buffer only. 11 * 12 * Brian Paul 13 * 31 Dec 2009 14 */ 15 16 17#include <assert.h> 18#include <stdio.h> 19#include <stdlib.h> 20#include <math.h> 21#include <GL/glew.h> 22#include "glut_wrap.h" 23 24 25static int Win; 26static int Width = 400, Height = 400; 27static GLuint FBobject, RBobjects[3]; 28static GLfloat Xrot = 0.0, Yrot = 0.0; 29static GLuint Program; 30static GLboolean Anim = GL_TRUE; 31 32 33static void 34CheckError(int line) 35{ 36 GLenum err = glGetError(); 37 if (err) { 38 printf("GL Error 0x%x at line %d\n", (int) err, line); 39 } 40} 41 42 43static void 44Display(void) 45{ 46 GLubyte *buffer = malloc(Width * Height * 4); 47 static const GLenum buffers[2] = { 48 GL_COLOR_ATTACHMENT0_EXT, 49 GL_COLOR_ATTACHMENT1_EXT 50 }; 51 52 glUseProgram(Program); 53 54 glEnable(GL_DEPTH_TEST); 55 56 /* draw to user framebuffer */ 57 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBobject); 58 59 /* Clear color buffer 0 (blue) */ 60 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); 61 glClear(GL_COLOR_BUFFER_BIT); 62 63 /* Clear color buffer 1 (1 - blue) */ 64 glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT); 65 glClear(GL_COLOR_BUFFER_BIT); 66 67 glClear(GL_DEPTH_BUFFER_BIT); 68 69 /* draw to two buffers w/ fragment shader */ 70 glDrawBuffersARB(2, buffers); 71 72 /* different color masks for each buffer */ 73 if (1) { 74 glColorMaskIndexedEXT(0, GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE); 75 glColorMaskIndexedEXT(1, GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE); 76 } 77 78 glPushMatrix(); 79 glRotatef(Xrot, 1, 0, 0); 80 glRotatef(Yrot, 0, 1, 0); 81 glPushMatrix(); 82 glTranslatef(1, 0, 0); 83 glutSolidTorus(1.0, 2.0, 10, 20); 84 glPopMatrix(); 85 glPushMatrix(); 86 glTranslatef(-1, 0, 0); 87 glRotatef(90, 1, 0, 0); 88 glutSolidTorus(1.0, 2.0, 10, 20); 89 glPopMatrix(); 90 glPopMatrix(); 91 92 /* restore default color masks */ 93 glColorMaskIndexedEXT(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 94 glColorMaskIndexedEXT(1, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 95 96 /* read from user framebuffer */ 97 /* left half = colorbuffer 0 */ 98 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); 99 glPixelStorei(GL_PACK_ROW_LENGTH, Width); 100 glPixelStorei(GL_PACK_SKIP_PIXELS, 0); 101 glReadPixels(0, 0, Width / 2, Height, GL_RGBA, GL_UNSIGNED_BYTE, 102 buffer); 103 104 /* right half = colorbuffer 1 */ 105 glReadBuffer(GL_COLOR_ATTACHMENT1_EXT); 106 glPixelStorei(GL_PACK_SKIP_PIXELS, Width / 2); 107 glReadPixels(Width / 2, 0, Width - Width / 2, Height, 108 GL_RGBA, GL_UNSIGNED_BYTE, 109 buffer); 110 111 /* draw to window */ 112 glUseProgram(0); 113 glDisable(GL_DEPTH_TEST); 114 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 115 glWindowPos2iARB(0, 0); 116 glDrawPixels(Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); 117 118 free(buffer); 119 glutSwapBuffers(); 120 CheckError(__LINE__); 121} 122 123 124static void 125Idle(void) 126{ 127 Xrot = glutGet(GLUT_ELAPSED_TIME) * 0.05; 128 glutPostRedisplay(); 129} 130 131 132static void 133Reshape(int width, int height) 134{ 135 float ar = (float) width / (float) height; 136 137 glViewport(0, 0, width, height); 138 glMatrixMode(GL_PROJECTION); 139 glLoadIdentity(); 140 glFrustum(-ar, ar, -1.0, 1.0, 5.0, 35.0); 141 glMatrixMode(GL_MODELVIEW); 142 glLoadIdentity(); 143 glTranslatef(0.0, 0.0, -20.0); 144 145 Width = width; 146 Height = height; 147 148 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, RBobjects[0]); 149 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, Width, Height); 150 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, RBobjects[1]); 151 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, Width, Height); 152 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, RBobjects[2]); 153 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, 154 Width, Height); 155} 156 157 158static void 159CleanUp(void) 160{ 161 glDeleteFramebuffersEXT(1, &FBobject); 162 glDeleteRenderbuffersEXT(3, RBobjects); 163 glutDestroyWindow(Win); 164 exit(0); 165} 166 167 168static void 169Key(unsigned char key, int x, int y) 170{ 171 (void) x; 172 (void) y; 173 switch (key) { 174 case ' ': 175 Anim = !Anim; 176 glutIdleFunc(Anim ? Idle : NULL); 177 break; 178 case 'x': 179 Xrot += 5.0; 180 break; 181 case 'X': 182 Xrot -= 5.0; 183 break; 184 case 'y': 185 Yrot += 5.0; 186 break; 187 case 'Y': 188 Yrot -= 5.0; 189 break; 190 case 27: 191 CleanUp(); 192 break; 193 } 194 glutPostRedisplay(); 195} 196 197 198static void 199CheckExtensions(void) 200{ 201 const char *req[] = { 202 "GL_EXT_framebuffer_object", 203 "GL_ARB_draw_buffers", 204 "GL_EXT_draw_buffers2" 205 }; 206 207 GLint numBuf; 208 GLint i; 209 210 for (i = 0; i < 3; i++) { 211 if (!glutExtensionSupported(req[i])) { 212 printf("Sorry, %s extension is required!\n", req[i]); 213 exit(1); 214 } 215 } 216 if (!GLEW_VERSION_2_0) { 217 printf("Sorry, OpenGL 2.0 is required!\n"); 218 exit(1); 219 } 220 221 glGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &numBuf); 222 printf("GL_MAX_DRAW_BUFFERS_ARB = %d\n", numBuf); 223 if (numBuf < 2) { 224 printf("Sorry, GL_MAX_DRAW_BUFFERS_ARB needs to be >= 2\n"); 225 exit(1); 226 } 227 228 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); 229} 230 231 232static void 233SetupRenderbuffers(void) 234{ 235 glGenFramebuffersEXT(1, &FBobject); 236 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBobject); 237 238 glGenRenderbuffersEXT(3, RBobjects); 239 240 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, RBobjects[0]); 241 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, Width, Height); 242 243 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, RBobjects[1]); 244 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, Width, Height); 245 246 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, RBobjects[2]); 247 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, 248 Width, Height); 249 250 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 251 GL_RENDERBUFFER_EXT, RBobjects[0]); 252 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, 253 GL_RENDERBUFFER_EXT, RBobjects[1]); 254 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, 255 GL_RENDERBUFFER_EXT, RBobjects[2]); 256 257 CheckError(__LINE__); 258} 259 260 261static GLuint 262LoadAndCompileShader(GLenum target, const char *text) 263{ 264 GLint stat; 265 GLuint shader = glCreateShader(target); 266 glShaderSource(shader, 1, (const GLchar **) &text, NULL); 267 glCompileShader(shader); 268 glGetShaderiv(shader, GL_COMPILE_STATUS, &stat); 269 if (!stat) { 270 GLchar log[1000]; 271 GLsizei len; 272 glGetShaderInfoLog(shader, 1000, &len, log); 273 fprintf(stderr, "drawbuffers: problem compiling shader:\n%s\n", log); 274 exit(1); 275 } 276 return shader; 277} 278 279 280static void 281CheckLink(GLuint prog) 282{ 283 GLint stat; 284 glGetProgramiv(prog, GL_LINK_STATUS, &stat); 285 if (!stat) { 286 GLchar log[1000]; 287 GLsizei len; 288 glGetProgramInfoLog(prog, 1000, &len, log); 289 fprintf(stderr, "drawbuffers: shader link error:\n%s\n", log); 290 } 291} 292 293 294static void 295SetupShaders(void) 296{ 297 /* emit same color to both draw buffers */ 298 static const char *fragShaderText = 299 "void main() {\n" 300 " gl_FragData[0] = gl_Color; \n" 301 " gl_FragData[1] = gl_Color; \n" 302 "}\n"; 303 304 GLuint fragShader; 305 306 fragShader = LoadAndCompileShader(GL_FRAGMENT_SHADER, fragShaderText); 307 Program = glCreateProgram(); 308 309 glAttachShader(Program, fragShader); 310 glLinkProgram(Program); 311 CheckLink(Program); 312 glUseProgram(Program); 313} 314 315 316static void 317SetupLighting(void) 318{ 319 static const GLfloat ambient[4] = { 0.0, 0.0, 0.0, 0.0 }; 320 static const GLfloat diffuse[4] = { 1.0, 1.0, 1.0, 0.75 }; 321 322 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); 323 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient); 324 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse); 325 326 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0); 327 glEnable(GL_LIGHT0); 328 glEnable(GL_LIGHTING); 329} 330 331 332static void 333Init(void) 334{ 335 CheckExtensions(); 336 SetupRenderbuffers(); 337 SetupShaders(); 338 SetupLighting(); 339 glEnable(GL_DEPTH_TEST); 340 341 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 342 glEnableIndexedEXT(GL_BLEND, 1); 343} 344 345 346int 347main(int argc, char *argv[]) 348{ 349 glutInit(&argc, argv); 350 glutInitWindowPosition(0, 0); 351 glutInitWindowSize(Width, Height); 352 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); 353 Win = glutCreateWindow(argv[0]); 354 glewInit(); 355 glutIdleFunc(Anim ? Idle : NULL); 356 glutReshapeFunc(Reshape); 357 glutKeyboardFunc(Key); 358 glutDisplayFunc(Display); 359 Init(); 360 glutMainLoop(); 361 return 0; 362} 363