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.
17 #include "glut_wrap.h"
25 static PFNGLISRENDERBUFFERPROC glIsRenderbuffer_func
= NULL
;
26 static PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer_func
= NULL
;
27 static PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers_func
= NULL
;
28 static PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers_func
= NULL
;
29 static PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage_func
= NULL
;
30 static PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv_func
= NULL
;
31 static PFNGLISFRAMEBUFFERPROC glIsFramebuffer_func
= NULL
;
32 static PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer_func
= NULL
;
33 static PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers_func
= NULL
;
34 static PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers_func
= NULL
;
35 static PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus_func
= NULL
;
36 static PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D_func
= NULL
;
37 static PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D_func
= NULL
;
38 static PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D_func
= NULL
;
39 static PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer_func
= NULL
;
40 static PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv_func
= NULL
;
41 static PFNGLGENERATEMIPMAPPROC glGenerateMipmap_func
= NULL
;
45 static int Width
= 400, Height
= 400;
48 static GLenum TexTarget
= GL_TEXTURE_2D
;
49 static int TexWidth
= 512, TexHeight
= 512;
50 static GLenum TexIntFormat
= GL_RGB
; /* either GL_RGB or GL_RGBA */
52 static GLenum TexTarget
= GL_TEXTURE_RECTANGLE_ARB
;
53 static int TexWidth
= 200, TexHeight
= 200;
54 static GLenum TexIntFormat
= GL_RGB5
; /* either GL_RGB or GL_RGBA */
56 static GLuint TextureLevel
= 0; /* which texture level to render to */
60 static GLuint DepthRB
= 0, StencilRB
= 0;
61 static GLboolean Anim
= GL_FALSE
;
62 static GLfloat Rot
= 0.0;
63 static GLboolean UsePackedDepthStencil
= GL_FALSE
;
64 static GLboolean UsePackedDepthStencilBoth
= GL_FALSE
;
65 static GLboolean Use_ARB_fbo
= GL_FALSE
;
66 static GLboolean Cull
= GL_FALSE
;
67 static GLboolean Wireframe
= GL_FALSE
;
73 GLenum err
= glGetError();
75 printf("GL Error 0x%x at line %d\n", (int) err
, line
);
83 Rot
= glutGet(GLUT_ELAPSED_TIME
) * 0.1;
93 glMatrixMode(GL_PROJECTION
);
95 glOrtho(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
96 glMatrixMode(GL_MODELVIEW
);
98 glTranslatef(0.0, 0.0, -15.0);
100 /* draw to texture image */
101 glBindFramebuffer_func(GL_FRAMEBUFFER_EXT
, MyFB
);
103 status
= glCheckFramebufferStatus_func(GL_FRAMEBUFFER_EXT
);
104 if (status
!= GL_FRAMEBUFFER_COMPLETE_EXT
) {
105 printf("Framebuffer incomplete!!!\n");
108 glViewport(0, 0, TexWidth
, TexHeight
);
110 glClearColor(0.5, 0.5, 1.0, 0.0);
111 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
| GL_STENCIL_BUFFER_BIT
);
112 CheckError(__LINE__
);
115 glEnable(GL_DEPTH_TEST
);
119 glEnable(GL_STENCIL_TEST
);
120 glStencilFunc(GL_NEVER
, 1, ~0);
121 glStencilOp(GL_REPLACE
, GL_KEEP
, GL_REPLACE
);
124 CheckError(__LINE__
);
127 /* draw diamond-shaped stencil pattern */
130 glVertex2f(-0.2, 0.0);
131 glVertex2f( 0.0, -0.2);
132 glVertex2f( 0.2, 0.0);
133 glVertex2f( 0.0, 0.2);
137 /* draw teapot where stencil != 1 */
139 glStencilFunc(GL_NOTEQUAL
, 1, ~0);
140 glStencilOp(GL_KEEP
, GL_KEEP
, GL_KEEP
);
143 CheckError(__LINE__
);
146 glPolygonMode(GL_FRONT
, GL_LINE
);
149 glPolygonMode(GL_FRONT
, GL_FILL
);
155 glEnable(GL_CULL_FACE
);
158 glDisable(GL_CULL_FACE
);
171 glEnable(GL_LIGHTING
);
174 glRotatef(0.5 * Rot
, 1.0, 0.0, 0.0);
175 glFrontFace(GL_CW
); /* Teapot patches backward */
176 glutSolidTeapot(0.5);
179 glDisable(GL_LIGHTING
);
181 PrintStencilHistogram(TexWidth, TexHeight);
185 glDisable(GL_DEPTH_TEST
);
186 glDisable(GL_STENCIL_TEST
);
187 glDisable(GL_CULL_FACE
);
188 glPolygonMode(GL_FRONT_AND_BACK
, GL_FILL
);
191 /* Bind normal framebuffer */
192 glBindFramebuffer_func(GL_FRAMEBUFFER_EXT
, 0);
195 CheckError(__LINE__
);
203 float ar
= (float) Width
/ (float) Height
;
207 /* draw textured quad in the window */
209 glMatrixMode(GL_PROJECTION
);
211 glFrustum(-ar
, ar
, -1.0, 1.0, 5.0, 25.0);
212 glMatrixMode(GL_MODELVIEW
);
214 glTranslatef(0.0, 0.0, -7.0);
216 glViewport(0, 0, Width
, Height
);
218 glClearColor(0.25, 0.25, 0.25, 0);
219 glClear(GL_COLOR_BUFFER_BIT
);
222 glRotatef(Rot
, 0, 1, 0);
224 glBindTexture(TexTarget
, TexObj
);
226 glColor3f(0.25, 0.25, 0.25);
227 if (TexTarget
== GL_TEXTURE_2D
) {
232 glColor3f(1.0, 1.0, 1.0);
239 assert(TexTarget
== GL_TEXTURE_RECTANGLE_ARB
);
242 glTexCoord2f(TexWidth
, 0);
244 glColor3f(1.0, 1.0, 1.0);
245 glTexCoord2f(TexWidth
, TexHeight
);
247 glTexCoord2f(0, TexHeight
);
252 glDisable(TexTarget
);
256 CheckError(__LINE__
);
261 Reshape(int width
, int height
)
263 glViewport(0, 0, width
, height
);
273 glDeleteRenderbuffers_func(1, &DepthRB
);
276 glDeleteRenderbuffers_func(1, &StencilRB
);
278 glDeleteFramebuffers_func(1, &MyFB
);
280 glDeleteTextures(1, &TexObj
);
282 glutDestroyWindow(Win
);
289 Key(unsigned char key
, int x
, int y
)
305 Wireframe
= !Wireframe
;
322 * Attach depth and stencil renderbuffer(s) to the given framebuffer object.
323 * \param tryDepthStencil if true, try to use a combined depth+stencil buffer
324 * \param bindDepthStencil if true, and tryDepthStencil is true, bind with
325 * the GL_DEPTH_STENCIL_ATTACHMENT target.
326 * \return GL_TRUE for success, GL_FALSE for failure
329 AttachDepthAndStencilBuffers(GLuint fbo
,
330 GLsizei width
, GLsizei height
,
331 GLboolean tryDepthStencil
,
332 GLboolean bindDepthStencil
,
333 GLuint
*depthRbOut
, GLuint
*stencilRbOut
)
337 *depthRbOut
= *stencilRbOut
= 0;
339 glBindFramebuffer_func(GL_FRAMEBUFFER_EXT
, fbo
);
341 if (tryDepthStencil
) {
344 glGenRenderbuffers_func(1, &rb
);
345 glBindRenderbuffer_func(GL_RENDERBUFFER_EXT
, rb
);
346 glRenderbufferStorage_func(GL_RENDERBUFFER_EXT
,
347 GL_DEPTH24_STENCIL8_EXT
,
352 if (bindDepthStencil
) {
353 /* attach to both depth and stencil at once */
354 glFramebufferRenderbuffer_func(GL_FRAMEBUFFER_EXT
,
355 GL_DEPTH_STENCIL_ATTACHMENT
,
356 GL_RENDERBUFFER_EXT
, rb
);
361 /* attach to depth attachment point */
362 glFramebufferRenderbuffer_func(GL_FRAMEBUFFER_EXT
,
363 GL_DEPTH_ATTACHMENT_EXT
,
364 GL_RENDERBUFFER_EXT
, rb
);
368 /* and attach to stencil attachment point */
369 glFramebufferRenderbuffer_func(GL_FRAMEBUFFER_EXT
,
370 GL_STENCIL_ATTACHMENT_EXT
,
371 GL_RENDERBUFFER_EXT
, rb
);
376 status
= glCheckFramebufferStatus_func(GL_FRAMEBUFFER_EXT
);
377 if (status
!= GL_FRAMEBUFFER_COMPLETE_EXT
)
380 *depthRbOut
= *stencilRbOut
= rb
;
384 /* just depth renderbuffer */
388 glGenRenderbuffers_func(1, &rb
);
389 glBindRenderbuffer_func(GL_RENDERBUFFER_EXT
, rb
);
390 glRenderbufferStorage_func(GL_RENDERBUFFER_EXT
,
396 /* attach to depth attachment point */
397 glFramebufferRenderbuffer_func(GL_FRAMEBUFFER_EXT
,
398 GL_DEPTH_ATTACHMENT_EXT
,
399 GL_RENDERBUFFER_EXT
, rb
);
403 status
= glCheckFramebufferStatus_func(GL_FRAMEBUFFER_EXT
);
404 if (status
!= GL_FRAMEBUFFER_COMPLETE_EXT
)
410 /* just stencil renderbuffer */
414 glGenRenderbuffers_func(1, &rb
);
415 glBindRenderbuffer_func(GL_RENDERBUFFER_EXT
, rb
);
416 glRenderbufferStorage_func(GL_RENDERBUFFER_EXT
,
422 /* attach to depth attachment point */
423 glFramebufferRenderbuffer_func(GL_FRAMEBUFFER_EXT
,
424 GL_STENCIL_ATTACHMENT_EXT
,
425 GL_RENDERBUFFER_EXT
, rb
);
429 status
= glCheckFramebufferStatus_func(GL_FRAMEBUFFER_EXT
);
430 if (status
!= GL_FRAMEBUFFER_COMPLETE_EXT
) {
431 glDeleteRenderbuffers_func(1, depthRbOut
);
433 glDeleteRenderbuffers_func(1, &rb
);
445 ParseArgs(int argc
, char *argv
[])
448 for (i
= 1; i
< argc
; i
++) {
449 if (strcmp(argv
[i
], "-ds") == 0) {
450 if (!glutExtensionSupported("GL_EXT_packed_depth_stencil")) {
451 printf("GL_EXT_packed_depth_stencil not found!\n");
454 UsePackedDepthStencil
= GL_TRUE
;
455 printf("Using GL_EXT_packed_depth_stencil\n");
457 else if (strcmp(argv
[i
], "-ds2") == 0) {
458 if (!glutExtensionSupported("GL_EXT_packed_depth_stencil")) {
459 printf("GL_EXT_packed_depth_stencil not found!\n");
462 if (!glutExtensionSupported("GL_ARB_framebuffer_object")) {
463 printf("GL_ARB_framebuffer_object not found!\n");
466 UsePackedDepthStencil
= GL_TRUE
;
467 UsePackedDepthStencilBoth
= GL_TRUE
;
468 printf("Using GL_EXT_packed_depth_stencil and GL_DEPTH_STENCIL attachment point\n");
470 else if (strcmp(argv
[i
], "-arb") == 0) {
471 if (!glutExtensionSupported("GL_ARB_framebuffer_object")) {
472 printf("Sorry, GL_ARB_framebuffer object not supported!\n");
475 Use_ARB_fbo
= GL_TRUE
;
479 printf("Unknown option: %s\n", argv
[i
]);
486 SetupFunctionPointers(void)
489 /* use the ARB functions */
490 glIsRenderbuffer_func
= glIsRenderbuffer
;
491 glBindRenderbuffer_func
= glBindRenderbuffer
;
492 glDeleteRenderbuffers_func
= glDeleteRenderbuffers
;
493 glGenRenderbuffers_func
= glGenRenderbuffers
;
494 glRenderbufferStorage_func
= glRenderbufferStorage
;
495 glGetRenderbufferParameteriv_func
= glGetRenderbufferParameteriv
;
496 glIsFramebuffer_func
= glIsFramebuffer
;
497 glBindFramebuffer_func
= glBindFramebuffer
;
498 glDeleteFramebuffers_func
= glDeleteFramebuffers
;
499 glGenFramebuffers_func
= glGenFramebuffers
;
500 glCheckFramebufferStatus_func
= glCheckFramebufferStatus
;
501 glFramebufferTexture1D_func
= glFramebufferTexture1D
;
502 glFramebufferTexture2D_func
= glFramebufferTexture2D
;
503 glFramebufferTexture3D_func
= glFramebufferTexture3D
;
504 glFramebufferRenderbuffer_func
= glFramebufferRenderbuffer
;
505 glGetFramebufferAttachmentParameteriv_func
= glGetFramebufferAttachmentParameteriv
;
506 glGenerateMipmap_func
= glGenerateMipmap
;
509 /* use the EXT functions */
510 glIsRenderbuffer_func
= glIsRenderbufferEXT
;
511 glBindRenderbuffer_func
= glBindRenderbufferEXT
;
512 glDeleteRenderbuffers_func
= glDeleteRenderbuffersEXT
;
513 glGenRenderbuffers_func
= glGenRenderbuffersEXT
;
514 glRenderbufferStorage_func
= glRenderbufferStorageEXT
;
515 glGetRenderbufferParameteriv_func
= glGetRenderbufferParameterivEXT
;
516 glIsFramebuffer_func
= glIsFramebufferEXT
;
517 glBindFramebuffer_func
= glBindFramebufferEXT
;
518 glDeleteFramebuffers_func
= glDeleteFramebuffersEXT
;
519 glGenFramebuffers_func
= glGenFramebuffersEXT
;
520 glCheckFramebufferStatus_func
= glCheckFramebufferStatusEXT
;
521 glFramebufferTexture1D_func
= glFramebufferTexture1DEXT
;
522 glFramebufferTexture2D_func
= glFramebufferTexture2DEXT
;
523 glFramebufferTexture3D_func
= glFramebufferTexture3DEXT
;
524 glFramebufferRenderbuffer_func
= glFramebufferRenderbufferEXT
;
525 glGetFramebufferAttachmentParameteriv_func
= glGetFramebufferAttachmentParameterivEXT
;
526 glGenerateMipmap_func
= glGenerateMipmapEXT
;
532 * Make FBO to render into given texture.
535 MakeFBO_RenderTexture(GLuint texObj
)
540 glGenFramebuffers_func(1, &fb
);
541 glBindFramebuffer_func(GL_FRAMEBUFFER_EXT
, fb
);
542 /* Render color to texture */
543 glFramebufferTexture2D_func(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
,
544 TexTarget
, texObj
, TextureLevel
);
547 /* use a smaller depth buffer to see what happens */
551 /* Setup depth and stencil buffers */
554 b
= AttachDepthAndStencilBuffers(fb
,
555 TexWidth
- sizeFudge
,
556 TexHeight
- sizeFudge
,
557 UsePackedDepthStencil
,
558 UsePackedDepthStencilBoth
,
559 &DepthRB
, &StencilRB
);
561 /* try !UsePackedDepthStencil */
562 b
= AttachDepthAndStencilBuffers(fb
,
563 TexWidth
- sizeFudge
,
564 TexHeight
- sizeFudge
,
565 !UsePackedDepthStencil
,
566 UsePackedDepthStencilBoth
,
567 &DepthRB
, &StencilRB
);
570 printf("Unable to create/attach depth and stencil renderbuffers "
578 GLint bits
, w
, h
, name
;
580 glBindRenderbuffer_func(GL_RENDERBUFFER_EXT
, DepthRB
);
581 glGetRenderbufferParameteriv_func(GL_RENDERBUFFER_EXT
,
582 GL_RENDERBUFFER_WIDTH_EXT
, &w
);
583 glGetRenderbufferParameteriv_func(GL_RENDERBUFFER_EXT
,
584 GL_RENDERBUFFER_HEIGHT_EXT
, &h
);
585 printf("Color/Texture size: %d x %d\n", TexWidth
, TexHeight
);
586 printf("Depth buffer size: %d x %d\n", w
, h
);
588 glGetRenderbufferParameteriv_func(GL_RENDERBUFFER_EXT
,
589 GL_RENDERBUFFER_DEPTH_SIZE_EXT
, &bits
);
590 printf("Depth renderbuffer size = %d bits\n", bits
);
592 glBindRenderbuffer_func(GL_RENDERBUFFER_EXT
, StencilRB
);
593 glGetRenderbufferParameteriv_func(GL_RENDERBUFFER_EXT
,
594 GL_RENDERBUFFER_STENCIL_SIZE_EXT
, &bits
);
595 printf("Stencil renderbuffer size = %d bits\n", bits
);
597 glGetFramebufferAttachmentParameteriv_func(GL_FRAMEBUFFER_EXT
,
598 GL_COLOR_ATTACHMENT0
,
599 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT
,
601 printf("Render to texture name: %d\n", texObj
);
602 printf("Color attachment[0] name: %d\n", name
);
603 assert(texObj
== name
);
605 glGetFramebufferAttachmentParameteriv_func(GL_FRAMEBUFFER_EXT
,
606 GL_STENCIL_ATTACHMENT
,
607 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT
,
609 printf("Stencil attachment name: %d\n", name
);
611 glGetFramebufferAttachmentParameteriv_func(GL_FRAMEBUFFER_EXT
,
613 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT
,
615 printf("Depth attachment name: %d\n", name
);
618 /* bind the regular framebuffer */
619 glBindFramebuffer_func(GL_FRAMEBUFFER_EXT
, 0);
628 if (!glutExtensionSupported("GL_EXT_framebuffer_object")) {
629 printf("GL_EXT_framebuffer_object not found!\n");
633 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
635 SetupFunctionPointers();
639 static const GLfloat mat
[4] = { 1.0, 0.5, 0.5, 1.0 };
640 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT_AND_DIFFUSE
, mat
);
644 * Make texture object/image (we'll render into this texture)
647 glGenTextures(1, &TexObj
);
648 glBindTexture(TexTarget
, TexObj
);
650 /* make two image levels */
651 glTexImage2D(TexTarget
, 0, TexIntFormat
, TexWidth
, TexHeight
, 0,
652 GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
653 if (TexTarget
== GL_TEXTURE_2D
) {
654 glTexImage2D(TexTarget
, 1, TexIntFormat
, TexWidth
/2, TexHeight
/2, 0,
655 GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
656 TexWidth
= TexWidth
>> TextureLevel
;
657 TexHeight
= TexHeight
>> TextureLevel
;
658 glTexParameteri(TexTarget
, GL_TEXTURE_MAX_LEVEL
, TextureLevel
);
661 glTexParameteri(TexTarget
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
662 glTexParameteri(TexTarget
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
663 glTexParameteri(TexTarget
, GL_TEXTURE_BASE_LEVEL
, TextureLevel
);
664 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
667 MyFB
= MakeFBO_RenderTexture(TexObj
);
675 printf(" -ds Use combined depth/stencil renderbuffer\n");
676 printf(" -arb Try GL_ARB_framebuffer_object's mismatched buffer sizes\n");
677 printf(" -ds2 Try GL_ARB_framebuffer_object's GL_DEPTH_STENCIL_ATTACHMENT\n");
679 printf(" a Toggle animation\n");
680 printf(" s/s Step/rotate\n");
681 printf(" c Toggle back-face culling\n");
682 printf(" w Toggle wireframe mode (front-face only)\n");
683 printf(" Esc Exit\n");
688 main(int argc
, char *argv
[])
690 glutInit(&argc
, argv
);
691 glutInitWindowPosition(0, 0);
692 glutInitWindowSize(Width
, Height
);
693 glutInitDisplayMode(GLUT_RGB
| GLUT_DOUBLE
);
694 Win
= glutCreateWindow(argv
[0]);
695 glutReshapeFunc(Reshape
);
696 glutKeyboardFunc(Key
);
697 glutDisplayFunc(Display
);
701 ParseArgs(argc
, argv
);