2 * Test GL_EXT_framebuffer_object render-to-texture
4 * Draw a teapot into a texture image with stenciling.
5 * Then draw a textured quad using that texture.
27 static int Width
= 400, Height
= 400;
30 static GLenum TexTarget
= GL_TEXTURE_2D
;
31 static int TexWidth
= 512, TexHeight
= 512;
32 static GLenum TexIntFormat
= GL_RGB
; /* either GL_RGB or GL_RGBA */
34 static GLenum TexTarget
= GL_TEXTURE_RECTANGLE_ARB
;
35 static int TexWidth
= 200, TexHeight
= 200;
36 static GLenum TexIntFormat
= GL_RGB5
; /* either GL_RGB or GL_RGBA */
38 static GLuint TextureLevel
= 0; /* which texture level to render to */
42 static GLuint DepthRB
= 0, StencilRB
= 0;
43 static GLboolean Anim
= GL_FALSE
;
44 static GLfloat Rot
= 0.0;
45 static GLboolean UsePackedDepthStencil
= GL_FALSE
;
46 static GLboolean UsePackedDepthStencilBoth
= GL_FALSE
;
47 static GLboolean Use_ARB_fbo
= GL_FALSE
;
48 static GLboolean Cull
= GL_FALSE
;
49 static GLboolean Wireframe
= GL_FALSE
;
55 GLenum err
= glGetError();
57 printf("GL Error 0x%x at line %d\n", (int) err
, line
);
65 Rot
= glutGet(GLUT_ELAPSED_TIME
) * 0.1;
75 glMatrixMode(GL_PROJECTION
);
77 glOrtho(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
78 glMatrixMode(GL_MODELVIEW
);
80 glTranslatef(0.0, 0.0, -15.0);
82 /* draw to texture image */
83 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, MyFB
);
85 status
= glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT
);
86 if (status
!= GL_FRAMEBUFFER_COMPLETE_EXT
) {
87 printf("Framebuffer incomplete!!!\n");
90 glViewport(0, 0, TexWidth
, TexHeight
);
92 glClearColor(0.5, 0.5, 1.0, 0.0);
93 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
| GL_STENCIL_BUFFER_BIT
);
97 glEnable(GL_DEPTH_TEST
);
101 glEnable(GL_STENCIL_TEST
);
102 glStencilFunc(GL_NEVER
, 1, ~0);
103 glStencilOp(GL_REPLACE
, GL_KEEP
, GL_REPLACE
);
106 CheckError(__LINE__
);
109 /* draw diamond-shaped stencil pattern */
112 glVertex2f(-0.2, 0.0);
113 glVertex2f( 0.0, -0.2);
114 glVertex2f( 0.2, 0.0);
115 glVertex2f( 0.0, 0.2);
119 /* draw teapot where stencil != 1 */
121 glStencilFunc(GL_NOTEQUAL
, 1, ~0);
122 glStencilOp(GL_KEEP
, GL_KEEP
, GL_KEEP
);
125 CheckError(__LINE__
);
128 glPolygonMode(GL_FRONT
, GL_LINE
);
131 glPolygonMode(GL_FRONT
, GL_FILL
);
137 glEnable(GL_CULL_FACE
);
140 glDisable(GL_CULL_FACE
);
153 glEnable(GL_LIGHTING
);
156 glRotatef(0.5 * Rot
, 1.0, 0.0, 0.0);
157 glFrontFace(GL_CW
); /* Teapot patches backward */
158 glutSolidTeapot(0.5);
161 glDisable(GL_LIGHTING
);
163 PrintStencilHistogram(TexWidth, TexHeight);
167 glDisable(GL_DEPTH_TEST
);
168 glDisable(GL_STENCIL_TEST
);
169 glDisable(GL_CULL_FACE
);
170 glPolygonMode(GL_FRONT_AND_BACK
, GL_FILL
);
173 /* Bind normal framebuffer */
174 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0);
177 CheckError(__LINE__
);
185 float ar
= (float) Width
/ (float) Height
;
189 /* draw textured quad in the window */
191 glMatrixMode(GL_PROJECTION
);
193 glFrustum(-ar
, ar
, -1.0, 1.0, 5.0, 25.0);
194 glMatrixMode(GL_MODELVIEW
);
196 glTranslatef(0.0, 0.0, -7.0);
198 glViewport(0, 0, Width
, Height
);
200 glClearColor(0.25, 0.25, 0.25, 0);
201 glClear(GL_COLOR_BUFFER_BIT
);
204 glRotatef(Rot
, 0, 1, 0);
206 glBindTexture(TexTarget
, TexObj
);
208 glColor3f(0.25, 0.25, 0.25);
209 if (TexTarget
== GL_TEXTURE_2D
) {
214 glColor3f(1.0, 1.0, 1.0);
221 assert(TexTarget
== GL_TEXTURE_RECTANGLE_ARB
);
224 glTexCoord2f(TexWidth
, 0);
226 glColor3f(1.0, 1.0, 1.0);
227 glTexCoord2f(TexWidth
, TexHeight
);
229 glTexCoord2f(0, TexHeight
);
234 glDisable(TexTarget
);
238 CheckError(__LINE__
);
243 Reshape(int width
, int height
)
245 glViewport(0, 0, width
, height
);
255 glDeleteRenderbuffersEXT(1, &DepthRB
);
258 glDeleteRenderbuffersEXT(1, &StencilRB
);
260 glDeleteFramebuffersEXT(1, &MyFB
);
262 glDeleteTextures(1, &TexObj
);
264 glutDestroyWindow(Win
);
271 Key(unsigned char key
, int x
, int y
)
287 Wireframe
= !Wireframe
;
304 * Attach depth and stencil renderbuffer(s) to the given framebuffer object.
305 * \param tryDepthStencil if true, try to use a combined depth+stencil buffer
306 * \param bindDepthStencil if true, and tryDepthStencil is true, bind with
307 * the GL_DEPTH_STENCIL_ATTACHMENT target.
308 * \return GL_TRUE for success, GL_FALSE for failure
311 AttachDepthAndStencilBuffers(GLuint fbo
,
312 GLsizei width
, GLsizei height
,
313 GLboolean tryDepthStencil
,
314 GLboolean bindDepthStencil
,
315 GLuint
*depthRbOut
, GLuint
*stencilRbOut
)
319 *depthRbOut
= *stencilRbOut
= 0;
321 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, fbo
);
323 if (tryDepthStencil
) {
326 glGenRenderbuffersEXT(1, &rb
);
327 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT
, rb
);
328 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT
,
329 GL_DEPTH24_STENCIL8_EXT
,
334 if (bindDepthStencil
) {
335 /* attach to both depth and stencil at once */
336 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
,
337 GL_DEPTH_STENCIL_ATTACHMENT
,
338 GL_RENDERBUFFER_EXT
, rb
);
343 /* attach to depth attachment point */
344 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
,
345 GL_DEPTH_ATTACHMENT_EXT
,
346 GL_RENDERBUFFER_EXT
, rb
);
350 /* and attach to stencil attachment point */
351 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
,
352 GL_STENCIL_ATTACHMENT_EXT
,
353 GL_RENDERBUFFER_EXT
, rb
);
358 status
= glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT
);
359 if (status
!= GL_FRAMEBUFFER_COMPLETE_EXT
)
362 *depthRbOut
= *stencilRbOut
= rb
;
366 /* just depth renderbuffer */
370 glGenRenderbuffersEXT(1, &rb
);
371 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT
, rb
);
372 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT
,
378 /* attach to depth attachment point */
379 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
,
380 GL_DEPTH_ATTACHMENT_EXT
,
381 GL_RENDERBUFFER_EXT
, rb
);
385 status
= glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT
);
386 if (status
!= GL_FRAMEBUFFER_COMPLETE_EXT
)
392 /* just stencil renderbuffer */
396 glGenRenderbuffersEXT(1, &rb
);
397 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT
, rb
);
398 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT
,
404 /* attach to depth attachment point */
405 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
,
406 GL_STENCIL_ATTACHMENT_EXT
,
407 GL_RENDERBUFFER_EXT
, rb
);
411 status
= glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT
);
412 if (status
!= GL_FRAMEBUFFER_COMPLETE_EXT
) {
413 glDeleteRenderbuffersEXT(1, depthRbOut
);
415 glDeleteRenderbuffersEXT(1, &rb
);
427 ParseArgs(int argc
, char *argv
[])
430 for (i
= 1; i
< argc
; i
++) {
431 if (strcmp(argv
[i
], "-ds") == 0) {
432 if (!glutExtensionSupported("GL_EXT_packed_depth_stencil")) {
433 printf("GL_EXT_packed_depth_stencil not found!\n");
436 UsePackedDepthStencil
= GL_TRUE
;
437 printf("Using GL_EXT_packed_depth_stencil\n");
439 else if (strcmp(argv
[i
], "-ds2") == 0) {
440 if (!glutExtensionSupported("GL_EXT_packed_depth_stencil")) {
441 printf("GL_EXT_packed_depth_stencil not found!\n");
444 if (!glutExtensionSupported("GL_ARB_framebuffer_object")) {
445 printf("GL_ARB_framebuffer_object not found!\n");
448 UsePackedDepthStencilBoth
= GL_TRUE
;
449 printf("Using GL_EXT_packed_depth_stencil and GL_DEPTH_STENCIL attachment point\n");
451 else if (strcmp(argv
[i
], "-arb") == 0) {
452 if (!glutExtensionSupported("GL_ARB_framebuffer_object")) {
453 printf("Sorry, GL_ARB_framebuffer object not supported!\n");
456 Use_ARB_fbo
= GL_TRUE
;
460 printf("Unknown option: %s\n", argv
[i
]);
467 * Make FBO to render into given texture.
470 MakeFBO_RenderTexture(GLuint TexObj
)
475 glGenFramebuffersEXT(1, &fb
);
476 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, fb
);
477 /* Render color to texture */
478 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
,
479 TexTarget
, TexObj
, TextureLevel
);
482 /* use a smaller depth buffer to see what happens */
486 /* Setup depth and stencil buffers */
489 b
= AttachDepthAndStencilBuffers(fb
,
490 TexWidth
- sizeFudge
,
491 TexHeight
- sizeFudge
,
492 UsePackedDepthStencil
,
493 UsePackedDepthStencilBoth
,
494 &DepthRB
, &StencilRB
);
496 /* try !UsePackedDepthStencil */
497 b
= AttachDepthAndStencilBuffers(fb
,
498 TexWidth
- sizeFudge
,
499 TexHeight
- sizeFudge
,
500 !UsePackedDepthStencil
,
501 UsePackedDepthStencilBoth
,
502 &DepthRB
, &StencilRB
);
505 printf("Unable to create/attach depth and stencil renderbuffers "
515 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT
, DepthRB
);
516 glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT
,
517 GL_RENDERBUFFER_WIDTH_EXT
, &w
);
518 glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT
,
519 GL_RENDERBUFFER_HEIGHT_EXT
, &h
);
520 printf("Color/Texture size: %d x %d\n", TexWidth
, TexHeight
);
521 printf("Depth buffer size: %d x %d\n", w
, h
);
523 glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT
,
524 GL_RENDERBUFFER_DEPTH_SIZE_EXT
, &bits
);
525 printf("Depth renderbuffer size = %d bits\n", bits
);
527 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT
, StencilRB
);
528 glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT
,
529 GL_RENDERBUFFER_STENCIL_SIZE_EXT
, &bits
);
530 printf("Stencil renderbuffer size = %d bits\n", bits
);
533 /* bind the regular framebuffer */
534 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0);
543 if (!glutExtensionSupported("GL_EXT_framebuffer_object")) {
544 printf("GL_EXT_framebuffer_object not found!\n");
548 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
552 static const GLfloat mat
[4] = { 1.0, 0.5, 0.5, 1.0 };
553 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT_AND_DIFFUSE
, mat
);
557 * Make texture object/image (we'll render into this texture)
560 glGenTextures(1, &TexObj
);
561 glBindTexture(TexTarget
, TexObj
);
563 /* make two image levels */
564 glTexImage2D(TexTarget
, 0, TexIntFormat
, TexWidth
, TexHeight
, 0,
565 GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
566 if (TexTarget
== GL_TEXTURE_2D
) {
567 glTexImage2D(TexTarget
, 1, TexIntFormat
, TexWidth
/2, TexHeight
/2, 0,
568 GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
569 TexWidth
= TexWidth
>> TextureLevel
;
570 TexHeight
= TexHeight
>> TextureLevel
;
571 glTexParameteri(TexTarget
, GL_TEXTURE_MAX_LEVEL
, TextureLevel
);
574 glTexParameteri(TexTarget
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
575 glTexParameteri(TexTarget
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
576 glTexParameteri(TexTarget
, GL_TEXTURE_BASE_LEVEL
, TextureLevel
);
577 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
580 MyFB
= MakeFBO_RenderTexture(TexObj
);
588 printf(" -ds Use combined depth/stencil renderbuffer\n");
589 printf(" -arb Try GL_ARB_framebuffer_object's mismatched buffer sizes\n");
590 printf(" -ds2 Try GL_ARB_framebuffer_object's GL_DEPTH_STENCIL_ATTACHMENT\n");
592 printf(" a Toggle animation\n");
593 printf(" s/s Step/rotate\n");
594 printf(" c Toggle back-face culling\n");
595 printf(" w Toggle wireframe mode (front-face only)\n");
596 printf(" Esc Exit\n");
601 main(int argc
, char *argv
[])
603 glutInit(&argc
, argv
);
604 glutInitWindowPosition(0, 0);
605 glutInitWindowSize(Width
, Height
);
606 glutInitDisplayMode(GLUT_RGB
| GLUT_DOUBLE
);
607 Win
= glutCreateWindow(argv
[0]);
609 glutReshapeFunc(Reshape
);
610 glutKeyboardFunc(Key
);
611 glutDisplayFunc(Display
);
615 ParseArgs(argc
, argv
);