Open GL Super Bible

Previous Table of Contents Next


Summary

In this chapter we’ve covered the quadric drawing functions. OpenGL quadrics are geometric shapes that form the basic “building blocks” of many objects, both manufactured and natural. Using the quadric drawing functions is a convenient and fast way to avoid writing a lot of extra code for drawing these shapes.

Now here’s Listing 13-1, the pencil program.

Listing 13-1 The pencil drawing program

/*
 * Include necessary headers.
 */

#include "texture.h"
#include "pencil.h"
#include <stdarg.h>
/*
 * Globals…
 */

HWND       PencilWindow;      /* Scene window */
HPALETTE   PencilPalette;     /* Color palette (if necessary) */
HDC        PencilDC;          /* Drawing context */
HGLRC      PencilRC;          /* OpenGL rendering context */

GLuint     PencilTexture,     /* Pencil texture image */
           LeadTexture;       /* Lead… */

GLfloat    PencilRoll = 0.0,  /* Pencil orientation */
           PencilPitch = 90.0,     
           PencilHeading = 0.0;
GLUquadricObj   *PencilObj;
/* 
* Local functions…
 */
void                DisplayErrorMessage(char *, …);
void                MakePalette(int);
LRESULT CALLBACK    PencilProc(HWND, UINT, WPARAM, LPARAM);
void                LoadAllTextures(void);
void                RepaintWindow(RECT *);
void                PrintBitmap(void);

/*
 * 'WinMain()' - Main entry…
 */

int APIENTRY
WinMain(HINSTANCE hInst,                /* I - Current process instance */
	   HINSTANCE hPrevInstance,     /* I - Parent process instance */
   	   LPSTR     lpCmdLine,         /* I - Command-line arguments */
  	   int       nCmdShow)          /* I - Show window at startup? */
{
  MSG        msg;                       /* Window UI event */
  WNDCLASS   wc;                        /* Window class */
  RECT       rect;                      /* Current client area rectangle */

 /*
  * Register main window…
  */

  wc.style         = 0;
  wc.lpfnWndProc   = (WNDPROC)PencilProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = 0;
  wc.hInstance     = hInst;
  wc.hIcon         = NULL;
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = 0;        
  wc.lpszMenuName  = MAKEINTRESOURCE(IDR_MENU1);
  wc.lpszClassName = "Textured Quadric Pencil";

  if (RegisterClass(&wc) == 0)
  {
    DisplayErrorMessage("Unable to register window class!");
    return (FALSE);
  };

 /*
  * Then create it…
  */

  PencilWindow = CreateWindow("Textured Quadric Pencil", "Textured
                             Quadric Pencil", WS_OVERLAPPEDWINDOW
                             | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
                             32, 32, 400, 300,
                             NULL, NULL, hInst, NULL);

  if (PencilWindow == NULL)
  {
    DisplayErrorMessage("Unable to create window!");
    return (FALSE);
  };

  ShowWindow(PencilWindow, nCmdShow);
  UpdateWindow(PencilWindow);
 /*
  * Loop on events until the user quits this application…
  */

  while (TRUE)
  {
   /*
    * Process all messages in the queue…
    */

    while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) == TRUE)
      if (GetMessage(&msg, NULL, 0, 0))
      {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
      else
        return (1);

   /*
    * Spin the pencil…
    */

    PencilRoll    += 1.0;
    PencilPitch   += 2.0;
    PencilHeading += 3.0;

    GetClientRect(PencilWindow, &rect);
    RepaintWindow(&rect);
  };

  return (msg.wParam);
}
/*
 * 'DisplayErrorMessage()' - Display an error message dialog.
 */

void
DisplayErrorMessage(char *format,   /* I - printf() style format string */
                       …)           /* I - Other arguments as necessary */
{
  va_list   ap;                     /* Argument pointer */
  char      s[1024];                /* Output string */

  if (format == NULL)
    return;

  va_start(ap, format);
  vsprintf(s, format, ap);
  va_end(ap);

  MessageBeep(MB_ICONEXCLAMATION);
  MessageBox(NULL, s, "Error", MB_OK | MB_ICONEXCLAMATION);
}


/*
 * 'MakePalette()' - Make a color palette for RGB colors if necessary.
 */

void
MakePalette(int pf)                /* I - Pixel format ID */
{
  PIXELFORMATDESCRIPTOR pfd;       /* Pixel format information */
  LOGPALETTE      *pPal;           /* Pointer to logical palette */
  int              nColors;        /* Number of entries in palette   */
  int              i,              /* Color index */
                   rmax,           /* Maximum red value */
                   gmax,           /* Maximum green value */
                   bmax;           /* Maximum blue value */

 /*
  * Find out if we need to define a color palette…
  */

  DescribePixelFormat(PencilDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

  if (!(pfd.dwFlags & PFD_NEED_PALETTE))
  {
    PencilPalette = NULL;
    return;
  };

 /*
  * Allocate memory for a color palette…
  */

  nColors = 1 << pfd.cColorBits; 
  
  pPal = (LOGPALETTE *)malloc(sizeof(LOGPALETTE) +
                              nColors * sizeof(PALETTEENTRY));
  pPal->palVersion    = 0x300;
  pPal->palNumEntries = nColors;

 /*
  * Get the maximum values for red, green, and blue.  Then build 'nColors'
  * colors…
  */

  rmax = (1 << pfd.cRedBits)   - 1;
  gmax = (1 << pfd.cGreenBits) - 1;
  bmax = (1 << pfd.cBlueBits)  - 1;

  for (i = 0; i < nColors; i ++)
  {
    pPal->palPalEntry[i].peRed   = 255 *
                   ((i >> pfd.cRedShift) & rmax) /
    rmax;
    pPal->palPalEntry[i].peGreen = 255 *
                   ((i >> pfd.cGreenShift) & gmax) /
    gmax;
    pPal->palPalEntry[i].peBlue  = 255 *
                   ((i >> pfd.cBlueShift) & bmax) /
    bmax;

    pPal->palPalEntry[i].peFlags = 0;
  };

 /*
  * Create, select, and realize the palette…
  */

  PencilPalette = CreatePalette(pPal);
  SelectPalette(PencilDC, PencilPalette, FALSE);
  RealizePalette(PencilDC);

  free(pPal);
}

/*
 * 'PencilProc()' - Handle window events in the viewing window.
 */

LRESULT CALLBACK
PencilProc(CHWND   hWnd,      /* I - Window triggering this event */
         UINT   uMsg,         /* I - Message type */
         WPARAM wParam,       /* I - 'word' parameter value */
         LPARAM lParam)       /* I - 'long' parameter value */
{
  int                  pf;    /* Pixel format ID */
  PIXELFORMATDESCRIPTOR pfd;  /* Pixel format information */
  PAINTSTRUCT          ps;    /* WM_PAINT message info */
  RECT            rect;       /* Current client area rectangle */

  switch (uMsg)
  {
    case WM_CREATE :
       /*
        * 'Create' message.  Get device and rendering contexts, and
   * setup the client area for OpenGL drawing…
   */

   PencilDC = GetDC(hWnd);             
        pfd.nSize        = sizeof(pfd);
        pfd.nVersion     = 1;
        pfd.dwFlags      = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL
                                              | PFD_DOUBLEBUFFER;
                                               /* Do OpenGL drawing */
        pfd.dwLayerMask  = PFD_MAIN_PLANE;     /* Main drawing plane */
        pfd.iPixelType   = PFD_TYPE_RGBA;      /* RGB color buffer */
        pfd.cColorBits   = 0;                  /* Best color buffer
                                               please*/
        pfd.cDepthBits   = 32;                 /* Need a depth buffer */
        pfd.cStencilBits = 0;                  /* No stencil buffer */
        pfd.cAccumBits   = 0;                  /* No accumulation buffer
        */

        pf = ChoosePixelFormat(PencilDC, &pfd);
        if (pf == 0)
          DisplayErrorMessage("texscene was unable to choose a suitable 
          pixel format!");
        else if (!SetPixelFormat(PencilDC, pf, &pfd))
          DisplayErrorMessage("texscene was unable to set the pixel
          format!"); 
     
         MakePalette(pf); 
     
         PencilRC = wglCreateContext(PencilDC);
        wglMakeCurrent(PencilDC, PencilRC); 
     
        /*
        * Load all the texture images into display lists…
        */

        LoadAllTextures();
        PencilObj = gluNewQuadric();
        gluQuadricTexture(PencilObj, GL_TRUE);
        break;

case WM_SIZE :
case WM_PAINT :
       /*
        * Repaint the client area with our bitmap…
        */

        BeginPaint(hWnd, &ps);

        GetClientRect(hWnd, &rect);
        RepaintWindow(&rect);

        EndPaint(hWnd, &ps);
        break;

    case WM_COMMAND :
       /*
        * Handle menu selections…
        */

        switch (LOWORD(wParam))
        {
          case IDM_FILE_PRINT :
               PrintBitmap();
               break;
          case IDM_FILE_EXIT :
               DestroyWindow(PencilWindow);
               break;
        };
        break;
    case WM_QUIT :
    case WM_CLOSE :
       /*
        * Destroy the windows and bitmaps and exit…
        */

        DestroyWindow(PencilWindow);

        exit(0);
        break;

	case WM_DESTROY :
       /*
        * Release and free the device context, rendering
        * context, and color palette…
        */

        if (PencilRC)
          wglDeleteContext(PencilRC);

        if (PencilDC)
          ReleaseDC(PencilWindow, PencilDC);

        if (PencilPalette)
          DeleteObject(PencilPalette);

        PostQuitMessage(0);
        break;

    case WM_QUERYNEWPALETTE :
       /*
        * Realize the color palette if necessary…
        */

        if (PencilPalette)
        {
          SelectPalette(PencilDC, PencilPalette, FALSE);
          RealizePalette(PencilDC);

          InvalidateRect(hWnd, NULL, FALSE);
          return (TRUE);
        };
        break;

    case WM_PALETTECHANGED:
       /*
        * Reselect our color palette if necessary…
        */

        if (PencilPalette && (HWND)wParam != hWnd)
        {
          SelectPalette(PencilDC, PencilPalette, FALSE);
          RealizePalette(PencilDC);

          UpdateColors(PencilDC);
        };
        break;

default :
       /*
        * Pass all other messages through the default window
        * procedure…
        */

        return (DefWindowProc(hWnd, uMsg, wParam, lParam));
  };

  return (FALSE);
}

/*
 * 'LoadAllTextures()' - Load texture images for the scene.
 */

void
LoadAllTextures(void)
{
  glNewList(PencilTexture = glGenLists(1), GL_COMPILE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    TextureLoadBitmap("textures/pencil.bmp");
  glEndList();

  glNewList(LeadTexture = glGenLists(1), GL_COMPILE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    TextureLoadBitmap("textures/lead.bmp");
  glEndList();
}

/*
 * 'RepaintWindow()' - Redraw the client area with our pencil.
 */

void
RepaintWindow(RECT *rect)   /* I - Client area rectangle */
{
 /*
  * Reset the viewport and clear the window to light blue…
  */

  glViewport(0, 0, rect->right, rect->bottom);

  glClearColor(0.7, 0.7, 1.0, 1.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 /*
  * Setup viewing transformations for the current position and
  * orientation…
  */

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45.0, (float)rect->right / (float)rect->bottom,
                 0.1, 1000.0);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_TEXTURE_2D);
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
    glTranslatef(0.0, 0.0, -80.0);
    glRotatef(PencilHeading, 0.0, -1.0, 0.0);
    glRotatef(PencilPitch, 1.0, 0.0, 0.0);
    glRotatef(PencilRoll, 0.0, 0.0, -1.0);

   /*
    * First the pencil body - this uses a 6-sided cylinder…
    */

    gluQuadricNormals(PencilObj, GLU_FLAT);
    glCallList(PencilTexture);

    glPushMatrix();
      glTranslatef(0.0, 0.0, -20.0);

      gluCylinder(PencilObj, 5.0, 5.0, 40.0, 6, 2);
    glPopMatrix();

   /*
    * Then the ends - a cone at the tip and a flat cone at the base…
    */

    gluQuadricNormals(PencilObj, GLU_SMOOTH);
    glCallList(LeadTexture);

    glPushMatrix();
      glTranslatef(0.0, 0.0, 20.0);

      gluCylinder(PencilObj, 5.0, 0.0, 7.5, 6, 2);
    glPopMatrix();

    glPushMatrix();
      glTranslatef(0.0, 0.0, -20.0);

     /*
      * Normally we might use a disk shape for this, but unfortunately the
      texture
      * coordinates don't match up…
      */
      gluCylinder(PencilObj, 5.0, 0.0, 0.0, 6, 2);
    glPopMatrix();
  glPopMatrix();

 /*
  * Swap buffers and return…
  */

  glFinish();
  SwapBuffers(PencilDC);
}
/*
 * 'PrintBitmap()' - Print the currently displayed scene.
 */

void
PrintBitmap(void)
{
  void      *bits;        /* Screen bitmap bits */
  BITMAPINFO   *info;     /* Screen bitmap info */

 /*
  * Grab the screen bitmap…
  */

  bits = ReadDIBitmap(&info);
  if (bits == NULL)
  {
    DisplayErrorMessage("Unable to get OpenGL bitmap from screen!");
    return;
  };

 /*
  * Print the bitmap…
  */

  PrintDIBitmap(PencilWindow, info, bits);

 /*
  * Free memory and return…
  */

  free(info);
  free(bits);
}


Previous Table of Contents Next