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.
12 #define GL_GLEXT_PROTOTYPES
27 static int Width
= 400, Height
= 400;
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;*/
35 static GLuint DepthRB
= 0, StencilRB
= 0;
36 static GLboolean Anim
= GL_FALSE
;
37 static GLfloat Rot
= 0.0;
38 static GLboolean UsePackedDepthStencil
= GL_FALSE
;
39 static GLboolean UsePackedDepthStencilBoth
= GL_FALSE
;
40 static GLboolean Use_ARB_fbo
= GL_FALSE
;
41 static GLuint TextureLevel
= 0; /* which texture level to render to */
42 static GLenum TexIntFormat
= GL_RGB
; /* either GL_RGB or GL_RGBA */
43 static GLboolean Cull
= GL_FALSE
;
44 static GLboolean Wireframe
= GL_FALSE
;
50 GLenum err
= glGetError();
52 printf("GL Error 0x%x at line %d\n", (int) err
, line
);
60 Rot
= glutGet(GLUT_ELAPSED_TIME
) * 0.1;
70 glMatrixMode(GL_PROJECTION
);
72 glOrtho(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
73 glMatrixMode(GL_MODELVIEW
);
75 glTranslatef(0.0, 0.0, -15.0);
77 /* draw to texture image */
78 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, MyFB
);
80 status
= glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT
);
81 if (status
!= GL_FRAMEBUFFER_COMPLETE_EXT
) {
82 printf("Framebuffer incomplete!!!\n");
85 glViewport(0, 0, TexWidth
, TexHeight
);
87 glClearColor(0.5, 0.5, 1.0, 0.0);
88 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
| GL_STENCIL_BUFFER_BIT
);
92 glEnable(GL_DEPTH_TEST
);
96 glEnable(GL_STENCIL_TEST
);
97 glStencilFunc(GL_NEVER
, 1, ~0);
98 glStencilOp(GL_REPLACE
, GL_KEEP
, GL_REPLACE
);
101 CheckError(__LINE__
);
104 /* draw diamond-shaped stencil pattern */
107 glVertex2f(-0.2, 0.0);
108 glVertex2f( 0.0, -0.2);
109 glVertex2f( 0.2, 0.0);
110 glVertex2f( 0.0, 0.2);
114 /* draw teapot where stencil != 1 */
116 glStencilFunc(GL_NOTEQUAL
, 1, ~0);
117 glStencilOp(GL_KEEP
, GL_KEEP
, GL_KEEP
);
120 CheckError(__LINE__
);
123 glPolygonMode(GL_FRONT
, GL_LINE
);
126 glPolygonMode(GL_FRONT
, GL_FILL
);
132 glEnable(GL_CULL_FACE
);
135 glDisable(GL_CULL_FACE
);
148 glEnable(GL_LIGHTING
);
151 glRotatef(0.5 * Rot
, 1.0, 0.0, 0.0);
152 glFrontFace(GL_CW
); /* Teapot patches backward */
153 glutSolidTeapot(0.5);
156 glDisable(GL_LIGHTING
);
158 PrintStencilHistogram(TexWidth, TexHeight);
162 glDisable(GL_DEPTH_TEST
);
163 glDisable(GL_STENCIL_TEST
);
164 glDisable(GL_CULL_FACE
);
165 glPolygonMode(GL_FRONT_AND_BACK
, GL_FILL
);
168 /* Bind normal framebuffer */
169 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0);
172 CheckError(__LINE__
);
180 float ar
= (float) Width
/ (float) Height
;
184 /* draw textured quad in the window */
186 glMatrixMode(GL_PROJECTION
);
188 glFrustum(-ar
, ar
, -1.0, 1.0, 5.0, 25.0);
189 glMatrixMode(GL_MODELVIEW
);
191 glTranslatef(0.0, 0.0, -7.0);
193 glViewport(0, 0, Width
, Height
);
195 glClearColor(0.25, 0.25, 0.25, 0);
196 glClear(GL_COLOR_BUFFER_BIT
);
199 glRotatef(Rot
, 0, 1, 0);
201 glBindTexture(TexTarget
, TexObj
);
203 glColor3f(0.25, 0.25, 0.25);
204 if (TexTarget
== GL_TEXTURE_2D
) {
209 glColor3f(1.0, 1.0, 1.0);
216 assert(TexTarget
== GL_TEXTURE_RECTANGLE_ARB
);
219 glTexCoord2f(TexWidth
, 0);
221 glColor3f(1.0, 1.0, 1.0);
222 glTexCoord2f(TexWidth
, TexHeight
);
224 glTexCoord2f(0, TexHeight
);
229 glDisable(TexTarget
);
233 CheckError(__LINE__
);
238 Reshape(int width
, int height
)
240 glViewport(0, 0, width
, height
);
250 glDeleteRenderbuffersEXT(1, &DepthRB
);
253 glDeleteRenderbuffersEXT(1, &StencilRB
);
255 glDeleteFramebuffersEXT(1, &MyFB
);
257 glDeleteTextures(1, &TexObj
);
259 glutDestroyWindow(Win
);
266 Key(unsigned char key
, int x
, int y
)
282 Wireframe
= !Wireframe
;
299 * Attach depth and stencil renderbuffer(s) to the given framebuffer object.
300 * \param tryDepthStencil if true, try to use a combined depth+stencil buffer
301 * \param bindDepthStencil if true, and tryDepthStencil is true, bind with
302 * the GL_DEPTH_STENCIL_ATTACHMENT target.
303 * \return GL_TRUE for success, GL_FALSE for failure
306 AttachDepthAndStencilBuffers(GLuint fbo
,
307 GLsizei width
, GLsizei height
,
308 GLboolean tryDepthStencil
,
309 GLboolean bindDepthStencil
,
310 GLuint
*depthRbOut
, GLuint
*stencilRbOut
)
314 *depthRbOut
= *stencilRbOut
= 0;
316 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, fbo
);
318 if (tryDepthStencil
) {
321 glGenRenderbuffersEXT(1, &rb
);
322 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT
, rb
);
323 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT
,
324 GL_DEPTH24_STENCIL8_EXT
,
329 if (bindDepthStencil
) {
330 /* attach to both depth and stencil at once */
331 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
,
332 GL_DEPTH_STENCIL_ATTACHMENT
,
333 GL_RENDERBUFFER_EXT
, rb
);
338 /* attach to depth attachment point */
339 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
,
340 GL_DEPTH_ATTACHMENT_EXT
,
341 GL_RENDERBUFFER_EXT
, rb
);
345 /* and attach to stencil attachment point */
346 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
,
347 GL_STENCIL_ATTACHMENT_EXT
,
348 GL_RENDERBUFFER_EXT
, rb
);
353 status
= glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT
);
354 if (status
!= GL_FRAMEBUFFER_COMPLETE_EXT
)
357 *depthRbOut
= *stencilRbOut
= rb
;
361 /* just depth renderbuffer */
365 glGenRenderbuffersEXT(1, &rb
);
366 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT
, rb
);
367 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT
,
373 /* attach to depth attachment point */
374 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
,
375 GL_DEPTH_ATTACHMENT_EXT
,
376 GL_RENDERBUFFER_EXT
, rb
);
380 status
= glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT
);
381 if (status
!= GL_FRAMEBUFFER_COMPLETE_EXT
)
387 /* just stencil renderbuffer */
391 glGenRenderbuffersEXT(1, &rb
);
392 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT
, rb
);
393 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT
,
399 /* attach to depth attachment point */
400 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
,
401 GL_STENCIL_ATTACHMENT_EXT
,
402 GL_RENDERBUFFER_EXT
, rb
);
406 status
= glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT
);
407 if (status
!= GL_FRAMEBUFFER_COMPLETE_EXT
)
418 ParseArgs(int argc
, char *argv
[])
421 for (i
= 1; i
< argc
; i
++) {
422 if (strcmp(argv
[i
], "-ds") == 0) {
423 if (!glutExtensionSupported("GL_EXT_packed_depth_stencil")) {
424 printf("GL_EXT_packed_depth_stencil not found!\n");
427 UsePackedDepthStencil
= GL_TRUE
;
428 printf("Using GL_EXT_packed_depth_stencil\n");
430 else if (strcmp(argv
[i
], "-ds2") == 0) {
431 if (!glutExtensionSupported("GL_EXT_packed_depth_stencil")) {
432 printf("GL_EXT_packed_depth_stencil not found!\n");
435 if (!glutExtensionSupported("GL_ARB_framebuffer_object")) {
436 printf("GL_ARB_framebuffer_object not found!\n");
439 UsePackedDepthStencilBoth
= GL_TRUE
;
440 printf("Using GL_EXT_packed_depth_stencil and GL_DEPTH_STENCIL attachment point\n");
442 else if (strcmp(argv
[i
], "-arb") == 0) {
443 if (!glutExtensionSupported("GL_ARB_framebuffer_object")) {
444 printf("Sorry, GL_ARB_framebuffer object not supported!\n");
447 Use_ARB_fbo
= GL_TRUE
;
451 printf("Unknown option: %s\n", argv
[i
]);
458 * Make FBO to render into given texture.
461 MakeFBO_RenderTexture(GLuint TexObj
)
466 glGenFramebuffersEXT(1, &fb
);
467 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, fb
);
468 /* Render color to texture */
469 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
,
470 TexTarget
, TexObj
, TextureLevel
);
473 /* use a smaller depth buffer to see what happens */
477 /* Setup depth and stencil buffers */
480 b
= AttachDepthAndStencilBuffers(fb
,
481 TexWidth
- sizeFudge
,
482 TexHeight
- sizeFudge
,
483 UsePackedDepthStencil
,
484 UsePackedDepthStencilBoth
,
485 &DepthRB
, &StencilRB
);
487 /* try !UsePackedDepthStencil */
488 b
= AttachDepthAndStencilBuffers(fb
,
489 TexWidth
- sizeFudge
,
490 TexHeight
- sizeFudge
,
491 !UsePackedDepthStencil
,
492 UsePackedDepthStencilBoth
,
493 &DepthRB
, &StencilRB
);
496 printf("Unable to create/attach depth and stencil renderbuffers "
506 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT
, DepthRB
);
507 glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT
,
508 GL_RENDERBUFFER_WIDTH_EXT
, &w
);
509 glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT
,
510 GL_RENDERBUFFER_HEIGHT_EXT
, &h
);
511 printf("Color/Texture size: %d x %d\n", TexWidth
, TexHeight
);
512 printf("Depth buffer size: %d x %d\n", w
, h
);
514 glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT
,
515 GL_RENDERBUFFER_DEPTH_SIZE_EXT
, &bits
);
516 printf("Depth renderbuffer size = %d bits\n", bits
);
518 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT
, StencilRB
);
519 glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT
,
520 GL_RENDERBUFFER_STENCIL_SIZE_EXT
, &bits
);
521 printf("Stencil renderbuffer size = %d bits\n", bits
);
524 /* bind the regular framebuffer */
525 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0);
534 if (!glutExtensionSupported("GL_EXT_framebuffer_object")) {
535 printf("GL_EXT_framebuffer_object not found!\n");
539 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
543 static const GLfloat mat
[4] = { 1.0, 0.5, 0.5, 1.0 };
544 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT_AND_DIFFUSE
, mat
);
548 * Make texture object/image (we'll render into this texture)
551 glGenTextures(1, &TexObj
);
552 glBindTexture(TexTarget
, TexObj
);
554 /* make two image levels */
555 glTexImage2D(TexTarget
, 0, TexIntFormat
, TexWidth
, TexHeight
, 0,
556 GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
557 glTexImage2D(TexTarget
, 1, TexIntFormat
, TexWidth
/2, TexHeight
/2, 0,
558 GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
559 TexWidth
= TexWidth
>> TextureLevel
;
560 TexHeight
= TexHeight
>> TextureLevel
;
562 glTexParameteri(TexTarget
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
563 glTexParameteri(TexTarget
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
564 glTexParameteri(TexTarget
, GL_TEXTURE_BASE_LEVEL
, TextureLevel
);
565 glTexParameteri(TexTarget
, GL_TEXTURE_MAX_LEVEL
, TextureLevel
);
566 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
569 MyFB
= MakeFBO_RenderTexture(TexObj
);
577 printf(" -ds Use combined depth/stencil renderbuffer\n");
578 printf(" -arb Try GL_ARB_framebuffer_object's mismatched buffer sizes\n");
579 printf(" -ds2 Tye GL_ARB_framebuffer_object's GL_DEPTH_STENCIL_ATTACHMENT\n");
581 printf(" a Toggle animation\n");
582 printf(" s/s Step/rotate\n");
583 printf(" c Toggle back-face culling\n");
584 printf(" w Toggle wireframe mode (front-face only)\n");
585 printf(" Esc Exit\n");
590 main(int argc
, char *argv
[])
592 glutInit(&argc
, argv
);
593 glutInitWindowPosition(0, 0);
594 glutInitWindowSize(Width
, Height
);
595 glutInitDisplayMode(GLUT_RGB
| GLUT_DOUBLE
);
596 Win
= glutCreateWindow(argv
[0]);
597 glutReshapeFunc(Reshape
);
598 glutKeyboardFunc(Key
);
599 glutDisplayFunc(Display
);
603 ParseArgs(argc
, argv
);