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