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