Open GL Super Bible

Previous Table of Contents Next


Listing 16-1 BLENDPOT.C: Using glBlendFunc for transparency

/*
 * "blendpot.c" - A test program demonstrating the use of glBlendFunc()
 *                for transparency.
 */

#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 */

GLfloat rotation = 0.0;

/*
 * '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)
{
  GLfloat        frame;
  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);

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

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

 /*
  * 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);

  glEnable(GL_COLOR_MATERIAL);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  glPushMatrix();
    glTranslatef(0.0, 0.0, -15.0);
    glRotatef(-rotation, 0.0, 1.0, 0.0);

    glDisable(GL_BLEND);
    glColor3f(1.0, 1.0, 0.0);
    auxSolidTeapot(1.0);
  glPopMatrix();

  glPushMatrix();
    glTranslatef(0.0, 0.0, -10.0);
    glRotatef(rotation, 0.0, 1.0, 0.0);
    glEnable(GL_BLEND);
    glColor4f(1.0, 1.0, 1.0, 0.25);
    auxSolidTeapot(1.0);
  glPopMatrix();

  auxSwapBuffers();
}

/*
 * 'rotate_objects()' - Rotate while we are idle…
 */

void CALLBACK
rotate_objects(void)
{
  rotation += 2.0;
  if (rotation >= 360.0)
    rotation -= 360.0;

  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("Blended Teapot");

  auxReshapeFunc(reshape_scene);
  auxIdleFunc(rotate_objects);

  auxMainLoop(draw_scene);
}

/*
 * End of "blendpot.c".
 */

Using Blending with Anti-Aliasing

The appearance of anti-aliased points, lines, and polygons can be enhanced by using the same two blending functions as for transparency, GL_SRC_ALPHA and GL_ONE_MINUS_SRC_ALPHA. On systems with hardware-assisted anti-aliasing and blending, blending will produce results similar to full-screen anti-aliased scenes made using the accumulation buffer. At the same time, blending is several times faster than accumulation because the scene needs to be drawn only once.

To draw a scene using blending and anti-aliased primitives, call the following functions:

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_POLYGON_SMOOTH);

Using Blending for a Paint Program

The same techniques used for 3D graphics can be applied to 2D graphics. In the case of paint programs, we can use blending to create soft-edged “brushes.” To start, we will define alpha images of each brush. An alpha image contains alpha values but no RGB (color) values and will define how much color actually is drawn on the page (see Figure 16-2).


Figure 16-2  Alpha “brush” image

To “paint” using this brush image, we’re going to use a different set of blending functions:

glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_ALPHA);

Instead of the GL_SRC_ALPHA function for the source color, we use the GL_SRC_COLOR function, which uses the current color instead of the alpha component. Thus, the color that will be applied is as follows:

R = Rs * Ab + Rd * (1.0 - Ab)
G = Gs * Ab + Gd * (1.0 - Ab)
B = Bs * Ab + Bd * (1.0 - Ab)

That is, the alpha values from the brush image will be used instead of the current alpha color value!

Listing 16-2 is a simple “paint” program that uses a 7 x 7 pixel brush image for painting. The main event loop handles drawing in the window. When you hold the left mouse button down, the event loop will call the DrawXY function to paint at the current mouse position:

glRasterPos2i(mousex, mousey);
glDrawPixels(7, 7, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, BlendBrush[0]);

The RepaintWindow function clears the client area whenever the window is resized or needs to be redrawn:

glViewport(0, 0, rect->right, rect->bottom);
glOrtho(0.0, (float)rect->right, (float)rect->bottom, 0.0, -1.0, 1.0);

glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

Unfortunately, this means you’ll lose your painting. A real paint application could use glReadPixels to copy the drawn pixels to an off-screen buffer, which could be used to redraw the screen later using glDrawPixels.


Previous Table of Contents Next