Tunnel: C/C++ Version


/****************************************************************************\
*                                                                            *
*  Tunnel.c                                                                  *
*                                                                            *
*  This program draws a Gouraud-shaded tunnel and allows the viewer to move  *
*  through the tunnel using keyboard controls.                               *
*                                                                            *
\****************************************************************************/
#include 
#define vbWidth  640
#define vbHeight 480
typedef struct point3d
{
   double x;
   double y;
   double z;
} POINT3D;
// four sides of a 20x40x100 tunnel, defined in 3D world coordinates
POINT3D Floor[] = {
   {-10.0, 0.0,100.0},
   {-10.0, 0.0,200.0},
   { 10.0, 0.0,200.0},
   { 10.0, 0.0,100.0}
};
POINT3D WestSide[] = {
   {-10.0,  0.0,100.0},
   {-10.0, 40.0,100.0},
   {-10.0, 40.0,200.0},
   {-10.0,  0.0,200.0}
};
POINT3D EastSide[] = {
   { 10.0,  0.0,100.0},
   { 10.0,  0.0,200.0},
   { 10.0, 40.0,200.0},
   { 10.0, 40.0,100.0}
};
POINT3D Ceiling[] = {
   {-10.0, 40.0,100.0},
   { 10.0, 40.0,100.0},
   { 10.0, 40.0,200.0},
   {-10.0, 40.0,200.0}
};
// RGB color values at each vertex of each side
BYTE FloorRGB[]    = {192,192,192,  64, 64, 64,  64, 64, 64, 192,192,192};
BYTE WestSideRGB[] = { 32, 32,255,  32, 32,255,  32, 32, 96,  32, 32, 96};
BYTE EastSideRGB[] = { 32, 32,255,  32, 32, 96,  32, 32, 96,  32, 32,255};
BYTE CeilingRGB[]  = {192,192,192, 192,192,192,  64, 64, 64,  64, 64, 64};
// for convenience, an array of pointers to each of the four sides
POINT3D *Faces[] = {Floor,WestSide,EastSide,Ceiling};
// a similar array of pointers to each side's RGB values
BYTE *FacesRGB[] = {FloorRGB,WestSideRGB,EastSideRGB,CeilingRGB};
LRESULT CALLBACK WindowProc(HWND,UINT,WPARAM,LPARAM);
void CheckForMovement(void);
void DrawTunnel(void);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdParam, int iCmdShow)
{
   static char szAppName[] = "FGtunnel";
   HWND        hWnd;
   MSG         msg;
   WNDCLASSEX  wndclass;
   wndclass.cbSize        = sizeof(wndclass);
   wndclass.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
   wndclass.lpfnWndProc   = WindowProc;
   wndclass.cbClsExtra    = 0;
   wndclass.cbWndExtra    = 0;
   wndclass.hInstance     = hInstance;
   wndclass.hIcon         = LoadIcon(NULL,IDI_APPLICATION);
   wndclass.hCursor       = LoadCursor(NULL,IDC_ARROW);
   wndclass.hbrBackground = NULL;
   wndclass.lpszMenuName  = NULL;
   wndclass.lpszClassName = szAppName;
   wndclass.hIconSm       = LoadIcon(NULL,IDI_APPLICATION);
   RegisterClassEx(&wndclass);
   hWnd = CreateWindow(szAppName, // window class name
      "Gouraud-Shaded Tunnel", // window caption
      WS_OVERLAPPEDWINDOW,     // window style
      CW_USEDEFAULT,           // initial x position
      CW_USEDEFAULT,           // initial y position
      CW_USEDEFAULT,           // initial x size
      CW_USEDEFAULT,           // initial y size
      NULL,                    // parent window handle
      NULL,                    // window menu handle
      hInstance,               // program instance handle
      NULL);                   // creation parameters
   ShowWindow(hWnd,iCmdShow);
   UpdateWindow(hWnd);
   // The message loop processes entries placed in the message queue.
   // When no message is ready, call CheckForMovement() to check if
   // we want to perform movement.
   while (TRUE)
   {
      if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
      {
         if (msg.message == WM_QUIT)
            break;
         else
         {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
         }
      }
      else
         CheckForMovement();
   }
   return msg.wParam;
}
/****************************************************************************\
*                                                                            *
*  WindowProc()                                                              *
*                                                                            *
\****************************************************************************/
HDC      hDC;
HPALETTE hPal;
int      hVB;
UINT     cxClient, cyClient;
int      hZB;
LRESULT CALLBACK WindowProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
   PAINTSTRUCT ps;
   int vbDepth;
   switch (iMsg)
   {
      case WM_CREATE:
         hDC = GetDC(hWnd);
         fg_setdc(hDC);
         hPal = fg_defpal();
         fg_realize(hPal);
         fg_vbinit();
         vbDepth = fg_colors();
         if (vbDepth < 16) vbDepth = 16;
         fg_vbdepth(vbDepth);
         hVB = fg_vballoc(vbWidth,vbHeight);
         fg_vbopen(hVB);
         fg_vbcolors();
         hZB = fg_zballoc(vbWidth,vbHeight);
         fg_zbopen(hZB);
         fg_setcolor(-1);
         fg_fillpage();
         fg_3Dviewport(0,vbWidth-1,0,vbHeight-1,1.0);
         fg_3Drenderstate(FG_ZBUFFER | FG_ZCLIP);
         fg_3Dlookat(0.0,10.0,50.0,0.0,10.0,100.0);
         return 0;
      case WM_PAINT:
         BeginPaint(hWnd,&ps);
         fg_vbscale(0,vbWidth-1,0,vbHeight-1,0,cxClient-1,0,cyClient-1);
         EndPaint(hWnd,&ps);
         return 0;
      case WM_SETFOCUS:
         fg_realize(hPal);
         InvalidateRect(hWnd,NULL,TRUE);
         return 0;
      case WM_SIZE:
         cxClient = LOWORD(lParam);
         cyClient = HIWORD(lParam);
         return 0;
      case WM_DESTROY:
         fg_vbclose();
         fg_zbfree(hZB);
         fg_vbfree(hVB);
         fg_vbfin();
         DeleteObject(hPal);
         ReleaseDC(hWnd,hDC);
         PostQuitMessage(0);
         return 0;
   }
   return DefWindowProc(hWnd,iMsg,wParam,lParam);
}
/****************************************************************************\
*                                                                            *
*  CheckForMovement()                                                        *
*                                                                            *
*  The CheckForMovement() function checks for key presses that control the   *
*  user's movement, and if required redraws the tunnel viewed from the new   *
*  camera position. It is called from the WinMain() message loop when there  *
*  are no messages waiting.                                                  *
*                                                                            *
\****************************************************************************/
void CheckForMovement()
{
   static BOOL Redraw = TRUE;
   // up arrow moves viewer forward
   if (fg_kbtest(72))
   {
      fg_3Dmoveforward(2.0);
      Redraw = TRUE;
   }
   // down arrow moves viewer backward
   else if (fg_kbtest(80))
   {
      fg_3Dmoveforward(-2.0);
      Redraw = TRUE;
   }
   // right arrow turns viewer to the right
   else if (fg_kbtest(77))
   {
      fg_3Drotateright(6*10);
      Redraw = TRUE;
   }
   // left arrow turns viewer to the left
   else if (fg_kbtest(75))
   {
      fg_3Drotateright(-6*10);
      Redraw = TRUE;
   }
   // if the viewer's position or rotation changed, redraw the tunnel
   if (Redraw)
   {
      // prepare the z-buffer for the next frame
      fg_zbframe();
      // erase the previous frame from the virtual buffer
      fg_setcolor(-1);
      fg_fillpage();
      // draw the tunnel
      DrawTunnel();
      // display what we just drew
      fg_vbscale(0,vbWidth-1,0,vbHeight-1,0,cxClient-1,0,cyClient-1);
      Redraw = FALSE;
   }
}
/****************************************************************************\
*                                                                            *
*  DrawTunnel()                                                              *
*                                                                            *
*  Draws each of the tunnel's four sides in 3D world space.                  *
*                                                                            *
\****************************************************************************/
void DrawTunnel()
{
   register int i;
   for (i = 0; i < 4; i++)
   {
      fg_3Dshade((double *)Faces[i],(char *)FacesRGB[i],4);
   }
}

<< Prev

Next >>

Contents
Fastgraph Home Page

 

copyright 2001 Ted Gruber Software, Inc.