home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Hits 1995 June / Image.iso / demos / woodruff / wing / cube.cp_ / cube.cp
Encoding:
Text File  |  1994-06-26  |  16.7 KB  |  632 lines

  1. /**************************************************************************
  2.     cube.cpp - A spinning cube demo for WinG
  3.  
  4.     History:
  5.         11/18/93 JonBl    Created
  6.  **************************************************************************/
  7. /**************************************************************************
  8.  
  9.    THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  10.    KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  11.    IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  12.    PURPOSE.
  13.  
  14.    Copyright (c) 1993  Microsoft Corporation.  All Rights Reserved.
  15.  
  16.  **************************************************************************/
  17.  
  18. #include <windows.h>
  19. #include <windowsx.h>
  20. #include <wing.h>
  21.  
  22. #include "cube.hpp"
  23. #include "dumb3d.hpp"
  24.  
  25. #if defined(WIN32)
  26. #define _export
  27. #endif
  28.  
  29. /**************************************************************************
  30.     Global Variables
  31.  **************************************************************************/
  32.  
  33. static char    szAppName[]="Spinning Cube";
  34.  
  35. //*** Global Windows needs
  36. static HINSTANCE    hInstApp;
  37. static BOOL            fAppActive;
  38. static HWND            hwndApp;
  39. static HPALETTE    hpalApp = 0;
  40. static HDC        hdcWinG;
  41. static HBITMAP OldBitmap;
  42. static HBITMAP WinGBitmap;
  43.  
  44. struct
  45. {
  46.     BITMAPINFOHEADER Header;
  47.     RGBQUAD aColorTable[256];
  48.  
  49. } HeaderAndPalette =
  50. {
  51.     sizeof(BITMAPINFOHEADER),
  52.     50, 50,
  53.     1, 8,
  54.     BI_RGB,
  55.     0, 0, 0, 0, 0
  56. };
  57.  
  58.  
  59. static int        DibWidth, DibHeight;
  60.  
  61. //*** Cube vertices, normals, shades, and modelling transform
  62. static point_4 CubeVertices[8] =
  63. {
  64.     point_4( -10,  10, -10 ),
  65.     point_4( -10,  10,  10 ),
  66.     point_4(  10,  10,  10 ),
  67.     point_4(  10,  10, -10 ),
  68.     point_4(  10, -10, -10 ),
  69.     point_4(  10, -10,  10 ),
  70.     point_4( -10, -10,  10 ),
  71.     point_4( -10, -10, -10 )
  72. };
  73. static vector_4   CubeSurfaceNormals[6];
  74. static real       CubeSurfaceShades[6];
  75. static matrix_4x4 CubeTransform;
  76.  
  77. //*** Cube edges - ordered indices into the vertex array
  78. const int CubeFaces[6][4] =
  79. {
  80.     0, 1, 2, 3,
  81.     2, 1, 6, 5,
  82.     3, 2, 5, 4,
  83.     0, 3, 4, 7,
  84.     1, 0, 7, 6,
  85.     4, 5, 6, 7
  86. };
  87.  
  88. //*** Cube colors - one RGB color per surface
  89. const unsigned char CubeColors[6][3] =
  90. {
  91.     240,  20,  20,        // Unsaturated Red
  92.      20, 240,  20,        // Unsaturated Green
  93.      20,  20, 240,        // Unsaturated Blue
  94.     128,  64,   0,        // Brown
  95.     240,  20, 240,        // Unsaturated Magenta
  96.     240, 240,  20        // Unsaturated Yellow
  97. };
  98.  
  99. //*** Lighting
  100. vector_4   LightSourceDirection;
  101. const real AmbientLight = 0.2;
  102.  
  103. //*** Viewing and perspective
  104. static matrix_4x4 ViewPerspective;
  105. static point_4    Viewpoint(60, 60, 60);
  106. static vector_4   Up(0, 1, 0);
  107. static point_4    Origin;
  108.  
  109. //*** Interaction
  110. static real  XMove,YMove;
  111. static short gSpinFlag = 1;
  112.  
  113. //*** Dithering
  114. static int DitherType = 0;
  115.  
  116. /**************************************************************************
  117.    Internal function declarations
  118.  **************************************************************************/
  119.  
  120. LONG FAR PASCAL _export AppWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);
  121. void AppExit(void);
  122. BOOL AppIdle(void);
  123. void AppPaint(HWND hwnd, HDC hdc);
  124.  
  125. void TransformCube(matrix_4x4 const &Transform);
  126. void ProjectAndDrawCube(HDC hdc, int XOffset, int YOffset);
  127.  
  128. /**************************************************************************
  129.     AppAbout
  130.  
  131.     Description:
  132.         This function handles messages belonging to the "About" dialog box.
  133.     The only message that it looks for is WM_COMMAND, indicating the user
  134.     has pressed the "OK" button.
  135.  **************************************************************************/
  136.  
  137. BOOL FAR PASCAL _export AppAbout(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
  138. {
  139.     switch (msg)
  140.     {
  141.         case WM_COMMAND:
  142.             if (LOWORD(wParam) == IDOK)
  143.                 EndDialog(hwnd, TRUE);
  144.             break;
  145.  
  146.         case WM_INITDIALOG:
  147.             return TRUE;
  148.     }
  149.     return FALSE;
  150. }
  151.  
  152. /**************************************************************************
  153.     AppInit
  154.  
  155.     Description:
  156.         This is called when the application is first loaded. It initializes
  157.     all variables, registers the window class, and creates the main app
  158.     window.
  159.  **************************************************************************/
  160.  
  161. BOOL AppInit(HINSTANCE hInst,HINSTANCE hPrev,int sw,LPSTR szCmdLine)
  162. {
  163.     WNDCLASS cls;
  164.  
  165.     /* Save instance handle for DialogBoxs */
  166.     hInstApp = hInst;
  167.  
  168.     if (!hPrev)
  169.     {
  170.         //***  Register a class for the main application window
  171.         cls.hCursor        = LoadCursor(0,IDC_ARROW);
  172.  
  173.         //*** Just for fun, we'll draw our own spinning cube icon.
  174.         cls.hIcon          = 0;
  175.         cls.lpszMenuName   = "AppMenu";
  176.         cls.lpszClassName  = szAppName;
  177.         cls.hbrBackground  = (HBRUSH)GetStockObject(WHITE_BRUSH);
  178.         cls.hInstance      = hInst;
  179.         cls.style          = CS_BYTEALIGNCLIENT | CS_VREDRAW | CS_HREDRAW;
  180.         cls.lpfnWndProc    = (WNDPROC)AppWndProc;
  181.         cls.cbClsExtra     = 0;
  182.         cls.cbWndExtra     = 0;
  183.  
  184.         if (!RegisterClass(&cls))
  185.             return FALSE;
  186.     }
  187.  
  188.     //*** Set and normalize the light source
  189.     LightSourceDirection = vector_4(50, 30, -15);
  190.     LightSourceDirection.Normalize();
  191.  
  192.     //*** Distance to view plane:
  193.     ViewPerspective.SetElement(3, 2, 1/300.0);
  194.     ViewPerspective.SetElement(3, 3, 0);
  195.  
  196.     //*** Viewport scaling - some arbitrary number like 3.5 will do
  197.     ViewPerspective.SetElement(0, 0, 3.5);
  198.     ViewPerspective.SetElement(1, 1, 3.5);
  199.  
  200.     //*** Calculate the initial normals and shades
  201.     TransformCube(CubeTransform);
  202.  
  203.     //*** Then generate an interesting rotation for the spin
  204.     CubeTransform.ConcatenateYRotation(6.0);
  205.     CubeTransform.ConcatenateXRotation(3.5);
  206.     CubeTransform.ConcatenateZRotation(2.0);
  207.  
  208.     hwndApp = CreateWindow (szAppName,           // Class name
  209.                                     szAppName,           // Caption
  210.                                     WS_OVERLAPPED |
  211.                                     WS_CAPTION |
  212.                                     WS_SYSMENU |
  213.                                     WS_MINIMIZEBOX,      // Style bits
  214.                                     CW_USEDEFAULT, 0,    // Position
  215.                                     350,350,                 // Size
  216.                                     0,                   // Parent window (no parent)
  217.                                     0,                   // use class menu
  218.                                     hInst,               // handle to window instance
  219.                                     0                    // no params to pass on
  220.                                     );
  221.     hdcWinG = WinGCreateDC();
  222.  
  223.     ShowWindow(hwndApp,sw);
  224.  
  225.     //*** Check the default dither selection
  226.     HMENU hMenu = GetMenu(hwndApp);
  227.     CheckMenuItem(hMenu, MENU_DISPERSED8x8, MF_CHECKED);
  228.     CheckMenuItem(hMenu, MENU_SPIN, MF_CHECKED);
  229.  
  230.     return TRUE;
  231. }
  232.  
  233. /**************************************************************************
  234.     WinMain
  235.  
  236.     Description:
  237.         The main procedure for the App.  After initializing, it just goes
  238.     into a message-processing loop until it gets a WM_QUIT message.
  239.  **************************************************************************/
  240.  
  241. int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
  242. {
  243.     MSG     msg;
  244.  
  245.     //*** Call initialization procedure
  246.     if (!AppInit(hInst,hPrev,sw,szCmdLine))
  247.         return FALSE;
  248.  
  249.       //*** Polling messages from event queue until quit
  250.     for (;;)
  251.     {
  252.         if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  253.         {
  254.             if (msg.message == WM_QUIT)
  255.                 break;
  256.             TranslateMessage(&msg);
  257.             DispatchMessage(&msg);
  258.         }
  259.         else
  260.         {
  261.             if (AppIdle())
  262.                 WaitMessage();
  263.         }
  264.     }
  265.  
  266.     return msg.wParam;
  267. }
  268.  
  269. /**************************************************************************
  270.     AppIdle
  271.  
  272.     Description:
  273.  **************************************************************************/
  274.  
  275. BOOL AppIdle()
  276. {
  277.     //*** Spin while the app is active, lbutton is up, and spinning is on.
  278.     //*** Spin while the app is iconized.
  279.     if ( (gSpinFlag && fAppActive && GetKeyState(VK_LBUTTON) >= 0)
  280.             || IsIconic(hwndApp))
  281.     {
  282.         //*** If the app is active, spin the cube and redraw
  283.         TransformCube(CubeTransform);
  284.         HDC hdc = GetDC(hwndApp);
  285.         if (hpalApp)
  286.         {
  287.             SelectPalette(hdc, hpalApp, FALSE);
  288.             RealizePalette(hdc);
  289.         }
  290.         AppPaint(hwndApp, hdc);
  291.         ReleaseDC(hwndApp, hdc);
  292.         return FALSE;
  293.     }
  294.     else
  295.     {
  296.         //*** Don't do anything when not the active app
  297.         return TRUE;
  298.     }
  299. }
  300.  
  301. /**************************************************************************
  302.     AppPaint
  303.  
  304.     Description:
  305.         The paint function. Draws the centered cube in the offscreen DIBDC,
  306.     then copies it to the screen using QuickStretchBlt.
  307.  **************************************************************************/
  308.  
  309. void AppPaint(HWND hwnd, HDC hdc)
  310. {
  311.     //*** Clear the DIBDC buffer to white
  312.     PatBlt(hdcWinG, 0, 0, DibWidth, DibHeight, WHITENESS);
  313.  
  314.     //*** Move the viewpoint according to the mouse movement
  315.     //*** Rotate it around the Y and X axes
  316.     if(YMove || XMove)
  317.     {
  318.         matrix_4x4 Movement;
  319.         Movement.ConcatenateYRotation(-YMove);
  320.         Movement.ConcatenateXRotation(XMove);
  321.  
  322.         XMove = YMove = 0;
  323.  
  324.         TransformCube(Movement);
  325.     }
  326.  
  327.     //*** and GO!
  328.     ProjectAndDrawCube(hdcWinG, DibWidth/2, DibHeight/2);
  329.  
  330.     RECT rc;
  331.     GetClientRect(hwndApp, &rc);
  332.  
  333.     //*** Flip the buffers using QuickStretchBlt
  334.     if (IsIconic(hwndApp))
  335.     {
  336.         WinGStretchBlt(hdc,0,0,rc.right,rc.bottom,hdcWinG,0,0,
  337.                 DibWidth,DibHeight);
  338.     }
  339.     else
  340.         WinGBitBlt(hdc,0,0,rc.right,rc.bottom,hdcWinG,0,0);
  341. }
  342.  
  343. /**************************************************************************
  344.     AppWndProc
  345.  
  346.     Description:
  347.         Main window proc. Standard Windows fare.
  348.  **************************************************************************/
  349.  
  350. LONG FAR PASCAL _export AppWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
  351. {
  352.     PAINTSTRUCT ps;
  353.     HDC hdc;
  354.     BOOL f;
  355.     HMENU hMenu;
  356.     static int LastX, LastY;
  357.  
  358.     switch (msg)
  359.     {
  360.         case WM_CREATE:
  361.         {
  362.             //*** Use the halftone palette to make things pretty
  363.             hpalApp = WinGCreateHalftonePalette();
  364.             GetPaletteEntries(hpalApp,0,256,
  365.                 (PALETTEENTRY far *)HeaderAndPalette.aColorTable);
  366.  
  367.             for(int Counter = 0;Counter < 256;Counter++)
  368.             {
  369.                 // PALETTEENTRYs and RGBQUADs are backwards
  370.  
  371.                 BYTE Temp = HeaderAndPalette.aColorTable[Counter].rgbBlue;
  372.  
  373.                 HeaderAndPalette.aColorTable[Counter].rgbBlue =
  374.                         HeaderAndPalette.aColorTable[Counter].rgbRed;
  375.  
  376.                 HeaderAndPalette.aColorTable[Counter].rgbRed = Temp;
  377.             }
  378.             break;
  379.         }
  380.         case WM_ACTIVATEAPP:
  381.             //*** Keep track of whether or not the app is in the foreground
  382.             fAppActive = (BOOL)wParam;
  383.             break;
  384.  
  385.         case WM_COMMAND:
  386.             switch(wParam)
  387.             {
  388.                 case MENU_ABOUT:
  389.                     DialogBox(hInstApp, "AppAbout", hwnd, AppAbout);
  390.                     break;
  391.  
  392.                 case MENU_EXIT:
  393.                     PostMessage(hwnd, WM_CLOSE, 0, 0L);
  394.                     break;
  395.  
  396.                 case MENU_SPIN:
  397.                     //*** Toggle the spin flag and the check mark
  398.                     hMenu = GetMenu(hwnd);
  399.                     if (gSpinFlag)
  400.                     {
  401.                         gSpinFlag = 0;
  402.                         CheckMenuItem(hMenu, MENU_SPIN, MF_UNCHECKED);
  403.                     }
  404.                     else
  405.                     {
  406.                         gSpinFlag = 1;
  407.                         CheckMenuItem(hMenu, MENU_SPIN, MF_CHECKED);
  408.                     }
  409.                     break;
  410.  
  411.                 case MENU_DISPERSED8x8:
  412.                 case MENU_DISPERSED4x4:
  413.                 case MENU_CLUSTERED4x4:
  414.                     hMenu = GetMenu(hwnd);
  415.  
  416.                     //*** Uncheck the current selection
  417.                     CheckMenuItem(hMenu, MENU_DISPERSED8x8 + DitherType,
  418.                         MF_UNCHECKED);
  419.  
  420.                     //*** Get the new selection and check it
  421.                     DitherType = wParam - MENU_DISPERSED8x8;
  422.                     CheckMenuItem(hMenu, wParam, MF_CHECKED);
  423.  
  424.                     //*** Redraw
  425.                     InvalidateRect(hwnd, 0, FALSE);
  426.                     UpdateWindow(hwnd);
  427.                     break;
  428.             }
  429.             return 0L;
  430.  
  431.         case WM_DESTROY:
  432.             //*** Clean up before leaving
  433.             if (hpalApp)
  434.                 DeleteObject(hpalApp);
  435.             if (hdcWinG)
  436.             {
  437.                 SelectObject(hdcWinG,OldBitmap);
  438.                 DeleteObject(WinGBitmap);
  439.                 DeleteDC(hdcWinG);
  440.             }
  441.  
  442.             PostQuitMessage(0);
  443.             break;
  444.  
  445.         case WM_LBUTTONDOWN:
  446.             //*** Get the start location for mouse rotations
  447.             LastX = LOWORD(lParam);
  448.             LastY = HIWORD(lParam);
  449.             break;
  450.  
  451.         case WM_MOUSEMOVE:
  452.             //*** While the mouse button is down, keep track of movement
  453.             //*** to update the eye position on AppPaint.
  454.             if(GetKeyState(VK_LBUTTON) < 0)
  455.             {
  456.                 int X = LOWORD(lParam);
  457.                 int Y = HIWORD(lParam);
  458.  
  459.                 YMove = X - LastX;
  460.                 XMove = Y - LastY;
  461.  
  462.                 LastX = X;
  463.                 LastY = Y;
  464.  
  465.                 InvalidateRect(hwnd, 0, FALSE);
  466.                 UpdateWindow(hwnd);
  467.             }
  468.             break;
  469.  
  470.         case WM_PALETTECHANGED:
  471.             if ((HWND)wParam == hwnd)
  472.                 break;
  473.             //*** Else fall through to WM_QUERYNEWPALETTE
  474.  
  475.         case WM_QUERYNEWPALETTE:
  476.             hdc = GetDC(hwnd);
  477.             if (hpalApp)
  478.                 SelectPalette(hdc, hpalApp, FALSE);
  479.             f = RealizePalette(hdc);
  480.             ReleaseDC(hwnd,hdc);
  481.  
  482.             if (f)
  483.                 InvalidateRect(hwnd, 0, FALSE);
  484.             return f;
  485.  
  486.          case WM_PAINT:
  487.             hdc = BeginPaint(hwnd,&ps);
  488.  
  489.             if (hpalApp)
  490.             {
  491.                 SelectPalette(hdc, hpalApp, FALSE);
  492.                 RealizePalette(hdc);
  493.             }
  494.             AppPaint (hwnd, hdc);
  495.  
  496.             EndPaint(hwnd,&ps);
  497.             return 0L;
  498.  
  499.         case WM_SIZE:
  500.             if (wParam != SIZE_MINIMIZED)
  501.             {
  502.                 //*** Create a WinGBitmap for the buffer that fills the client area
  503.                 if (WinGBitmap)
  504.                 {
  505.                     SelectObject(hdcWinG,OldBitmap);
  506.                     DeleteObject(WinGBitmap);
  507.                 }
  508.                 RECT rect;
  509.                 GetClientRect(hwnd, &rect);
  510.  
  511.                 HeaderAndPalette.Header.biWidth = rect.right;
  512.                 HeaderAndPalette.Header.biHeight = rect.bottom;
  513.  
  514.                 WinGBitmap = WinGCreateBitmap(hdcWinG,
  515.                     (BITMAPINFO far *)&HeaderAndPalette,0);
  516.  
  517.                 OldBitmap = SelectBitmap(hdcWinG,WinGBitmap);
  518.                 DibWidth = rect.right;
  519.                 DibHeight = rect.bottom;
  520.             }
  521.  
  522.             //*** Select a null pen so the polygons aren't outlined
  523.             if (hdcWinG)
  524.                 SelectPen(hdcWinG, GetStockObject(NULL_PEN));
  525.             break;
  526.     }
  527.  
  528.     return DefWindowProc(hwnd,msg,wParam,lParam);
  529. }
  530.  
  531. /**************************************************************************
  532.     TransformCube
  533.  
  534.     Description:
  535.         Transforms the cube vertices by the current rotation matrix.
  536.         Recalculates normals and flat shade values for the
  537.     directional light source.
  538.  **************************************************************************/
  539.  
  540. void TransformCube(matrix_4x4 const &Transform)
  541. {
  542.     int i;
  543.  
  544.     //*** Transform the cube by the matrix
  545.     for (i = 0; i < 8; ++i)
  546.         CubeVertices[i] = Transform * CubeVertices[i];
  547.  
  548.     //*** Recalculate normals and shades
  549.     for (i = 0; i < 6; ++i)
  550.     {
  551.         //*** Normals are perpendicular to two edges of the cube
  552.         vector_4 Edge1, Edge2;
  553.         Edge1 = CubeVertices[CubeFaces[i][1]] - CubeVertices[CubeFaces[i][0]];
  554.         Edge2 = CubeVertices[CubeFaces[i][3]] - CubeVertices[CubeFaces[i][0]];
  555.         CubeSurfaceNormals[i] = CrossProduct(Edge1, Edge2);
  556.         CubeSurfaceNormals[i].Normalize();
  557.  
  558.         //*** Cosine shading based on the surface normal, clamped to [0, 1]
  559.         real Shade = DotProduct(CubeSurfaceNormals[i], LightSourceDirection);
  560.         Shade = Shade + AmbientLight;
  561.         if (Shade < 0) Shade = 0;
  562.         else if (Shade > 1.0) Shade = 1.0;
  563.         CubeSurfaceShades[i] = Shade;
  564.     }
  565. }
  566.  
  567. /**************************************************************************
  568.     ProjectAndDrawCube
  569.  
  570.     Description:
  571.         Projects the cube vertices for the current viewpoint then culls
  572.     in screen space and draws into the DC. In this case, the DC is a DIBDC.
  573.  **************************************************************************/
  574.  
  575. void ProjectAndDrawCube(HDC hdc, int XOffset, int YOffset)
  576. {
  577.     //*** Create a viewing transform for the current eye position
  578.     vector_4 ViewDirection = Origin - Viewpoint;
  579.     ViewDirection.Normalize();
  580.     view_transform View(Viewpoint, ViewDirection, Up);
  581.  
  582.     //*** Transform and project the vertices into screen space
  583.     int i;
  584.     POINT aScreenVertices[8];
  585.     for (i = 0; i < 8; ++i)
  586.     {
  587.         point_4 Temp = View * CubeVertices[i];
  588.         Temp = ViewPerspective * Temp;
  589.         Temp.Homogenize();
  590.  
  591.         aScreenVertices[i].x = (int)Temp.GetX() + XOffset;
  592.         aScreenVertices[i].y = (int)Temp.GetY() + YOffset;
  593.     }
  594.  
  595.     for (i = 0; i < 6; ++i)
  596.     {
  597.         //*** Standard culling operation based on the z value of the
  598.         //*** cross product of the edges: are the vertices oriented in the
  599.          //*** counterclockwise or clockwise direction?
  600.         real v1 = aScreenVertices[ CubeFaces[i][2] ].x -
  601.             aScreenVertices[ CubeFaces[i][1] ].x;
  602.         real w1 = aScreenVertices[ CubeFaces[i][0] ].x -
  603.             aScreenVertices[ CubeFaces[i][1] ].x;
  604.         real v2 = aScreenVertices[ CubeFaces[i][2] ].y -
  605.             aScreenVertices[ CubeFaces[i][1] ].y;
  606.         real w2 = aScreenVertices[ CubeFaces[i][0] ].y -
  607.             aScreenVertices[ CubeFaces[i][1] ].y;
  608.         if ((v1*w2 - v2*w1) <= 0)
  609.             continue;
  610.  
  611.         //*** Get a brush for the shaded face color using the selected dither
  612.         COLORREF cr = RGB( (real)CubeColors[i][0] * CubeSurfaceShades[i],
  613.             (real)CubeColors[i][1] * CubeSurfaceShades[i],
  614.             (real)CubeColors[i][2] * CubeSurfaceShades[i] );
  615.         HBRUSH hbr;
  616.         static WING_DITHER_TYPE DitherTypeList[3] =
  617.             { WING_DISPERSED_8x8, WING_DISPERSED_4x4, WING_CLUSTERED_4x4 };
  618.         hbr = WinGCreateHalftoneBrush(hdcWinG,cr,DitherTypeList[DitherType]);
  619.  
  620.         //*** Collect the correct points in an array
  621.         POINT aQuadVertices[4];
  622.         for (int j = 0; j < 4; ++j)
  623.             aQuadVertices[j] = aScreenVertices[ CubeFaces[i][j] ];
  624.  
  625.         //*** Use GDI to draw the face
  626.         hbr = SelectBrush(hdc, hbr);
  627.         Polygon(hdc, aQuadVertices, 4);
  628.         hbr = SelectBrush(hdc, hbr);
  629.         DeleteObject(hbr);
  630.     }
  631. }
  632.