132001f49Smrg/* 232001f49Smrg * Test GL_ARB_draw_buffers2, GL_ARB_draw_buffers, GL_EXT_framebuffer_object 332001f49Smrg * and GLSL's gl_FragData[]. 432001f49Smrg * 532001f49Smrg * We draw to two color buffers and show the left half of the first 632001f49Smrg * color buffer on the left side of the window, and show the right 732001f49Smrg * half of the second color buffer on the right side of the window. 832001f49Smrg * 932001f49Smrg * Different color masks are used for the two color buffers. 1032001f49Smrg * Blending is enabled for the second buffer only. 1132001f49Smrg * 1232001f49Smrg * Brian Paul 1332001f49Smrg * 31 Dec 2009 1432001f49Smrg */ 1532001f49Smrg 1632001f49Smrg 1732001f49Smrg#include <assert.h> 1832001f49Smrg#include <stdio.h> 1932001f49Smrg#include <stdlib.h> 2032001f49Smrg#include <math.h> 2132001f49Smrg#include <GL/glew.h> 2232001f49Smrg#include "glut_wrap.h" 2332001f49Smrg 2432001f49Smrg 2532001f49Smrgstatic int Win; 2632001f49Smrgstatic int Width = 400, Height = 400; 2732001f49Smrgstatic GLuint FBobject, RBobjects[3]; 2832001f49Smrgstatic GLfloat Xrot = 0.0, Yrot = 0.0; 2932001f49Smrgstatic GLuint Program; 3032001f49Smrgstatic GLboolean Anim = GL_TRUE; 3132001f49Smrg 3232001f49Smrg 3332001f49Smrgstatic void 3432001f49SmrgCheckError(int line) 3532001f49Smrg{ 3632001f49Smrg GLenum err = glGetError(); 3732001f49Smrg if (err) { 3832001f49Smrg printf("GL Error 0x%x at line %d\n", (int) err, line); 3932001f49Smrg } 4032001f49Smrg} 4132001f49Smrg 4232001f49Smrg 4332001f49Smrgstatic void 4432001f49SmrgDisplay(void) 4532001f49Smrg{ 4632001f49Smrg GLubyte *buffer = malloc(Width * Height * 4); 4732001f49Smrg static const GLenum buffers[2] = { 4832001f49Smrg GL_COLOR_ATTACHMENT0_EXT, 4932001f49Smrg GL_COLOR_ATTACHMENT1_EXT 5032001f49Smrg }; 5132001f49Smrg 5232001f49Smrg glUseProgram(Program); 5332001f49Smrg 5432001f49Smrg glEnable(GL_DEPTH_TEST); 5532001f49Smrg 5632001f49Smrg /* draw to user framebuffer */ 5732001f49Smrg glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBobject); 5832001f49Smrg 5932001f49Smrg /* Clear color buffer 0 (blue) */ 6032001f49Smrg glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); 6132001f49Smrg glClear(GL_COLOR_BUFFER_BIT); 6232001f49Smrg 6332001f49Smrg /* Clear color buffer 1 (1 - blue) */ 6432001f49Smrg glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT); 6532001f49Smrg glClear(GL_COLOR_BUFFER_BIT); 6632001f49Smrg 6732001f49Smrg glClear(GL_DEPTH_BUFFER_BIT); 6832001f49Smrg 6932001f49Smrg /* draw to two buffers w/ fragment shader */ 7032001f49Smrg glDrawBuffersARB(2, buffers); 7132001f49Smrg 7232001f49Smrg /* different color masks for each buffer */ 7332001f49Smrg if (1) { 7432001f49Smrg glColorMaskIndexedEXT(0, GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE); 7532001f49Smrg glColorMaskIndexedEXT(1, GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE); 7632001f49Smrg } 7732001f49Smrg 7832001f49Smrg glPushMatrix(); 7932001f49Smrg glRotatef(Xrot, 1, 0, 0); 8032001f49Smrg glRotatef(Yrot, 0, 1, 0); 8132001f49Smrg glPushMatrix(); 8232001f49Smrg glTranslatef(1, 0, 0); 8332001f49Smrg glutSolidTorus(1.0, 2.0, 10, 20); 8432001f49Smrg glPopMatrix(); 8532001f49Smrg glPushMatrix(); 8632001f49Smrg glTranslatef(-1, 0, 0); 8732001f49Smrg glRotatef(90, 1, 0, 0); 8832001f49Smrg glutSolidTorus(1.0, 2.0, 10, 20); 8932001f49Smrg glPopMatrix(); 9032001f49Smrg glPopMatrix(); 9132001f49Smrg 9232001f49Smrg /* restore default color masks */ 9332001f49Smrg glColorMaskIndexedEXT(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 9432001f49Smrg glColorMaskIndexedEXT(1, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 9532001f49Smrg 9632001f49Smrg /* read from user framebuffer */ 9732001f49Smrg /* left half = colorbuffer 0 */ 9832001f49Smrg glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); 9932001f49Smrg glPixelStorei(GL_PACK_ROW_LENGTH, Width); 10032001f49Smrg glPixelStorei(GL_PACK_SKIP_PIXELS, 0); 10132001f49Smrg glReadPixels(0, 0, Width / 2, Height, GL_RGBA, GL_UNSIGNED_BYTE, 10232001f49Smrg buffer); 10332001f49Smrg 10432001f49Smrg /* right half = colorbuffer 1 */ 10532001f49Smrg glReadBuffer(GL_COLOR_ATTACHMENT1_EXT); 10632001f49Smrg glPixelStorei(GL_PACK_SKIP_PIXELS, Width / 2); 10732001f49Smrg glReadPixels(Width / 2, 0, Width - Width / 2, Height, 10832001f49Smrg GL_RGBA, GL_UNSIGNED_BYTE, 10932001f49Smrg buffer); 11032001f49Smrg 11132001f49Smrg /* draw to window */ 11232001f49Smrg glUseProgram(0); 11332001f49Smrg glDisable(GL_DEPTH_TEST); 11432001f49Smrg glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 11532001f49Smrg glWindowPos2iARB(0, 0); 11632001f49Smrg glDrawPixels(Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); 11732001f49Smrg 11832001f49Smrg free(buffer); 11932001f49Smrg glutSwapBuffers(); 12032001f49Smrg CheckError(__LINE__); 12132001f49Smrg} 12232001f49Smrg 12332001f49Smrg 12432001f49Smrgstatic void 12532001f49SmrgIdle(void) 12632001f49Smrg{ 12732001f49Smrg Xrot = glutGet(GLUT_ELAPSED_TIME) * 0.05; 12832001f49Smrg glutPostRedisplay(); 12932001f49Smrg} 13032001f49Smrg 13132001f49Smrg 13232001f49Smrgstatic void 13332001f49SmrgReshape(int width, int height) 13432001f49Smrg{ 13532001f49Smrg float ar = (float) width / (float) height; 13632001f49Smrg 13732001f49Smrg glViewport(0, 0, width, height); 13832001f49Smrg glMatrixMode(GL_PROJECTION); 13932001f49Smrg glLoadIdentity(); 14032001f49Smrg glFrustum(-ar, ar, -1.0, 1.0, 5.0, 35.0); 14132001f49Smrg glMatrixMode(GL_MODELVIEW); 14232001f49Smrg glLoadIdentity(); 14332001f49Smrg glTranslatef(0.0, 0.0, -20.0); 14432001f49Smrg 14532001f49Smrg Width = width; 14632001f49Smrg Height = height; 14732001f49Smrg 14832001f49Smrg glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, RBobjects[0]); 14932001f49Smrg glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, Width, Height); 15032001f49Smrg glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, RBobjects[1]); 15132001f49Smrg glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, Width, Height); 15232001f49Smrg glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, RBobjects[2]); 15332001f49Smrg glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, 15432001f49Smrg Width, Height); 15532001f49Smrg} 15632001f49Smrg 15732001f49Smrg 15832001f49Smrgstatic void 15932001f49SmrgCleanUp(void) 16032001f49Smrg{ 16132001f49Smrg glDeleteFramebuffersEXT(1, &FBobject); 16232001f49Smrg glDeleteRenderbuffersEXT(3, RBobjects); 16332001f49Smrg glutDestroyWindow(Win); 16432001f49Smrg exit(0); 16532001f49Smrg} 16632001f49Smrg 16732001f49Smrg 16832001f49Smrgstatic void 16932001f49SmrgKey(unsigned char key, int x, int y) 17032001f49Smrg{ 17132001f49Smrg (void) x; 17232001f49Smrg (void) y; 17332001f49Smrg switch (key) { 17432001f49Smrg case ' ': 17532001f49Smrg Anim = !Anim; 17632001f49Smrg glutIdleFunc(Anim ? Idle : NULL); 17732001f49Smrg break; 17832001f49Smrg case 'x': 17932001f49Smrg Xrot += 5.0; 18032001f49Smrg break; 18132001f49Smrg case 'X': 18232001f49Smrg Xrot -= 5.0; 18332001f49Smrg break; 18432001f49Smrg case 'y': 18532001f49Smrg Yrot += 5.0; 18632001f49Smrg break; 18732001f49Smrg case 'Y': 18832001f49Smrg Yrot -= 5.0; 18932001f49Smrg break; 19032001f49Smrg case 27: 19132001f49Smrg CleanUp(); 19232001f49Smrg break; 19332001f49Smrg } 19432001f49Smrg glutPostRedisplay(); 19532001f49Smrg} 19632001f49Smrg 19732001f49Smrg 19832001f49Smrgstatic void 19932001f49SmrgCheckExtensions(void) 20032001f49Smrg{ 20132001f49Smrg const char *req[] = { 20232001f49Smrg "GL_EXT_framebuffer_object", 20332001f49Smrg "GL_ARB_draw_buffers", 20432001f49Smrg "GL_EXT_draw_buffers2" 20532001f49Smrg }; 20632001f49Smrg 20732001f49Smrg GLint numBuf; 20832001f49Smrg GLint i; 20932001f49Smrg 21032001f49Smrg for (i = 0; i < 3; i++) { 21132001f49Smrg if (!glutExtensionSupported(req[i])) { 21232001f49Smrg printf("Sorry, %s extension is required!\n", req[i]); 21332001f49Smrg exit(1); 21432001f49Smrg } 21532001f49Smrg } 21632001f49Smrg if (!GLEW_VERSION_2_0) { 21732001f49Smrg printf("Sorry, OpenGL 2.0 is required!\n"); 21832001f49Smrg exit(1); 21932001f49Smrg } 22032001f49Smrg 22132001f49Smrg glGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &numBuf); 22232001f49Smrg printf("GL_MAX_DRAW_BUFFERS_ARB = %d\n", numBuf); 22332001f49Smrg if (numBuf < 2) { 22432001f49Smrg printf("Sorry, GL_MAX_DRAW_BUFFERS_ARB needs to be >= 2\n"); 22532001f49Smrg exit(1); 22632001f49Smrg } 22732001f49Smrg 22832001f49Smrg printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); 22932001f49Smrg} 23032001f49Smrg 23132001f49Smrg 23232001f49Smrgstatic void 23332001f49SmrgSetupRenderbuffers(void) 23432001f49Smrg{ 23532001f49Smrg glGenFramebuffersEXT(1, &FBobject); 23632001f49Smrg glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBobject); 23732001f49Smrg 23832001f49Smrg glGenRenderbuffersEXT(3, RBobjects); 23932001f49Smrg 24032001f49Smrg glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, RBobjects[0]); 24132001f49Smrg glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, Width, Height); 24232001f49Smrg 24332001f49Smrg glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, RBobjects[1]); 24432001f49Smrg glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, Width, Height); 24532001f49Smrg 24632001f49Smrg glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, RBobjects[2]); 24732001f49Smrg glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, 24832001f49Smrg Width, Height); 24932001f49Smrg 25032001f49Smrg glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 25132001f49Smrg GL_RENDERBUFFER_EXT, RBobjects[0]); 25232001f49Smrg glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, 25332001f49Smrg GL_RENDERBUFFER_EXT, RBobjects[1]); 25432001f49Smrg glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, 25532001f49Smrg GL_RENDERBUFFER_EXT, RBobjects[2]); 25632001f49Smrg 25732001f49Smrg CheckError(__LINE__); 25832001f49Smrg} 25932001f49Smrg 26032001f49Smrg 26132001f49Smrgstatic GLuint 26232001f49SmrgLoadAndCompileShader(GLenum target, const char *text) 26332001f49Smrg{ 26432001f49Smrg GLint stat; 26532001f49Smrg GLuint shader = glCreateShader(target); 26632001f49Smrg glShaderSource(shader, 1, (const GLchar **) &text, NULL); 26732001f49Smrg glCompileShader(shader); 26832001f49Smrg glGetShaderiv(shader, GL_COMPILE_STATUS, &stat); 26932001f49Smrg if (!stat) { 27032001f49Smrg GLchar log[1000]; 27132001f49Smrg GLsizei len; 27232001f49Smrg glGetShaderInfoLog(shader, 1000, &len, log); 27332001f49Smrg fprintf(stderr, "drawbuffers: problem compiling shader:\n%s\n", log); 27432001f49Smrg exit(1); 27532001f49Smrg } 27632001f49Smrg return shader; 27732001f49Smrg} 27832001f49Smrg 27932001f49Smrg 28032001f49Smrgstatic void 28132001f49SmrgCheckLink(GLuint prog) 28232001f49Smrg{ 28332001f49Smrg GLint stat; 28432001f49Smrg glGetProgramiv(prog, GL_LINK_STATUS, &stat); 28532001f49Smrg if (!stat) { 28632001f49Smrg GLchar log[1000]; 28732001f49Smrg GLsizei len; 28832001f49Smrg glGetProgramInfoLog(prog, 1000, &len, log); 28932001f49Smrg fprintf(stderr, "drawbuffers: shader link error:\n%s\n", log); 29032001f49Smrg } 29132001f49Smrg} 29232001f49Smrg 29332001f49Smrg 29432001f49Smrgstatic void 29532001f49SmrgSetupShaders(void) 29632001f49Smrg{ 29732001f49Smrg /* emit same color to both draw buffers */ 29832001f49Smrg static const char *fragShaderText = 29932001f49Smrg "void main() {\n" 30032001f49Smrg " gl_FragData[0] = gl_Color; \n" 30132001f49Smrg " gl_FragData[1] = gl_Color; \n" 30232001f49Smrg "}\n"; 30332001f49Smrg 30432001f49Smrg GLuint fragShader; 30532001f49Smrg 30632001f49Smrg fragShader = LoadAndCompileShader(GL_FRAGMENT_SHADER, fragShaderText); 30732001f49Smrg Program = glCreateProgram(); 30832001f49Smrg 30932001f49Smrg glAttachShader(Program, fragShader); 31032001f49Smrg glLinkProgram(Program); 31132001f49Smrg CheckLink(Program); 31232001f49Smrg glUseProgram(Program); 31332001f49Smrg} 31432001f49Smrg 31532001f49Smrg 31632001f49Smrgstatic void 31732001f49SmrgSetupLighting(void) 31832001f49Smrg{ 31932001f49Smrg static const GLfloat ambient[4] = { 0.0, 0.0, 0.0, 0.0 }; 32032001f49Smrg static const GLfloat diffuse[4] = { 1.0, 1.0, 1.0, 0.75 }; 32132001f49Smrg 32232001f49Smrg glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); 32332001f49Smrg glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient); 32432001f49Smrg glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse); 32532001f49Smrg 32632001f49Smrg glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0); 32732001f49Smrg glEnable(GL_LIGHT0); 32832001f49Smrg glEnable(GL_LIGHTING); 32932001f49Smrg} 33032001f49Smrg 33132001f49Smrg 33232001f49Smrgstatic void 33332001f49SmrgInit(void) 33432001f49Smrg{ 33532001f49Smrg CheckExtensions(); 33632001f49Smrg SetupRenderbuffers(); 33732001f49Smrg SetupShaders(); 33832001f49Smrg SetupLighting(); 33932001f49Smrg glEnable(GL_DEPTH_TEST); 34032001f49Smrg 34132001f49Smrg glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 34232001f49Smrg glEnableIndexedEXT(GL_BLEND, 1); 34332001f49Smrg} 34432001f49Smrg 34532001f49Smrg 34632001f49Smrgint 34732001f49Smrgmain(int argc, char *argv[]) 34832001f49Smrg{ 34932001f49Smrg glutInit(&argc, argv); 35032001f49Smrg glutInitWindowPosition(0, 0); 35132001f49Smrg glutInitWindowSize(Width, Height); 35232001f49Smrg glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); 35332001f49Smrg Win = glutCreateWindow(argv[0]); 35432001f49Smrg glewInit(); 35532001f49Smrg glutIdleFunc(Anim ? Idle : NULL); 35632001f49Smrg glutReshapeFunc(Reshape); 35732001f49Smrg glutKeyboardFunc(Key); 35832001f49Smrg glutDisplayFunc(Display); 35932001f49Smrg Init(); 36032001f49Smrg glutMainLoop(); 36132001f49Smrg return 0; 36232001f49Smrg} 363