Open GL Super Bible

Previous Table of Contents Next


Listing 15-2 Using glDrawBuffer to cut away selected pieces of an object

/*
 * "depthcut.c" - A test program demonstrating the use of glDepthFunc()
 *                and glDrawBuffer() to cut away parts of a scene.
 *
 * Press the 'd' key to toggle between GL_LESS and GL_GREATER depth
 * tests.  Press the 'ESC' key to quit.
 */

#include <GL/glaux.h>

/*
 * These #define constants are provided for compatibility between MS
 * Windows and the rest of the world.
 *
 * CALLBACK and APIENTRY are function modifiers under MS Windows.
 */

#ifndef WIN32
#  define CALLBACK
#  define APIENTRY
#endif /* !WIN32 */

GLenum      depth_function = GL_LESS;    /* Current depth function */
GLfloat     cutting_plane = -15.0,       /* Cutting plane distance */
            cutting_dir   = -1.0;        /* Cutting plane direction */

/*
 * 'reshape_scene()' - Change the size of the scene...
 */

void CALLBACK
reshape_scene(GLsizei width,   /* I - Width of the window in pixels */
              GLsizei height)  /* I - Height of the window in pixels */
{

 /*
  * Reset the current viewport and perspective transformation...
  */

  glViewport(0, 0, width, height);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(22.5, (float)width / (float)height, 0.1, 1000.0);

  glMatrixMode(GL_MODELVIEW);
}

/*
 * 'draw_scene()' - Draw a scene containing a cube with a sphere in
 *                 front of it.
 */

void CALLBACK
draw_scene(void)
{
  static float   red_light[4] = { 1.0, 0.0, 0.0, 1.0 };
  static float   red_pos[4] = { 1.0, 1.0, 1.0, 0.0 };
  static float   blue_light[4] = { 0.0, 0.0, 1.0, 1.0 };
  static float   blue_pos[4] = { -1.0, -1.0, -1.0, 0.0 };

 /*
  * Enable drawing features that we need...
  */

  glEnable(GL_DEPTH_TEST);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  glEnable(GL_LIGHT1);

  glShadeModel(GL_SMOOTH);
  glDepthFunc(depth_function); 

 /*
  * Clear the color and depth buffers...
  */

  if (depth_function == GL_LESS)
    glClearDepth(1.0);
  else
    glClearDepth(0.0);

  glClearColor(0.0, 0.0, 0.0, 0.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 /*
  * Draw the cutting plane.  Note that we disable drawing into the normal
  * color buffer while we do this...
  */

  glDrawBuffer(GL_NONE);
  glBegin(GL_POLYGON);
    glVertex3f(-100.0, 100.0, cutting_plane);
    glVertex3f(100.0, 100.0, cutting_plane);
    glVertex3f(100.0, -100.0, cutting_plane);
    glVertex3f(-100.0, -100.0, cutting_plane);
  glEnd();

  glDrawBuffer(GL_BACK);

 /*
  * Draw the cube and sphere in different colors...
  *
  * We have positioned two lights in this scene.  The first is red and
  * located above, to the right, and behind the viewer.  The second

  * is blue and located below, to the left, and in front of the viewer.
  */

  glLightfv(GL_LIGHT0, GL_DIFFUSE, red_light);
  glLightfv(GL_LIGHT0, GL_POSITION, red_pos);

  glLightfv(GL_LIGHT1, GL_DIFFUSE, blue_light);
  glLightfv(GL_LIGHT1, GL_POSITION, blue_pos);

  glPushMatrix();
    glTranslatef(-1.0, 0.0, -20.0);
    auxSolidSphere(1.0);
  glPopMatrix();

  glPushMatrix();
    glTranslatef(1.0, 0.0, -20.0);
    glRotatef(15.0, 0.0, 1.0, 0.0);
    glRotatef(15.0, 0.0, 0.0, 1.0);
    auxSolidCube(2.0);
  glPopMatrix();

  auxSwapBuffers();
}

/*
 * 'toggle_depth()' - Toggle the depth function between GL_LESS and
 *                    GL_GREATER.
 */

void CALLBACK
toggle_depth(void)
{
  if (depth_function == GL_LESS)
    depth_function = GL_GREATER;
  else
    depth_function = GL_LESS;
}

/*
 * 'move_plane()' - Move the cutting plane while we are idle...
 */

void CALLBACK
move_plane(void)
{
  cutting_plane += cutting_dir;

 /*
  * Reverse directions as needed...
  */

  if (cutting_plane <= -30.0 ||
      cutting_plane >= -15.0)
    cutting_dir = -cutting_dir;

  draw_scene();
}

/*
 * 'main()' - Initialize the window and display the scene until the
 *            user presses the ESCape key.
 */

void
main(void)
{
  auxInitDisplayMode(AUX_RGB | AUX_DOUBLE | AUX_DEPTH);
  auxInitWindow("Depth Function");

  auxKeyFunc(AUX_d, toggle_depth);
  auxReshapeFunc(reshape_scene);
  auxIdleFunc(move_plane);

  auxMainLoop(draw_scene);
}

/*
 * End of "depthcut.c".
 */

The Stencil Buffer

The stencil buffer provides many options to restrict drawing on the screen and has many applications that the depth buffer just canít do. At its simplest level, the stencil buffer can be used to block out certain areas on the screen. For example, a flight simulation program might use the stencil buffer to restrict drawing operations to the inside of the aircraftís round controls such as the artificial horizon and airspeed indicators.

Perhaps the most exciting application of the stencil buffer is for shadows. Depending on your graphics hardware, you can generate hard and soft shadows from multiple light sources, making your scenes much more realistic and exciting.

Using the Stencil Buffer

To use the stencil buffer, you have to first request one. For Windows, this means setting the cStencilBits field in the Pixel Format Descriptor (PFD) for your window, as in

pfd.cStencilBits = 1;

Once you have requested a stencil buffer, you must enable stenciling by calling glEnable(GL_STENCIL_TEST). Without this call, all stencil buffer operations are disabled.

Stencil Buffer Functions

There are four stenciling functions in OpenGL:

void glClearStencil(GLint s)
void glStencilFunc(GLenum func, GLint ref, GLuint mask)
void glStencilMask(GLuint mask)
void glStencilOp(GLenum fail, GLenum zfail, GLzpass)

The glClearStencil function is similar to glClearColor, glClearDepth, and glClearIndex; it provides the initial value that is stored in the stencil buffer when glClear(GL_STENCIL_BIT) is called. By default, a 0 stencil value is stored in the stencil buffer. Unlike the depth and color buffers, you donít always clear the stencil buffer every time you redisplay your scene. In the flight simulator example mentioned earlier, the aircraft control area might never change position or size, so redrawing into the stencil buffer would be unnecessary.


Previous Table of Contents Next