home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 July & August / Pcwk78a98.iso / System / WING / CUBE.CP_ / CUBE.CP
Text File  |  1995-06-20  |  19KB  |  679 lines

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