Merge branch 'gallium-0.1' into gallium-tex-surfaces
[mesa.git] / progs / tests / fbotexture.c
1 /*
2 * Test GL_EXT_framebuffer_object render-to-texture
3 *
4 * Draw a teapot into a texture image with stenciling.
5 * Then draw a textured quad using that texture.
6 *
7 * Brian Paul
8 * 18 Apr 2005
9 */
10
11
12 #define GL_GLEXT_PROTOTYPES
13 #include <GL/glut.h>
14 #include <assert.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <math.h>
19
20 /* For debug */
21 #define DEPTH 1
22 #define STENCIL 1
23 #define DRAW 1
24
25
26 static int Win = 0;
27 static int Width = 400, Height = 400;
28
29 static GLenum TexTarget = GL_TEXTURE_2D; /*GL_TEXTURE_RECTANGLE_ARB;*/
30 static int TexWidth = 512, TexHeight = 512;
31 /*static int TexWidth = 600, TexHeight = 600;*/
32
33 static GLuint MyFB;
34 static GLuint TexObj;
35 static GLuint DepthRB, StencilRB;
36 static GLboolean Anim = GL_FALSE;
37 static GLfloat Rot = 0.0;
38 static GLboolean UsePackedDepthStencil = GL_FALSE;
39 static GLuint TextureLevel = 1; /* which texture level to render to */
40 static GLenum TexIntFormat = GL_RGB; /* either GL_RGB or GL_RGBA */
41
42
43 static void
44 CheckError(int line)
45 {
46 GLenum err = glGetError();
47 if (err) {
48 printf("GL Error 0x%x at line %d\n", (int) err, line);
49 }
50 }
51
52
53 static void
54 Idle(void)
55 {
56 Rot = glutGet(GLUT_ELAPSED_TIME) * 0.1;
57 glutPostRedisplay();
58 }
59
60
61 static void
62 RenderTexture(void)
63 {
64 GLenum status;
65
66 glMatrixMode(GL_PROJECTION);
67 glLoadIdentity();
68 glOrtho(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
69 glMatrixMode(GL_MODELVIEW);
70 glLoadIdentity();
71 glTranslatef(0.0, 0.0, -15.0);
72
73 /* draw to texture image */
74 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, MyFB);
75
76 status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
77 if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
78 printf("Framebuffer incomplete!!!\n");
79 }
80
81 glViewport(0, 0, TexWidth, TexHeight);
82
83 glClearColor(0.5, 0.5, 1.0, 0.0);
84 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
85 CheckError(__LINE__);
86
87 #if DEPTH
88 glEnable(GL_DEPTH_TEST);
89 #endif
90
91 #if STENCIL
92 glEnable(GL_STENCIL_TEST);
93 glStencilFunc(GL_NEVER, 1, ~0);
94 glStencilOp(GL_REPLACE, GL_KEEP, GL_REPLACE);
95 #endif
96
97 CheckError(__LINE__);
98
99 #if DEPTH || STENCIL
100 /* draw diamond-shaped stencil pattern */
101 glColor3f(0, 1, 0);
102 glBegin(GL_POLYGON);
103 glVertex2f(-0.2, 0.0);
104 glVertex2f( 0.0, -0.2);
105 glVertex2f( 0.2, 0.0);
106 glVertex2f( 0.0, 0.2);
107 glEnd();
108 #endif
109
110 /* draw teapot where stencil != 1 */
111 #if STENCIL
112 glStencilFunc(GL_NOTEQUAL, 1, ~0);
113 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
114 #endif
115
116 CheckError(__LINE__);
117
118 #if 0
119 glBegin(GL_POLYGON);
120 glColor3f(1, 0, 0);
121 glVertex2f(-1, -1);
122 glColor3f(0, 1, 0);
123 glVertex2f(1, -1);
124 glColor3f(0, 0, 1);
125 glVertex2f(0, 1);
126 glEnd();
127 #else
128 glEnable(GL_LIGHTING);
129 glEnable(GL_LIGHT0);
130 glPushMatrix();
131 glRotatef(0.5 * Rot, 1.0, 0.0, 0.0);
132 glutSolidTeapot(0.5);
133 glPopMatrix();
134 glDisable(GL_LIGHTING);
135 /*
136 PrintStencilHistogram(TexWidth, TexHeight);
137 */
138 #endif
139
140 glDisable(GL_DEPTH_TEST);
141 glDisable(GL_STENCIL_TEST);
142
143 #if DRAW
144 /* Bind normal framebuffer */
145 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
146 #endif
147
148 CheckError(__LINE__);
149 }
150
151
152
153 static void
154 Display(void)
155 {
156 float ar = (float) Width / (float) Height;
157
158 RenderTexture();
159
160 /* draw textured quad in the window */
161 #if DRAW
162 glMatrixMode(GL_PROJECTION);
163 glLoadIdentity();
164 glFrustum(-ar, ar, -1.0, 1.0, 5.0, 25.0);
165 glMatrixMode(GL_MODELVIEW);
166 glLoadIdentity();
167 glTranslatef(0.0, 0.0, -7.0);
168
169 glViewport(0, 0, Width, Height);
170
171 glClearColor(0.25, 0.25, 0.25, 0);
172 glClear(GL_COLOR_BUFFER_BIT);
173
174 glPushMatrix();
175 glRotatef(Rot, 0, 1, 0);
176 glEnable(TexTarget);
177 glBindTexture(TexTarget, TexObj);
178 glBegin(GL_POLYGON);
179 glColor3f(0.25, 0.25, 0.25);
180 if (TexTarget == GL_TEXTURE_2D) {
181 glTexCoord2f(0, 0);
182 glVertex2f(-1, -1);
183 glTexCoord2f(1, 0);
184 glVertex2f(1, -1);
185 glColor3f(1.0, 1.0, 1.0);
186 glTexCoord2f(1, 1);
187 glVertex2f(1, 1);
188 glTexCoord2f(0, 1);
189 glVertex2f(-1, 1);
190 }
191 else {
192 assert(TexTarget == GL_TEXTURE_RECTANGLE_ARB);
193 glTexCoord2f(0, 0);
194 glVertex2f(-1, -1);
195 glTexCoord2f(TexWidth, 0);
196 glVertex2f(1, -1);
197 glColor3f(1.0, 1.0, 1.0);
198 glTexCoord2f(TexWidth, TexHeight);
199 glVertex2f(1, 1);
200 glTexCoord2f(0, TexHeight);
201 glVertex2f(-1, 1);
202 }
203 glEnd();
204 glPopMatrix();
205 glDisable(TexTarget);
206 #endif
207
208 glutSwapBuffers();
209 CheckError(__LINE__);
210 }
211
212
213 static void
214 Reshape(int width, int height)
215 {
216 glViewport(0, 0, width, height);
217 Width = width;
218 Height = height;
219 }
220
221
222 static void
223 CleanUp(void)
224 {
225 #if DEPTH
226 glDeleteRenderbuffersEXT(1, &DepthRB);
227 #endif
228 #if STENCIL
229 if (!UsePackedDepthStencil)
230 glDeleteRenderbuffersEXT(1, &StencilRB);
231 #endif
232 glDeleteFramebuffersEXT(1, &MyFB);
233
234 glDeleteTextures(1, &TexObj);
235
236 glutDestroyWindow(Win);
237
238 exit(0);
239 }
240
241
242 static void
243 Key(unsigned char key, int x, int y)
244 {
245 (void) x;
246 (void) y;
247 switch (key) {
248 case 'a':
249 Anim = !Anim;
250 if (Anim)
251 glutIdleFunc(Idle);
252 else
253 glutIdleFunc(NULL);
254 break;
255 case 's':
256 Rot += 2.0;
257 break;
258 case 27:
259 CleanUp();
260 break;
261 }
262 glutPostRedisplay();
263 }
264
265
266 static void
267 Init(int argc, char *argv[])
268 {
269 static const GLfloat mat[4] = { 1.0, 0.5, 0.5, 1.0 };
270 GLint i;
271
272 if (!glutExtensionSupported("GL_EXT_framebuffer_object")) {
273 printf("GL_EXT_framebuffer_object not found!\n");
274 exit(0);
275 }
276
277 if (argc > 1 && strcmp(argv[1], "-ds") == 0) {
278 if (!glutExtensionSupported("GL_EXT_packed_depth_stencil")) {
279 printf("GL_EXT_packed_depth_stencil not found!\n");
280 exit(0);
281 }
282 UsePackedDepthStencil = GL_TRUE;
283 printf("Using GL_EXT_packed_depth_stencil\n");
284 }
285
286 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
287
288 /* gen framebuffer id, delete it, do some assertions, just for testing */
289 glGenFramebuffersEXT(1, &MyFB);
290 assert(MyFB);
291 assert(!glIsFramebufferEXT(MyFB));
292 glDeleteFramebuffersEXT(1, &MyFB);
293 assert(!glIsFramebufferEXT(MyFB));
294 /* Note, continue to use MyFB below */
295
296 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, MyFB);
297 assert(glIsFramebufferEXT(MyFB));
298 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &i);
299 assert(i == MyFB);
300
301 /* Make texture object/image */
302 glGenTextures(1, &TexObj);
303 glBindTexture(TexTarget, TexObj);
304 /* make two image levels */
305 glTexImage2D(TexTarget, 0, TexIntFormat, TexWidth, TexHeight, 0,
306 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
307 glTexImage2D(TexTarget, 1, TexIntFormat, TexWidth/2, TexHeight/2, 0,
308 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
309 TexWidth = TexWidth >> TextureLevel;
310 TexHeight = TexHeight >> TextureLevel;
311
312 glTexParameteri(TexTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
313 glTexParameteri(TexTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
314 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
315 glTexParameteri(TexTarget, GL_TEXTURE_BASE_LEVEL, TextureLevel);
316 glTexParameteri(TexTarget, GL_TEXTURE_MAX_LEVEL, TextureLevel);
317
318 CheckError(__LINE__);
319
320 /* Render color to texture */
321 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
322 TexTarget, TexObj, TextureLevel);
323
324
325 #if DEPTH
326 /* make depth renderbuffer */
327 glGenRenderbuffersEXT(1, &DepthRB);
328 assert(DepthRB);
329 assert(!glIsRenderbufferEXT(DepthRB));
330 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, DepthRB);
331 assert(glIsRenderbufferEXT(DepthRB));
332 if (UsePackedDepthStencil)
333 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT,
334 TexWidth, TexHeight);
335 else
336 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT,
337 TexWidth, TexHeight);
338 CheckError(__LINE__);
339 glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT,
340 GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
341 CheckError(__LINE__);
342 printf("Depth renderbuffer size = %d bits\n", i);
343 assert(i > 0);
344
345 /* attach DepthRB to MyFB */
346 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
347 GL_RENDERBUFFER_EXT, DepthRB);
348 #endif
349
350 CheckError(__LINE__);
351
352 #if STENCIL
353 if (UsePackedDepthStencil) {
354 /* DepthRb is a combined depth/stencil renderbuffer */
355 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
356 GL_STENCIL_ATTACHMENT_EXT,
357 GL_RENDERBUFFER_EXT, DepthRB);
358 }
359 else {
360 /* make stencil renderbuffer */
361 glGenRenderbuffersEXT(1, &StencilRB);
362 assert(StencilRB);
363 assert(!glIsRenderbufferEXT(StencilRB));
364 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, StencilRB);
365 assert(glIsRenderbufferEXT(StencilRB));
366 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX,
367 TexWidth, TexHeight);
368 /* attach StencilRB to MyFB */
369 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
370 GL_STENCIL_ATTACHMENT_EXT,
371 GL_RENDERBUFFER_EXT, StencilRB);
372 }
373 glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT,
374 GL_RENDERBUFFER_STENCIL_SIZE_EXT, &i);
375 CheckError(__LINE__);
376 printf("Stencil renderbuffer size = %d bits\n", i);
377 assert(i > 0);
378 #endif
379
380 CheckError(__LINE__);
381
382 /* bind regular framebuffer */
383 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
384
385
386 /* lighting */
387 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat);
388 }
389
390
391 int
392 main(int argc, char *argv[])
393 {
394 glutInit(&argc, argv);
395 glutInitWindowPosition(0, 0);
396 glutInitWindowSize(Width, Height);
397 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
398 Win = glutCreateWindow(argv[0]);
399 glutReshapeFunc(Reshape);
400 glutKeyboardFunc(Key);
401 glutDisplayFunc(Display);
402 if (Anim)
403 glutIdleFunc(Idle);
404 Init(argc, argv);
405 glutMainLoop();
406 return 0;
407 }