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 glBindFramebuffer_func(GL_FRAMEBUFFER_EXT
, MyFB
);
85 status
= glCheckFramebufferStatus_func(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 glBindFramebuffer_func(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 glDeleteRenderbuffers_func(1, &DepthRB
);
258 glDeleteRenderbuffers_func(1, &StencilRB
);
260 glDeleteFramebuffers_func(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 glBindFramebuffer_func(GL_FRAMEBUFFER_EXT
, fbo
);
323 if (tryDepthStencil
) {
326 glGenRenderbuffers_func(1, &rb
);
327 glBindRenderbuffer_func(GL_RENDERBUFFER_EXT
, rb
);
328 glRenderbufferStorage_func(GL_RENDERBUFFER_EXT
,
329 GL_DEPTH24_STENCIL8_EXT
,
334 if (bindDepthStencil
) {
335 /* attach to both depth and stencil at once */
336 glFramebufferRenderbuffer_func(GL_FRAMEBUFFER_EXT
,
337 GL_DEPTH_STENCIL_ATTACHMENT
,
338 GL_RENDERBUFFER_EXT
, rb
);
343 /* attach to depth attachment point */
344 glFramebufferRenderbuffer_func(GL_FRAMEBUFFER_EXT
,
345 GL_DEPTH_ATTACHMENT_EXT
,
346 GL_RENDERBUFFER_EXT
, rb
);
350 /* and attach to stencil attachment point */
351 glFramebufferRenderbuffer_func(GL_FRAMEBUFFER_EXT
,
352 GL_STENCIL_ATTACHMENT_EXT
,
353 GL_RENDERBUFFER_EXT
, rb
);
358 status
= glCheckFramebufferStatus_func(GL_FRAMEBUFFER_EXT
);
359 if (status
!= GL_FRAMEBUFFER_COMPLETE_EXT
)
362 *depthRbOut
= *stencilRbOut
= rb
;
366 /* just depth renderbuffer */
370 glGenRenderbuffers_func(1, &rb
);
371 glBindRenderbuffer_func(GL_RENDERBUFFER_EXT
, rb
);
372 glRenderbufferStorage_func(GL_RENDERBUFFER_EXT
,
378 /* attach to depth attachment point */
379 glFramebufferRenderbuffer_func(GL_FRAMEBUFFER_EXT
,
380 GL_DEPTH_ATTACHMENT_EXT
,
381 GL_RENDERBUFFER_EXT
, rb
);
385 status
= glCheckFramebufferStatus_func(GL_FRAMEBUFFER_EXT
);
386 if (status
!= GL_FRAMEBUFFER_COMPLETE_EXT
)
392 /* just stencil renderbuffer */
396 glGenRenderbuffers_func(1, &rb
);
397 glBindRenderbuffer_func(GL_RENDERBUFFER_EXT
, rb
);
398 glRenderbufferStorage_func(GL_RENDERBUFFER_EXT
,
404 /* attach to depth attachment point */
405 glFramebufferRenderbuffer_func(GL_FRAMEBUFFER_EXT
,
406 GL_STENCIL_ATTACHMENT_EXT
,
407 GL_RENDERBUFFER_EXT
, rb
);
411 status
= glCheckFramebufferStatus_func(GL_FRAMEBUFFER_EXT
);
412 if (status
!= GL_FRAMEBUFFER_COMPLETE_EXT
) {
413 glDeleteRenderbuffers_func(1, depthRbOut
);
415 glDeleteRenderbuffers_func(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 SetupFunctionPointers(void)
472 /* no-op: use the ARB functions as-is */
475 /* set the ARB-flavor function pointers to point to the EXT functions */
476 glIsRenderbuffer_func
= glIsRenderbufferEXT_func
;
477 glBindRenderbuffer_func
= glBindRenderbufferEXT_func
;
478 glDeleteRenderbuffers_func
= glDeleteRenderbuffersEXT_func
;
479 glGenRenderbuffers_func
= glGenRenderbuffersEXT_func
;
480 glRenderbufferStorage_func
= glRenderbufferStorageEXT_func
;
481 glGetRenderbufferParameteriv_func
= glGetRenderbufferParameterivEXT_func
;
482 glIsFramebuffer_func
= glIsFramebufferEXT_func
;
483 glBindFramebuffer_func
= glBindFramebufferEXT_func
;
484 glDeleteFramebuffers_func
= glDeleteFramebuffersEXT_func
;
485 glGenFramebuffers_func
= glGenFramebuffersEXT_func
;
486 glCheckFramebufferStatus_func
= glCheckFramebufferStatusEXT_func
;
487 glFramebufferTexture1D_func
= glFramebufferTexture1DEXT_func
;
488 glFramebufferTexture2D_func
= glFramebufferTexture2DEXT_func
;
489 glFramebufferTexture3D_func
= glFramebufferTexture3DEXT_func
;
490 glFramebufferRenderbuffer_func
= glFramebufferRenderbufferEXT_func
;
491 glGetFramebufferAttachmentParameteriv_func
= glGetFramebufferAttachmentParameterivEXT_func
;
492 glGenerateMipmap_func
= glGenerateMipmapEXT_func
;
498 * Make FBO to render into given texture.
501 MakeFBO_RenderTexture(GLuint texObj
)
506 glGenFramebuffers_func(1, &fb
);
507 glBindFramebuffer_func(GL_FRAMEBUFFER_EXT
, fb
);
508 /* Render color to texture */
509 glFramebufferTexture2D_func(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
,
510 TexTarget
, texObj
, TextureLevel
);
513 /* use a smaller depth buffer to see what happens */
517 /* Setup depth and stencil buffers */
520 b
= AttachDepthAndStencilBuffers(fb
,
521 TexWidth
- sizeFudge
,
522 TexHeight
- sizeFudge
,
523 UsePackedDepthStencil
,
524 UsePackedDepthStencilBoth
,
525 &DepthRB
, &StencilRB
);
527 /* try !UsePackedDepthStencil */
528 b
= AttachDepthAndStencilBuffers(fb
,
529 TexWidth
- sizeFudge
,
530 TexHeight
- sizeFudge
,
531 !UsePackedDepthStencil
,
532 UsePackedDepthStencilBoth
,
533 &DepthRB
, &StencilRB
);
536 printf("Unable to create/attach depth and stencil renderbuffers "
544 GLint bits
, w
, h
, name
;
546 glBindRenderbuffer_func(GL_RENDERBUFFER_EXT
, DepthRB
);
547 glGetRenderbufferParameteriv_func(GL_RENDERBUFFER_EXT
,
548 GL_RENDERBUFFER_WIDTH_EXT
, &w
);
549 glGetRenderbufferParameteriv_func(GL_RENDERBUFFER_EXT
,
550 GL_RENDERBUFFER_HEIGHT_EXT
, &h
);
551 printf("Color/Texture size: %d x %d\n", TexWidth
, TexHeight
);
552 printf("Depth buffer size: %d x %d\n", w
, h
);
554 glGetRenderbufferParameteriv_func(GL_RENDERBUFFER_EXT
,
555 GL_RENDERBUFFER_DEPTH_SIZE_EXT
, &bits
);
556 printf("Depth renderbuffer size = %d bits\n", bits
);
558 glBindRenderbuffer_func(GL_RENDERBUFFER_EXT
, StencilRB
);
559 glGetRenderbufferParameteriv_func(GL_RENDERBUFFER_EXT
,
560 GL_RENDERBUFFER_STENCIL_SIZE_EXT
, &bits
);
561 printf("Stencil renderbuffer size = %d bits\n", bits
);
563 glGetFramebufferAttachmentParameteriv_func(GL_FRAMEBUFFER_EXT
,
564 GL_COLOR_ATTACHMENT0
,
565 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT
,
567 printf("Render to texture name: %d\n", texObj
);
568 printf("Color attachment[0] name: %d\n", name
);
569 assert(texObj
== name
);
571 glGetFramebufferAttachmentParameteriv_func(GL_FRAMEBUFFER_EXT
,
572 GL_STENCIL_ATTACHMENT
,
573 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT
,
575 printf("Stencil attachment name: %d\n", name
);
577 glGetFramebufferAttachmentParameteriv_func(GL_FRAMEBUFFER_EXT
,
579 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT
,
581 printf("Depth attachment name: %d\n", name
);
584 /* bind the regular framebuffer */
585 glBindFramebuffer_func(GL_FRAMEBUFFER_EXT
, 0);
594 if (!glutExtensionSupported("GL_EXT_framebuffer_object")) {
595 printf("GL_EXT_framebuffer_object not found!\n");
599 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
601 SetupFunctionPointers();
605 static const GLfloat mat
[4] = { 1.0, 0.5, 0.5, 1.0 };
606 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT_AND_DIFFUSE
, mat
);
610 * Make texture object/image (we'll render into this texture)
613 glGenTextures(1, &TexObj
);
614 glBindTexture(TexTarget
, TexObj
);
616 /* make two image levels */
617 glTexImage2D(TexTarget
, 0, TexIntFormat
, TexWidth
, TexHeight
, 0,
618 GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
619 if (TexTarget
== GL_TEXTURE_2D
) {
620 glTexImage2D(TexTarget
, 1, TexIntFormat
, TexWidth
/2, TexHeight
/2, 0,
621 GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
622 TexWidth
= TexWidth
>> TextureLevel
;
623 TexHeight
= TexHeight
>> TextureLevel
;
624 glTexParameteri(TexTarget
, GL_TEXTURE_MAX_LEVEL
, TextureLevel
);
627 glTexParameteri(TexTarget
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
628 glTexParameteri(TexTarget
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
629 glTexParameteri(TexTarget
, GL_TEXTURE_BASE_LEVEL
, TextureLevel
);
630 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
633 MyFB
= MakeFBO_RenderTexture(TexObj
);
641 printf(" -ds Use combined depth/stencil renderbuffer\n");
642 printf(" -arb Try GL_ARB_framebuffer_object's mismatched buffer sizes\n");
643 printf(" -ds2 Try GL_ARB_framebuffer_object's GL_DEPTH_STENCIL_ATTACHMENT\n");
645 printf(" a Toggle animation\n");
646 printf(" s/s Step/rotate\n");
647 printf(" c Toggle back-face culling\n");
648 printf(" w Toggle wireframe mode (front-face only)\n");
649 printf(" Esc Exit\n");
654 main(int argc
, char *argv
[])
656 glutInit(&argc
, argv
);
657 glutInitWindowPosition(0, 0);
658 glutInitWindowSize(Width
, Height
);
659 glutInitDisplayMode(GLUT_RGB
| GLUT_DOUBLE
);
660 Win
= glutCreateWindow(argv
[0]);
661 glutReshapeFunc(Reshape
);
662 glutKeyboardFunc(Key
);
663 glutDisplayFunc(Display
);
667 ParseArgs(argc
, argv
);