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