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