home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / directx / d3dex2 / d3dex2.c next >
Encoding:
C/C++ Source or Header  |  1997-07-15  |  72.7 KB  |  2,399 lines

  1. /***********************************************************************
  2.  *
  3.  * File :       d3dex1.c
  4.  *
  5.  * Abstract :   A very simple Direct3D example which simply draws a
  6.  *              single, rotating, Gouraud shaded triangle in a fixed
  7.  *              size window.
  8.  *
  9.  *              For code clarity a number of issues have not been
  10.  *              addressed in this sample. For example, full screen
  11.  *              operation, resizing the window, texture mapping are
  12.  *              not included. Furthermore, certain optimizations have
  13.  *              not been included where they would obfuscate the code.
  14.  *              Every attempt has been made to highlight these areas
  15.  *              will extensive comments.
  16.  *
  17.  * Author :     Colin D. C. McCartney
  18.  *
  19.  * Date :       09/04/96
  20.  *
  21.  * Version :    V1.0
  22.  *
  23.  * To do:
  24.  * - Handle DDERR_WRONGMODE
  25.  *
  26.  *  Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
  27.  ***********************************************************************/
  28.  
  29. /***********************************************************************
  30.  *
  31.  * Include files
  32.  *
  33.  ***********************************************************************/
  34.  
  35. #define  INITGUID
  36. #include <windows.h>
  37. #include <math.h>
  38. #include <assert.h>
  39. #include <ddraw.h>
  40. #include <d3d.h>
  41.  
  42. #include "nowarn.h"
  43. #include "resource.h"
  44.  
  45. // Multi-monitor support
  46. // Include this header file which has helper functions 
  47. // which help us use get the right DirectDraw object for
  48. // the monitor(s) that we want to display on.
  49. #include "ddmm.h"
  50.  
  51. #ifdef DEBUG
  52. // Make it possible to get reasonable symbols for crummy debuggers
  53. #define static 
  54. #endif
  55.  
  56.  
  57.  /***********************************************************************
  58.  *
  59.  * Constants
  60.  *
  61.  ***********************************************************************/
  62.  
  63. /*
  64.  * Class name for this application's window class.
  65.  */
  66. #define WINDOW_CLASSNAME      "D3DSample1Class"
  67.  
  68. /*
  69.  * Title for the application's window.
  70.  */
  71. #define WINDOW_TITLE          "D3D Sample 1"
  72.  
  73. /*
  74.  * String to be displayed when the application is paused.
  75.  */
  76. #define PAUSED_STRING         "Paused"
  77.  
  78. /*
  79.  * Half height of the view window.
  80.  */
  81. #define HALF_HEIGHT           D3DVAL(0.5)
  82.  
  83. /*
  84.  * Front and back clipping planes.
  85.  */
  86. #define FRONT_CLIP            D3DVAL(1.0)
  87. #define BACK_CLIP             D3DVAL(1000.0)
  88.  
  89. /*
  90.  * Fixed window size.
  91.  */
  92. #define WINDOW_WIDTH          320
  93. #define WINDOW_HEIGHT         200
  94.  
  95. /*
  96.  * Maximum length of the chosen device name and description of the
  97.  * chosen Direct3D device.
  98.  */
  99. #define MAX_DEVICE_NAME       256
  100. #define MAX_DEVICE_DESC       256
  101.  
  102. /*
  103.  * Amount to rotate per frame.
  104.  */
  105. #define M_PI                  3.14159265359
  106. #define M_2PI                 6.28318530718
  107. #define ROTATE_ANGLE_DELTA    (M_2PI / 300.0)
  108.  
  109. /*
  110.  * Execute buffer contents
  111.  */
  112. #define NUM_VERTICES          3UL
  113. #define NUM_INSTRUCTIONS      6UL
  114. #define NUM_STATES            8UL
  115. #define NUM_PROCESSVERTICES   1UL
  116. #define NUM_TRIANGLES         1UL
  117.  
  118. /***********************************************************************
  119.  *
  120.  * Macro funtions.
  121.  *
  122.  ***********************************************************************/
  123.  
  124. /*
  125.  * Extract the error code from an HRESULT
  126.  */
  127. #define CODEFROMHRESULT(hRes) ((hRes) & 0x0000FFFFUL)
  128.  
  129. /***********************************************************************
  130.  *
  131.  * Global store
  132.  *
  133.  ***********************************************************************/
  134.  
  135. /*
  136.  * Application instance handle (set in WinMain).
  137.  */
  138. static HINSTANCE               hAppInstance              = NULL;
  139.  
  140. /*
  141.  * Running in debug mode?
  142.  */
  143. static BOOL                    fDebug                    = FALSE;
  144.  
  145. /*
  146.  * Is the app. active?
  147.  */
  148. static BOOL                    fActive                   = TRUE;
  149.  
  150. /*
  151.  * Has the app. been suspended?
  152.  */
  153. static BOOL                    fSuspended                = FALSE;
  154.  
  155. /*
  156.  * DirectDraw interfaces
  157.  */
  158. static LPDIRECTDRAW            lpdd                      = NULL;
  159. static LPDIRECTDRAWSURFACE     lpddPrimary               = NULL;
  160. static LPDIRECTDRAWSURFACE     lpddDevice                = NULL;
  161. static LPDIRECTDRAWSURFACE     lpddZBuffer               = NULL;
  162. static LPDIRECTDRAWPALETTE     lpddPalette               = NULL;
  163.  
  164. /*
  165.  * Direct3D interfaces
  166.  */
  167. static LPDIRECT3D              lpd3d                     = NULL;
  168. static LPDIRECT3DDEVICE        lpd3dDevice               = NULL;
  169. static LPDIRECT3DMATERIAL      lpd3dMaterial             = NULL;
  170. static LPDIRECT3DMATERIAL      lpd3dBackgroundMaterial   = NULL;
  171. static LPDIRECT3DVIEWPORT      lpd3dViewport             = NULL;
  172. static LPDIRECT3DLIGHT         lpd3dLight                = NULL;
  173. static LPDIRECT3DEXECUTEBUFFER lpd3dExecuteBuffer        = NULL;
  174.  
  175. /*
  176.  * Direct3D handles
  177.  */
  178. static D3DMATRIXHANDLE         hd3dWorldMatrix           = 0UL;
  179. static D3DMATRIXHANDLE         hd3dViewMatrix            = 0UL;
  180. static D3DMATRIXHANDLE         hd3dProjMatrix            = 0UL;
  181. static D3DMATERIALHANDLE       hd3dSurfaceMaterial       = 0UL;
  182. static D3DMATERIALHANDLE       hd3dBackgroundMaterial    = 0UL;
  183.  
  184. /*
  185.  * Globals used for selecting the Direct3D device. They are
  186.  * globals as it makes it easy for the enumeration callback
  187.  * to read and write from them.
  188.  */
  189. static BOOL                    fDeviceFound              = FALSE;
  190. static DWORD                   dwDeviceBitDepth          = 0UL;
  191. static GUID                    guidDevice;
  192. static char                    szDeviceName[MAX_DEVICE_NAME];
  193. static char                    szDeviceDesc[MAX_DEVICE_DESC];
  194. static D3DDEVICEDESC           d3dHWDeviceDesc;
  195. static D3DDEVICEDESC           d3dSWDeviceDesc;
  196.  
  197. /*
  198.  * The screen coordinates of the client area of the window. This
  199.  * rectangle defines the destination into which we blit to update
  200.  * the client area of the window with the results of the 3D rendering.
  201.  */
  202. static RECT                    rDstRect;
  203.  
  204. /*
  205.  * This rectangle defines the portion of the rendering target surface
  206.  * into which we render. The top left coordinates of this rectangle
  207.  * are always zero and the right and bottom give the size of the
  208.  * viewport.
  209.  */
  210. static RECT                    rSrcRect = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
  211.  
  212. /*
  213.  * Angle of rotation of the world matrix.
  214.  */
  215. static double                  dAngleOfRotation          = 0.0;
  216.  
  217. /*
  218.  * Predefined transformations.
  219.  */
  220. static D3DMATRIX d3dWorldMatrix =
  221. {
  222.     D3DVAL( 1.0), D3DVAL( 0.0), D3DVAL( 0.0), D3DVAL( 0.0),
  223.     D3DVAL( 0.0), D3DVAL( 1.0), D3DVAL( 0.0), D3DVAL( 0.0),
  224.     D3DVAL( 0.0), D3DVAL( 0.0), D3DVAL( 1.0), D3DVAL( 0.0),
  225.     D3DVAL( 0.0), D3DVAL( 0.0), D3DVAL( 0.0), D3DVAL( 1.0)
  226. };
  227.  
  228. static D3DMATRIX d3dViewMatrix =
  229. {
  230.     D3DVAL( 1.0), D3DVAL( 0.0), D3DVAL( 0.0), D3DVAL( 0.0),
  231.     D3DVAL( 0.0), D3DVAL( 1.0), D3DVAL( 0.0), D3DVAL( 0.0),
  232.     D3DVAL( 0.0), D3DVAL( 0.0), D3DVAL( 1.0), D3DVAL( 0.0),
  233.     D3DVAL( 0.0), D3DVAL( 0.0), D3DVAL( 5.0), D3DVAL( 1.0)
  234. };
  235.  
  236. static D3DMATRIX d3dProjMatrix =
  237. {
  238.     D3DVAL( 2.0), D3DVAL( 0.0), D3DVAL( 0.0), D3DVAL( 0.0),
  239.     D3DVAL( 0.0), D3DVAL( 2.0), D3DVAL( 0.0), D3DVAL( 0.0),
  240.     D3DVAL( 0.0), D3DVAL( 0.0), D3DVAL( 1.0), D3DVAL( 1.0),
  241.     D3DVAL( 0.0), D3DVAL( 0.0), D3DVAL(-1.0), D3DVAL( 0.0)
  242. };
  243.  
  244. // Multimonitor globals
  245. int     hMonitor;
  246. char    szMonitor[128];
  247. RECT    rectMonitor;
  248.  
  249.  
  250. /***********************************************************************
  251.  *
  252.  * Function prototypes
  253.  *
  254.  ***********************************************************************/
  255.  
  256. static void           ReportError(HWND hwnd, int nMessage, HRESULT hRes);
  257. static void           FatalError(HWND hwnd, int nMessage, HRESULT hRes);
  258.  
  259. static DWORD          BitDepthToFlags(DWORD dwBitDepth);
  260. static DWORD          FlagsToBitDepth(DWORD dwFlags);
  261.  
  262. static void           SetPerspectiveProjection(LPD3DMATRIX lpd3dMatrix,
  263.                                                double      dHalfHeight,
  264.                                                double      dFrontClipping,
  265.                                                double      dBackClipping);
  266. static void           SetRotationAboutY(LPD3DMATRIX lpd3dMatrix,
  267.                                         double      dAngleOfRotation);
  268.  
  269. static HRESULT        CreateDirect3D(HWND hwnd);
  270. static HRESULT        ReleaseDirect3D(void);
  271.  
  272. static HRESULT        CreatePrimary(HWND hwnd);
  273. static HRESULT        RestorePrimary(void);
  274. static HRESULT        ReleasePrimary(void);
  275.  
  276. static HRESULT WINAPI EnumDeviceCallback(LPGUID          lpGUID, 
  277.                                          LPSTR           lpszDeviceDesc,
  278.                                          LPSTR           lpszDeviceName,
  279.                                          LPD3DDEVICEDESC lpd3dHWDeviceDesc,
  280.                                          LPD3DDEVICEDESC lpd3dSWDeviceDesc,
  281.                                          LPVOID          lpUserArg);
  282. static HRESULT        ChooseDevice(void);
  283.  
  284. static HRESULT        CreateDevice(DWORD dwWidth, DWORD dwHeight);
  285. static HRESULT        RestoreDevice(void);
  286. static HRESULT        ReleaseDevice(void);
  287.  
  288. static LRESULT        RestoreSurfaces(void);
  289.  
  290. static HRESULT        FillExecuteBuffer(void);
  291. static HRESULT        CreateScene(void);
  292. static HRESULT        ReleaseScene(void);
  293. static HRESULT        AnimateScene(void);
  294.  
  295. static HRESULT        UpdateViewport(void);
  296.  
  297. static HRESULT        RenderScene(void);
  298. static HRESULT        DoFrame(HWND hwnd);
  299. static void           PaintSuspended(HWND hwnd, HDC hdc);
  300.  
  301. static LRESULT        OnMove(HWND hwnd, int x, int y);
  302. static LRESULT        OnSize(HWND hwnd, int w, int h);
  303. static LRESULT        OnPaint(HWND hwnd, HDC hdc, LPPAINTSTRUCT lpps);
  304. static LRESULT        OnIdle(HWND hwnd);
  305.  
  306. // Multimonitor 
  307. static HRESULT          CheckMonitors(HWND hwnd, BOOL fReset);
  308.  
  309. LRESULT CALLBACK      WndProc(HWND hwnd, UINT msg,
  310.                               WPARAM wParam, LPARAM lParam);
  311. int PASCAL            WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  312.                               LPSTR lpszCommandLine, int cmdShow);
  313.  
  314. /***********************************************************************
  315.  *
  316.  * Macro functions
  317.  *
  318.  ***********************************************************************/
  319.  
  320. /***********************************************************************/
  321.  
  322. #ifdef _DEBUG
  323. #define ASSERT(x)       assert(x)
  324. #else
  325. #define ASSERT(x)
  326. #endif
  327.  
  328. /***********************************************************************/
  329.  
  330. /*
  331.  * Used to keep the compiler happy about any unused parameters.
  332.  */
  333. #define USE_PARAM(x)    (x) = (x)
  334.  
  335. /***********************************************************************/
  336.  
  337. /***********************************************************************
  338.  *
  339.  * Functions
  340.  *
  341.  ***********************************************************************/
  342.  
  343. /***********************************************************************/
  344.  
  345. /*
  346.  * Report the given error by display a message box.
  347.  */
  348. static void
  349. ReportError(HWND hwnd, int nMessage, HRESULT hRes)
  350. {
  351.     HDC  hdc;
  352.     char szBuffer[256];
  353.     char szMessage[128];
  354.     char szError[128];
  355.     int  nStrID;
  356.  
  357.     /*
  358.      * Turn the animation loop off.
  359.      */
  360.     fSuspended = TRUE;
  361.  
  362.     /*
  363.      * Get the high level error message.
  364.      */
  365.     LoadString(hAppInstance, nMessage, szMessage, sizeof(szMessage));
  366.  
  367.     /*
  368.      * We issue sensible error messages for common run time errors. For
  369.      * errors which are internal or coding errors we simply issue an
  370.      * error number (they should never occur).
  371.      */
  372.     switch (hRes)
  373.     {
  374.         case DDERR_EXCEPTION:        nStrID = IDS_ERR_EXCEPTION;        break;
  375.         case DDERR_GENERIC:          nStrID = IDS_ERR_GENERIC;          break;
  376.         case DDERR_OUTOFMEMORY:      nStrID = IDS_ERR_OUTOFMEMORY;      break;
  377.         case DDERR_OUTOFVIDEOMEMORY: nStrID = IDS_ERR_OUTOFVIDEOMEMORY; break;
  378.         case DDERR_SURFACEBUSY:      nStrID = IDS_ERR_SURFACEBUSY;      break;
  379.         case DDERR_SURFACELOST:      nStrID = IDS_ERR_SURFACELOST;      break;
  380.         case DDERR_WRONGMODE:        nStrID = IDS_ERR_WRONGMODE;        break;
  381.         default:                     nStrID = IDS_ERR_INTERNALERROR;    break;
  382.     }
  383.     LoadString(hAppInstance, nStrID, szError, sizeof(szError));
  384.  
  385.     /*
  386.      * Show the "paused" display.
  387.      */
  388.     hdc = GetDC(hwnd);
  389.     PaintSuspended(hwnd, hdc);
  390.     ReleaseDC(hwnd, hdc);
  391.  
  392.     /*
  393.      * Convert the error code into a string (not very informative but
  394.      * it keeps the code simple).
  395.      */
  396.     wsprintf(szBuffer, "%s\n%s (Error #%d)", szMessage, szError, CODEFROMHRESULT(hRes));
  397.     MessageBox(hwnd, szBuffer, WINDOW_TITLE, MB_OK | MB_APPLMODAL);
  398.     fSuspended = FALSE;
  399. }
  400.  
  401. /***********************************************************************/
  402.  
  403. /*
  404.  * Handle a fatal error. Displays the error message via a message box
  405.  * and then destroys the window.
  406.  */
  407. static void
  408. FatalError(HWND hwnd, int nMessage, HRESULT hRes)
  409. {
  410.     /*
  411.      * Report the error.
  412.      */
  413.     ReportError(hwnd, nMessage, hRes);
  414.     fSuspended = TRUE;
  415.  
  416.     /*
  417.      * And shut down.
  418.      *
  419.      * NOTE: We don't attempt to clean up. That will be done
  420.      * when WM_DESTROY happens.
  421.      */
  422.     DestroyWindow(hwnd);
  423. }
  424.  
  425. /***********************************************************************/
  426.  
  427. /*
  428.  * Converts a bit depth into the appropriate DirectDraw bit depth flag.
  429.  */
  430. static DWORD
  431. BitDepthToFlags(DWORD dwBitDepth)
  432. {
  433.     switch (dwBitDepth)
  434.     {
  435.         case  1UL: return DDBD_1;
  436.         case  2UL: return DDBD_2;
  437.         case  4UL: return DDBD_4;
  438.         case  8UL: return DDBD_8;
  439.         case 16UL: return DDBD_16;
  440.         case 24UL: return DDBD_24;
  441.         case 32UL: return DDBD_32;
  442.         default:   return 0UL;     /* Oh, please... */
  443.     }
  444. }
  445.  
  446. /***********************************************************************/
  447.  
  448. /*
  449.  * Convert bit depth flags to an acutal bit count. Selects the smallest
  450.  * bit count in the mask if more than one flag is present.
  451.  */
  452. static DWORD
  453. FlagsToBitDepth(DWORD dwFlags)
  454. {
  455.     if (dwFlags & DDBD_1)
  456.         return 1UL;
  457.     else if (dwFlags & DDBD_2)
  458.         return 2UL;
  459.     else if (dwFlags & DDBD_4)
  460.         return 4UL;
  461.     else if (dwFlags & DDBD_8)
  462.         return 8UL;
  463.     else if (dwFlags & DDBD_16)
  464.         return 16UL;
  465.     else if (dwFlags & DDBD_24)
  466.         return 24UL;
  467.     else if (dwFlags & DDBD_32)
  468.         return 32UL;
  469.     else
  470.         return 0UL; /* Oh, please... */
  471. }
  472.  
  473. /***********************************************************************/
  474.  
  475. /*
  476.  * Set the given matrix to a perspective transform for the given half
  477.  * height and front and back clipping planes.
  478.  */
  479. static void
  480. SetPerspectiveProjection(LPD3DMATRIX lpd3dMatrix,
  481.                          double      dHalfHeight,
  482.                          double      dFrontClipping,
  483.                          double      dBackClipping)
  484. {
  485.     double dTmp1;
  486.     double dTmp2;
  487.  
  488.     ASSERT(NULL != lpd3dMatrix);
  489.  
  490.     dTmp1 = dHalfHeight / dFrontClipping;
  491.     dTmp2 = dBackClipping / (dBackClipping - dFrontClipping);
  492.  
  493.     lpd3dMatrix->_11 =  D3DVAL(2.0);
  494.     lpd3dMatrix->_12 =  D3DVAL(0.0);
  495.     lpd3dMatrix->_13 =  D3DVAL(0.0);
  496.     lpd3dMatrix->_14 =  D3DVAL(0.0);
  497.     lpd3dMatrix->_21 =  D3DVAL(0.0);
  498.     lpd3dMatrix->_22 =  D3DVAL(2.0);
  499.     lpd3dMatrix->_23 =  D3DVAL(0.0);
  500.     lpd3dMatrix->_24 =  D3DVAL(0.0);
  501.     lpd3dMatrix->_31 =  D3DVAL(0.0);
  502.     lpd3dMatrix->_32 =  D3DVAL(0.0);
  503.     lpd3dMatrix->_33 =  D3DVAL(dTmp1 * dTmp2);
  504.     lpd3dMatrix->_34 =  D3DVAL(dTmp1);
  505.     lpd3dMatrix->_41 =  D3DVAL(0.0);
  506.     lpd3dMatrix->_42 =  D3DVAL(0.0);
  507.     lpd3dMatrix->_43 =  D3DVAL(-dHalfHeight * dTmp2);
  508.     lpd3dMatrix->_44 =  D3DVAL(0.0);
  509. }
  510.  
  511.  
  512. /***********************************************************************/
  513.  
  514. /*
  515.  * Set the given matrix to a rotation about Y transform of the given
  516.  * number of radians.
  517.  */
  518. static void
  519. SetRotationAboutY(LPD3DMATRIX lpd3dMatrix, double dAngleOfRotation)
  520. {
  521.     D3DVALUE dvCos;
  522.     D3DVALUE dvSin;
  523.  
  524.     ASSERT(NULL != lpd3dMatrix);
  525.  
  526.     dvCos = D3DVAL(cos(dAngleOfRotation));
  527.     dvSin = D3DVAL(sin(dAngleOfRotation));
  528.  
  529.     lpd3dMatrix->_11 =  dvCos;
  530.     lpd3dMatrix->_12 =  D3DVAL(0.0);
  531.     lpd3dMatrix->_13 = -dvSin;
  532.     lpd3dMatrix->_14 =  D3DVAL(0.0);
  533.     lpd3dMatrix->_21 =  D3DVAL(0.0);
  534.     lpd3dMatrix->_22 =  D3DVAL(1.0);
  535.     lpd3dMatrix->_23 =  D3DVAL(0.0);
  536.     lpd3dMatrix->_24 =  D3DVAL(0.0);
  537.     lpd3dMatrix->_31 =  dvSin;
  538.     lpd3dMatrix->_32 =  D3DVAL(0.0);
  539.     lpd3dMatrix->_33 =  dvCos;
  540.     lpd3dMatrix->_34 =  D3DVAL(0.0);
  541.     lpd3dMatrix->_41 =  D3DVAL(0.0);
  542.     lpd3dMatrix->_42 =  D3DVAL(0.0);
  543.     lpd3dMatrix->_43 =  D3DVAL(0.0);
  544.     lpd3dMatrix->_44 =  D3DVAL(1.0);
  545. }
  546.  
  547. /***********************************************************************/
  548.  
  549. /*
  550.  * Create the DirectDraw/3D driver object and get DirectDraw and Direct3D
  551.  * interfaces for communicating with that object.
  552.  */
  553. static HRESULT
  554. CreateDirect3D(HWND hwnd)
  555. {
  556.     HRESULT hRes;
  557.  
  558.     ASSERT(NULL == lpdd);
  559.     ASSERT(NULL == lpd3d);
  560.  
  561.     /*
  562.      * Create the DirectDraw/3D driver object and get the DirectDraw
  563.      * interface to that object.
  564.      */
  565.     lpdd = DirectDrawCreateFromWindow(hwnd);
  566.     if (lpdd == NULL)
  567.         return E_FAIL;
  568.  
  569.     /*
  570.      * As we are running in a window set the cooperative level to 
  571.      * normal. Also, to ensure that the palette is realized correctly
  572.      * we need to pass the hwnd of the main window.
  573.      */
  574.     hRes = lpdd->lpVtbl->SetCooperativeLevel(lpdd, hwnd, DDSCL_NORMAL);
  575.     if (FAILED(hRes))
  576.         return hRes;
  577.  
  578.     /*
  579.      * Get the Direct3D interface to the DirectDraw/3D driver object.
  580.      */
  581.     hRes = lpdd->lpVtbl->QueryInterface(lpdd, &IID_IDirect3D, &lpd3d);
  582.     if (FAILED(hRes))
  583.         return hRes;
  584.  
  585.     return DD_OK;
  586. }
  587.  
  588. /***********************************************************************/
  589.  
  590. /*
  591.  * Release the DirectDraw/3D driver object.
  592.  */
  593. static HRESULT
  594. ReleaseDirect3D(void)
  595. {
  596.     if (NULL != lpd3d)
  597.     {
  598.         lpd3d->lpVtbl->Release(lpd3d);
  599.         lpd3d = NULL;
  600.     }
  601.     if (NULL != lpdd)
  602.     {
  603.         lpdd->lpVtbl->Release(lpdd);
  604.         lpdd = NULL;
  605.     }
  606.  
  607.     return DD_OK;
  608. }
  609.  
  610. /***********************************************************************/
  611.  
  612. /*
  613.  * Create the primary surface (representing the desktop) and create and
  614.  * attach a clipper and, if necessary, a palette.
  615.  */
  616. static HRESULT
  617. CreatePrimary(HWND hwnd)
  618. {
  619.     HRESULT             hRes;
  620.     DDSURFACEDESC       ddsd;
  621.     LPDIRECTDRAWCLIPPER lpddClipper;
  622.     HDC                 hdc;
  623.     int                 i;
  624.     PALETTEENTRY        peColorTable[256];
  625.  
  626.     ASSERT(NULL != hwnd);
  627.     ASSERT(NULL != lpdd);
  628.     ASSERT(NULL == lpddPrimary);
  629.     ASSERT(NULL == lpddPalette);
  630.  
  631.     /*
  632.      * Create the primary surface.
  633.      */
  634.     ZeroMemory(&ddsd, sizeof(ddsd));
  635.     ddsd.dwSize         = sizeof(ddsd);
  636.     ddsd.dwFlags        = DDSD_CAPS;
  637.     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  638.     hRes = lpdd->lpVtbl->CreateSurface(lpdd, &ddsd, &lpddPrimary, NULL);
  639.     if (FAILED(hRes))
  640.         return hRes;
  641.  
  642.     /*
  643.      * Create the clipper. We bind the application's window to the
  644.      * clipper and attach it to the primary. This ensures then when we
  645.      * blit from the rendering surface to the primary we don't write
  646.      * outside the visible region of the window.
  647.      */
  648.     hRes = DirectDrawCreateClipper(0UL, &lpddClipper, NULL);
  649.     if (FAILED(hRes))
  650.         return hRes;
  651.     hRes = lpddClipper->lpVtbl->SetHWnd(lpddClipper, 0UL, hwnd);
  652.     if (FAILED(hRes))
  653.     {
  654.         lpddClipper->lpVtbl->Release(lpddClipper);
  655.         return hRes;
  656.     }
  657.     hRes = lpddPrimary->lpVtbl->SetClipper(lpddPrimary, lpddClipper);
  658.     if (FAILED(hRes))
  659.     {
  660.         lpddClipper->lpVtbl->Release(lpddClipper);
  661.         return hRes;
  662.     }
  663.  
  664.     /*
  665.      * We release the clipper interface after attaching it to the surface
  666.      * as we don't need to use it again. The surface holds a reference to
  667.      * the clipper when its been attached. The clipper will therefore be
  668.      * released when the surface is released.
  669.      */
  670.     lpddClipper->lpVtbl->Release(lpddClipper);
  671.  
  672.     /*
  673.      * If the primary is palettized then so will the device (the device
  674.      * surface must have the same pixel format as the current primary if
  675.      * we want to double buffer with DirectDraw). Hence, if the primary
  676.      * is palettized we need to create a palette and attach it to the
  677.      * primary (and to the device surface when we create it).
  678.      */
  679.     ZeroMemory(&ddsd, sizeof(ddsd));
  680.     ddsd.dwSize = sizeof(ddsd);
  681.     hRes = lpddPrimary->lpVtbl->GetSurfaceDesc(lpddPrimary, &ddsd);
  682.     if (FAILED(hRes))
  683.         return hRes;
  684.     if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
  685.     {
  686.         /*
  687.          * Initializing the palette correctly is essential. We are
  688.          * running in a window so we need to be a good windows app
  689.          * and not mess with the top ten and bottom ten static
  690.          * colors. Therefore, we copy them from the system palette
  691.          * and mark them as read only (D3DPAL_READONLY). The middle
  692.          * 236 entries are free for use by Direct3D so we mark them
  693.          * free (D3DPAL_FREE).
  694.          *
  695.          * NOTE: In order that the palette entries are correctly
  696.          * allocated it is essential that the free entries are
  697.          * also marked reserved to GDI (PC_RESERVED).
  698.          *
  699.          * NOTE: We don't need to specify the palette caps flag
  700.          * DDPCAPS_INITIALIZE. This flag is obsolete. CreatePalette
  701.          * must be given a valid palette entry array and always
  702.          * initializes from it.
  703.          */
  704.         hdc = GetDC(NULL);
  705.         GetSystemPaletteEntries(hdc, 0, 256, peColorTable);
  706.         ReleaseDC(NULL, hdc);
  707.  
  708.         for (i = 0; i < 10; i++)
  709.             peColorTable[i].peFlags = D3DPAL_READONLY;
  710.         for (i = 10; i < 246; i++)
  711.             peColorTable[i].peFlags = D3DPAL_FREE | PC_RESERVED;
  712.         for (i = 246; i < 256; i++)
  713.             peColorTable[i].peFlags = D3DPAL_READONLY;
  714.         hRes = lpdd->lpVtbl->CreatePalette(lpdd,
  715.                                            DDPCAPS_8BIT,
  716.                                            peColorTable,
  717.                                            &lpddPalette,
  718.                                            NULL);
  719.         if (FAILED(hRes))
  720.             return hRes;
  721.  
  722.         hRes = lpddPrimary->lpVtbl->SetPalette(lpddPrimary, lpddPalette);
  723.             return hRes;
  724.     }
  725.  
  726.     return DD_OK;
  727. }
  728.  
  729. /***********************************************************************/
  730.  
  731. /*
  732.  * Attempt to restore the video memory allocated for the primary. This
  733.  * function will be invoked by a DirectX function returning
  734.  * DDERR_SURFACELOST due to a mode switch or fullscreen DOS box
  735.  * invalidating video memory.
  736.  */
  737. static HRESULT
  738. RestorePrimary(void)
  739. {
  740.     ASSERT(NULL != lpddPrimary);
  741.  
  742.     return lpddPrimary->lpVtbl->Restore(lpddPrimary);
  743. }
  744.  
  745. /***********************************************************************/
  746.  
  747. /*
  748.  * Release the primary surface and its attached clipper and palette.
  749.  */
  750. static HRESULT
  751. ReleasePrimary(void)
  752. {
  753.     if (NULL != lpddPalette)
  754.     {
  755.         lpddPalette->lpVtbl->Release(lpddPalette);
  756.         lpddPalette = NULL;
  757.     }
  758.     if (NULL != lpddPrimary)
  759.     {
  760.         lpddPrimary->lpVtbl->Release(lpddPrimary);
  761.         lpddPrimary = NULL;
  762.     }
  763.  
  764.     return DD_OK;
  765. }
  766.  
  767. /***********************************************************************/
  768.  
  769. /*
  770.  * This callback is invoked for each Direct3D device installed on the
  771.  * system. For each device we get its identifying GUID, a name and
  772.  * description, a description of its hardware and software capabilities
  773.  * and a user argument (which we don't use).
  774.  */
  775. static HRESULT WINAPI
  776. EnumDeviceCallback(LPGUID          lpGUID, 
  777.                    LPSTR           lpszDeviceDesc,
  778.                    LPSTR           lpszDeviceName,
  779.                    LPD3DDEVICEDESC lpd3dHWDeviceDesc,
  780.                    LPD3DDEVICEDESC lpd3dSWDeviceDesc,
  781.                    LPVOID          lpUserArg)
  782. {
  783.     BOOL            fIsHardware;
  784.     LPD3DDEVICEDESC lpd3dDeviceDesc;
  785.  
  786.     /*
  787.      * We don't use the user argument so just keep the compiler happy.
  788.      */
  789.     USE_PARAM(lpUserArg);
  790.  
  791.     /*
  792.      * If there is no hardware support then the color model is zero.
  793.      */
  794.     fIsHardware     = (0UL != lpd3dHWDeviceDesc->dcmColorModel);
  795.     lpd3dDeviceDesc = (fIsHardware ? lpd3dHWDeviceDesc : lpd3dSWDeviceDesc);
  796.  
  797.     /*
  798.      * If we are in debug mode and this is a hardware device skip it.
  799.      */
  800.     if (fDebug && fIsHardware)
  801.         return D3DENUMRET_OK;
  802.  
  803.     /*
  804.      * Does the device render at the depth we want?
  805.      */
  806.     if (0UL == (lpd3dDeviceDesc->dwDeviceRenderBitDepth & dwDeviceBitDepth))
  807.     {
  808.         /*
  809.          * No skip this device.
  810.          */
  811.         return D3DENUMRET_OK;
  812.     }
  813.  
  814.     /*
  815.      * The device must support gouraud shaded triangles.
  816.      */
  817.     if (D3DCOLOR_MONO == lpd3dDeviceDesc->dcmColorModel)
  818.     {
  819.         if (!(lpd3dDeviceDesc->dpcTriCaps.dwShadeCaps & D3DPSHADECAPS_COLORGOURAUDMONO))
  820.         {
  821.             /*
  822.              * No gouraud shading. Skip this device.
  823.              */
  824.             return D3DENUMRET_OK;
  825.         }
  826.     }
  827.     else
  828.     {
  829.         if (!(lpd3dDeviceDesc->dpcTriCaps.dwShadeCaps & D3DPSHADECAPS_COLORGOURAUDRGB))
  830.         {
  831.             /*
  832.              * No gouraud shading. Skip this device.
  833.              */
  834.             return D3DENUMRET_OK;
  835.         }
  836.     }
  837.  
  838.     if (!fIsHardware && fDeviceFound && (D3DCOLOR_RGB == lpd3dDeviceDesc->dcmColorModel))
  839.     {
  840.         /*
  841.          * If this is software RGB and we already have found a software
  842.          * mono already then we are not interested. Skip it.
  843.          */
  844.         return D3DENUMRET_OK;
  845.     }
  846.  
  847.     /*
  848.      * This is a device we are interested in - cache the details away.
  849.      */
  850.     fDeviceFound = TRUE;
  851.     CopyMemory(&guidDevice, lpGUID, sizeof(GUID));
  852.     strcpy(szDeviceDesc, lpszDeviceDesc);
  853.     strcpy(szDeviceName, lpszDeviceName);
  854.     CopyMemory(&d3dHWDeviceDesc, lpd3dHWDeviceDesc, sizeof(D3DDEVICEDESC));
  855.     CopyMemory(&d3dSWDeviceDesc, lpd3dSWDeviceDesc, sizeof(D3DDEVICEDESC));
  856.  
  857.     /*
  858.      * If this is a hardware device we have found what we are looking
  859.      * for.
  860.      */
  861.     if (fIsHardware)
  862.         return D3DENUMRET_CANCEL;
  863.  
  864.     /*
  865.      * Keep looking...
  866.      */
  867.     return D3DENUMRET_OK;
  868. }
  869.                             
  870. /***********************************************************************/
  871.  
  872. /*
  873.  * Choose an appropriate Direct3D using the following mechanism:
  874.  *
  875.  * 1) Discard any devices which don't match the current display depth.
  876.  * 2) Discard any devices which can't do gouraud shaded triangles.
  877.  * 3) If a hardware device is found which matches 1) and 2) use it.
  878.  *    However, if we are running in debug mode we will skip hardware.
  879.  * 4) Otherwise favour Mono/Ramp mode software renderers over RGB ones
  880.  *    as, at least until MMX is widespread, Mono will be faster.
  881.  *
  882.  * The actual implementation of this mechanism is in the callback
  883.  * function above.
  884.  */
  885. static HRESULT
  886. ChooseDevice(void)
  887. {
  888.     DDSURFACEDESC ddsd;
  889.     HRESULT       hRes;
  890.  
  891.     ASSERT(NULL != lpd3d);
  892.     ASSERT(NULL != lpddPrimary);
  893.  
  894.     /*
  895.      * As we are running in a window we will not be changing the screen
  896.      * depth and hence the pixel format of the rendering target must match
  897.      * the pixel format of the current primary. Therefore, we need to
  898.      * determine the pixel format of the primary.
  899.      */
  900.     ZeroMemory(&ddsd, sizeof(ddsd));
  901.     ddsd.dwSize = sizeof(ddsd);
  902.     hRes = lpddPrimary->lpVtbl->GetSurfaceDesc(lpddPrimary, &ddsd);
  903.     if (FAILED(hRes))
  904.         return hRes;
  905.  
  906.     dwDeviceBitDepth = BitDepthToFlags(ddsd.ddpfPixelFormat.dwRGBBitCount);
  907.  
  908.     /*
  909.      * Enumerate the devices and pick one.
  910.      */
  911.     fDeviceFound = FALSE;
  912.     hRes = lpd3d->lpVtbl->EnumDevices(lpd3d, EnumDeviceCallback, &fDeviceFound);
  913.     if (FAILED(hRes))
  914.         return hRes;
  915.  
  916.     if (!fDeviceFound)
  917.     {
  918.         /*
  919.          * No suitable device was found. We have no alternative but to
  920.          * fail creation entirely.
  921.          */
  922.         return DDERR_NOTFOUND;
  923.     }
  924.  
  925.     return DD_OK;
  926. }
  927.  
  928. /***********************************************************************/
  929.  
  930. /*
  931.  * Create an instance of the Direct3D device we choose earlier with the
  932.  * given width and height.
  933.  *
  934.  * This function handles all aspects of the device creation including
  935.  * choosing surface memory type, create the device surface, the z-buffer
  936.  * (if necessary) and attaching the palette (if required).
  937.  */
  938. static HRESULT
  939. CreateDevice(DWORD dwWidth, DWORD dwHeight)
  940. {
  941.     LPD3DDEVICEDESC lpd3dDeviceDesc;
  942.     DWORD           dwDeviceMemType;
  943.     DWORD           dwZBufferMemType;
  944.     DDSURFACEDESC   ddsd;
  945.     HRESULT         hRes;
  946.     DWORD           dwZBufferBitDepth;
  947.  
  948.     ASSERT(NULL != lpdd);
  949.     ASSERT(NULL != lpd3d);
  950.     ASSERT(NULL != lpddPrimary);
  951.     ASSERT(NULL == lpddDevice);
  952.     ASSERT(NULL == lpd3dDevice);
  953.  
  954.     /*
  955.      * The first step is to determine the kind of memory (system or
  956.      * video) from which the device surface should be allocated.
  957.      */
  958.     if (0UL != d3dHWDeviceDesc.dcmColorModel)
  959.     {
  960.         lpd3dDeviceDesc = &d3dHWDeviceDesc;
  961.  
  962.         /*
  963.          * Device has a hardware rasterizer. Currently this means that
  964.          * the device surface must be in video memory.
  965.          */
  966.         dwDeviceMemType  = DDSCAPS_VIDEOMEMORY;
  967.         dwZBufferMemType = DDSCAPS_VIDEOMEMORY;
  968.     }
  969.     else
  970.     {
  971.         lpd3dDeviceDesc = &d3dSWDeviceDesc;
  972.  
  973.         /*
  974.          * Device has a software rasterizer. We will let DirectDraw
  975.          * decide where the device surface resides unless we are
  976.          * running in debug mode in which case we will force it into
  977.          * system memory. For a software rasterizer the z-buffer should
  978.          * always go into system memory. A z-buffer in video memory will
  979.          * kill performance.
  980.          */
  981.         dwDeviceMemType  = (fDebug ? DDSCAPS_SYSTEMMEMORY : 0UL);
  982.         dwZBufferMemType = DDSCAPS_SYSTEMMEMORY;
  983.     }
  984.  
  985.     /*
  986.      * Create the device surface. The pixel format will be identical
  987.      * to the primary so we don't have to explicitly specify it. We do
  988.      * need to explicity specify the size, memory type and capabilities
  989.      * of the surface.
  990.      */
  991.     ZeroMemory(&ddsd, sizeof(ddsd));
  992.     ddsd.dwSize         = sizeof(ddsd);
  993.     ddsd.dwFlags        = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
  994.     ddsd.dwWidth        = dwWidth;
  995.     ddsd.dwHeight       = dwHeight;
  996.     ddsd.ddsCaps.dwCaps = DDSCAPS_3DDEVICE | DDSCAPS_OFFSCREENPLAIN | dwDeviceMemType;
  997.     hRes = lpdd->lpVtbl->CreateSurface(lpdd, &ddsd, &lpddDevice, NULL);
  998.     if (FAILED(hRes))
  999.         return hRes;
  1000.  
  1001.     /*
  1002.      * If we have created a palette then we have already determined that
  1003.      * the primary (and hence the device surface) is palettized so 
  1004.      * attach the palette to the device surface (its already attached to
  1005.      * the primary).
  1006.      */
  1007.     if (NULL != lpddPalette)
  1008.     {
  1009.         hRes = lpddDevice->lpVtbl->SetPalette(lpddDevice, lpddPalette);
  1010.         if (FAILED(hRes))
  1011.             return hRes;
  1012.     }
  1013.  
  1014.     /*
  1015.      * We now determine whether we need a z-buffer or not and if so
  1016.      * its bit depth. 
  1017.      */
  1018.     if (0UL != lpd3dDeviceDesc->dwDeviceZBufferBitDepth)
  1019.     {
  1020.         /*
  1021.          * The device supports z-buffering. Determine the depth. We
  1022.          * select the lowest supported z-buffer depth to save memory.
  1023.          * Accuracy is not too important for this sample.
  1024.          */
  1025.         dwZBufferBitDepth = FlagsToBitDepth(lpd3dDeviceDesc->dwDeviceZBufferBitDepth);
  1026.  
  1027.         /*
  1028.          * Create the z-buffer.
  1029.          */
  1030.         ZeroMemory(&ddsd, sizeof(ddsd));
  1031.         ddsd.dwSize            = sizeof(ddsd);
  1032.         ddsd.dwFlags           = DDSD_CAPS   |
  1033.                                  DDSD_WIDTH  |
  1034.                                  DDSD_HEIGHT |
  1035.                                  DDSD_ZBUFFERBITDEPTH;
  1036.         ddsd.ddsCaps.dwCaps    = DDSCAPS_ZBUFFER | dwZBufferMemType;
  1037.         ddsd.dwWidth           = dwWidth;
  1038.         ddsd.dwHeight          = dwHeight;
  1039.         ddsd.dwZBufferBitDepth = dwZBufferBitDepth;
  1040.         hRes = lpdd->lpVtbl->CreateSurface(lpdd, &ddsd, &lpddZBuffer, NULL);
  1041.         if (FAILED(hRes))
  1042.             return hRes;
  1043.  
  1044.         /*
  1045.          * Attach it to the rendering target.
  1046.          */
  1047.         hRes = lpddDevice->lpVtbl->AddAttachedSurface(lpddDevice, lpddZBuffer);
  1048.         if (FAILED(hRes))
  1049.             return hRes;
  1050.     }
  1051.  
  1052.     /*
  1053.      * Now all the elements are in place (device surface in correct
  1054.      * memory type, attached z-buffer of correct depth and memory
  1055.      * type, and palette if necessary) we can actually query for the
  1056.      * Direct3D we choose earlier.
  1057.      */
  1058.     hRes = lpddDevice->lpVtbl->QueryInterface(lpddDevice,
  1059.                                               &guidDevice,
  1060.                                               &lpd3dDevice);
  1061.     if (FAILED(hRes))
  1062.         return hRes;
  1063.  
  1064.     return DD_OK;
  1065. }
  1066.  
  1067. /***********************************************************************/
  1068.  
  1069. /*
  1070.  * Restore the video memory for the device surface and z-buffer if it
  1071.  * has been lost.
  1072.  */
  1073. static HRESULT
  1074. RestoreDevice(void)
  1075. {
  1076.     HRESULT hRes;
  1077.  
  1078.     if (NULL != lpddZBuffer)
  1079.     {
  1080.         hRes = lpddZBuffer->lpVtbl->Restore(lpddZBuffer);
  1081.         if (FAILED(hRes))
  1082.             return hRes;
  1083.     }
  1084.  
  1085.     if (NULL != lpddDevice)
  1086.     {
  1087.         hRes = lpddDevice->lpVtbl->Restore(lpddDevice);
  1088.         if (FAILED(hRes))
  1089.             return hRes;
  1090.     }
  1091.  
  1092.     return DD_OK;
  1093. }
  1094.  
  1095. /***********************************************************************/
  1096.  
  1097. /*
  1098.  * Release the Direct3D device and its associated surfaces.
  1099.  */
  1100. static HRESULT
  1101. ReleaseDevice(void)
  1102. {
  1103.     if (NULL != lpd3dDevice)
  1104.     {
  1105.         lpd3dDevice->lpVtbl->Release(lpd3dDevice);
  1106.         lpd3dDevice = NULL;
  1107.     }
  1108.     if (NULL != lpddZBuffer)
  1109.     {
  1110.         lpddZBuffer->lpVtbl->Release(lpddZBuffer);
  1111.         lpddZBuffer = NULL;
  1112.     }
  1113.     if (NULL != lpddDevice)
  1114.     {
  1115.         lpddDevice->lpVtbl->Release(lpddDevice);
  1116.         lpddDevice = NULL;
  1117.     }
  1118.  
  1119.     return DD_OK;
  1120. }
  1121.  
  1122. /***********************************************************************/
  1123.  
  1124. /*
  1125.  * Attempt to restore all the surfaces used by the application.
  1126.  */
  1127. static LRESULT
  1128. RestoreSurfaces(void)
  1129. {
  1130.     HRESULT hRes;
  1131.  
  1132.     hRes = RestorePrimary();
  1133.     if (FAILED(hRes))
  1134.         return hRes;
  1135.  
  1136.     hRes = RestoreDevice();
  1137.     if (FAILED(hRes))
  1138.         return hRes;
  1139.  
  1140.     return DD_OK;
  1141. }
  1142.  
  1143. /***********************************************************************/
  1144.  
  1145. /*
  1146.  * Fill the single execute buffer used in this sample with all the
  1147.  * vertices, transform, light and render state and drawing primitives
  1148.  * necessary to draw our triangle.
  1149.  *
  1150.  * NOTE: This is not the most efficient way of organizing the execute
  1151.  * buffer. For best performance you want to minimize state changes. In
  1152.  * this sample we submit the execute buffer for each frame in the
  1153.  * animation loop and no state in the buffer is modified. The only 
  1154.  * thing we modify is the world matrix (its contents - not its handle).
  1155.  * Therefore, it would be more efficient to extract all the static
  1156.  * state instructions into a separate execute buffer which we issue
  1157.  * once only at startup and, from then on, simply execute a second
  1158.  * execute buffer with vertices and triangles.
  1159.  * However, this sample is not exactly performance critical so we will
  1160.  * just use one execute buffer and resubmit it its entirety for each
  1161.  * frame.
  1162.  */
  1163. static HRESULT
  1164. FillExecuteBuffer(void)
  1165. {
  1166.     HRESULT              hRes;
  1167.     D3DEXECUTEBUFFERDESC d3dExeBufDesc;
  1168.     LPD3DVERTEX          lpVertex;
  1169.     LPD3DINSTRUCTION     lpInstruction;
  1170.     LPD3DPROCESSVERTICES lpProcessVertices;
  1171.     LPD3DTRIANGLE        lpTriangle;
  1172.     LPD3DSTATE           lpState;
  1173.  
  1174.     ASSERT(NULL != lpd3dExecuteBuffer);
  1175.     ASSERT(0UL  != hd3dSurfaceMaterial);
  1176.     ASSERT(0UL  != hd3dWorldMatrix);
  1177.     ASSERT(0UL  != hd3dViewMatrix);
  1178.     ASSERT(0UL  != hd3dProjMatrix);
  1179.  
  1180.     /*
  1181.      * Lock the execute buffer.
  1182.      */
  1183.     ZeroMemory(&d3dExeBufDesc, sizeof(d3dExeBufDesc));
  1184.     d3dExeBufDesc.dwSize = sizeof(d3dExeBufDesc);
  1185.     hRes = lpd3dExecuteBuffer->lpVtbl->Lock(lpd3dExecuteBuffer, &d3dExeBufDesc);
  1186.     if (FAILED(hRes))
  1187.         return hRes;
  1188.  
  1189.     /*
  1190.      * For explanatory purposes we fill the execute buffer by casting
  1191.      * a pointer to the execute buffer to the appropriate data structures.
  1192.      *
  1193.      * !!! NOTE: Issue - alignment.
  1194.      */
  1195.     lpVertex = (LPD3DVERTEX)d3dExeBufDesc.lpData;
  1196.  
  1197.     /*
  1198.      * First vertex.
  1199.      */
  1200.     lpVertex->dvX  = D3DVAL( 0.0); /* Position in model coordinates       */
  1201.     lpVertex->dvY  = D3DVAL( 1.0);
  1202.     lpVertex->dvZ  = D3DVAL( 0.0);
  1203.     lpVertex->dvNX = D3DVAL( 0.0); /* Normalized illumination normal      */
  1204.     lpVertex->dvNY = D3DVAL( 0.0);
  1205.     lpVertex->dvNZ = D3DVAL(-1.0);
  1206.     lpVertex->dvTU = D3DVAL( 0.0); /* Texture coordinates (not used here) */
  1207.     lpVertex->dvTV = D3DVAL( 1.0);
  1208.     lpVertex++;
  1209.  
  1210.     /*
  1211.      * Second vertex.
  1212.      */
  1213.     lpVertex->dvX  = D3DVAL( 1.0); /* Position in model coordinates       */
  1214.     lpVertex->dvY  = D3DVAL(-1.0);
  1215.     lpVertex->dvZ  = D3DVAL( 0.0);
  1216.     lpVertex->dvNX = D3DVAL( 0.0); /* Normalized illumination normal      */
  1217.     lpVertex->dvNY = D3DVAL( 0.0);
  1218.     lpVertex->dvNZ = D3DVAL(-1.0);
  1219.     lpVertex->dvTU = D3DVAL( 1.0); /* Texture coordinates (not used here) */
  1220.     lpVertex->dvTV = D3DVAL( 1.0);
  1221.     lpVertex++;
  1222.  
  1223.     /*
  1224.      * Third vertex.
  1225.      */
  1226.     lpVertex->dvX  = D3DVAL(-1.0); /* Position in model coordinates       */
  1227.     lpVertex->dvY  = D3DVAL(-1.0);
  1228.     lpVertex->dvZ  = D3DVAL( 0.0);
  1229.     lpVertex->dvNX = D3DVAL( 0.0); /* Normalized illumination normal      */
  1230.     lpVertex->dvNY = D3DVAL( 0.0);
  1231.     lpVertex->dvNZ = D3DVAL(-1.0);
  1232.     lpVertex->dvTU = D3DVAL( 1.0); /* Texture coordinates (not used here) */
  1233.     lpVertex->dvTV = D3DVAL( 0.0);
  1234.     lpVertex++;
  1235.  
  1236.     /*
  1237.      * Transform state - world, view and projection.
  1238.      */
  1239.     lpInstruction = (LPD3DINSTRUCTION)lpVertex;
  1240.     lpInstruction->bOpcode = D3DOP_STATETRANSFORM;
  1241.     lpInstruction->bSize   = sizeof(D3DSTATE);
  1242.     lpInstruction->wCount  = 3U;
  1243.     lpInstruction++;
  1244.     lpState = (LPD3DSTATE)lpInstruction;
  1245.     lpState->dtstTransformStateType = D3DTRANSFORMSTATE_WORLD;
  1246.     lpState->dwArg[0] = hd3dWorldMatrix;
  1247.     lpState++;
  1248.     lpState->dtstTransformStateType = D3DTRANSFORMSTATE_VIEW;
  1249.     lpState->dwArg[0] = hd3dViewMatrix;
  1250.     lpState++;
  1251.     lpState->dtstTransformStateType = D3DTRANSFORMSTATE_PROJECTION;
  1252.     lpState->dwArg[0] = hd3dProjMatrix;
  1253.     lpState++;
  1254.  
  1255.     /*
  1256.      * Lighting state.
  1257.      */
  1258.     lpInstruction = (LPD3DINSTRUCTION)lpState;
  1259.     lpInstruction->bOpcode = D3DOP_STATELIGHT;
  1260.     lpInstruction->bSize   = sizeof(D3DSTATE);
  1261.     lpInstruction->wCount  = 2U;
  1262.     lpInstruction++;
  1263.     lpState = (LPD3DSTATE)lpInstruction;
  1264.     lpState->dlstLightStateType = D3DLIGHTSTATE_MATERIAL;
  1265.     lpState->dwArg[0] = hd3dSurfaceMaterial;
  1266.     lpState++;
  1267.     lpState->dlstLightStateType = D3DLIGHTSTATE_AMBIENT;
  1268.     lpState->dwArg[0] = RGBA_MAKE(128, 128, 128, 128);
  1269.     lpState++;
  1270.  
  1271.     /*
  1272.      * Render state.
  1273.      */
  1274.     lpInstruction = (LPD3DINSTRUCTION)lpState;
  1275.     lpInstruction->bOpcode = D3DOP_STATERENDER;
  1276.     lpInstruction->bSize = sizeof(D3DSTATE);
  1277.     lpInstruction->wCount = 3U;
  1278.     lpInstruction++;
  1279.     lpState = (LPD3DSTATE)lpInstruction;
  1280.     lpState->drstRenderStateType = D3DRENDERSTATE_FILLMODE;
  1281.     lpState->dwArg[0] = D3DFILL_SOLID;
  1282.     lpState++;
  1283.     lpState->drstRenderStateType = D3DRENDERSTATE_SHADEMODE;
  1284.     lpState->dwArg[0] = D3DSHADE_GOURAUD;
  1285.     lpState++;
  1286.     lpState->drstRenderStateType = D3DRENDERSTATE_DITHERENABLE;
  1287.     lpState->dwArg[0] = TRUE;
  1288.     lpState++;
  1289.  
  1290.     /*
  1291.      * The process vertices instruction tells the driver what to
  1292.      * do with the vertices in the buffer. In this sample we want
  1293.      * Direct3D to perform the entire pipeline on our behalf so
  1294.      * the instruction is D3DPROCESSVERTICES_TRANSFORMLIGHT.
  1295.      */
  1296.     lpInstruction = (LPD3DINSTRUCTION)lpState;
  1297.     lpInstruction->bOpcode = D3DOP_PROCESSVERTICES;
  1298.     lpInstruction->bSize   = sizeof(D3DPROCESSVERTICES);
  1299.     lpInstruction->wCount  = 1U;
  1300.     lpInstruction++;
  1301.     lpProcessVertices = (LPD3DPROCESSVERTICES)lpInstruction;
  1302.     lpProcessVertices->dwFlags    = D3DPROCESSVERTICES_TRANSFORMLIGHT;
  1303.     lpProcessVertices->wStart     = 0U;           /* First source vertex */
  1304.     lpProcessVertices->wDest      = 0U;
  1305.     lpProcessVertices->dwCount    = NUM_VERTICES; /* Number of vertices  */
  1306.     lpProcessVertices->dwReserved = 0UL;
  1307.     lpProcessVertices++;
  1308.  
  1309.     /*
  1310.      * Draw the triangle.
  1311.      */
  1312.     lpInstruction = (LPD3DINSTRUCTION)lpProcessVertices;
  1313.     lpInstruction->bOpcode = D3DOP_TRIANGLE;
  1314.     lpInstruction->bSize   = sizeof(D3DTRIANGLE);
  1315.     lpInstruction->wCount  = 1U;
  1316.     lpInstruction++;
  1317.     lpTriangle = (LPD3DTRIANGLE)lpInstruction;
  1318.     lpTriangle->wV1    = 0U; 
  1319.     lpTriangle->wV2    = 1U;
  1320.     lpTriangle->wV3    = 2U;
  1321.     lpTriangle->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  1322.     lpTriangle++;
  1323.  
  1324.     /*
  1325.      * Stop execution of the buffer.
  1326.      */
  1327.     lpInstruction = (LPD3DINSTRUCTION)lpTriangle;
  1328.     lpInstruction->bOpcode = D3DOP_EXIT;
  1329.     lpInstruction->bSize   = 0UL;
  1330.     lpInstruction->wCount  = 0U;
  1331.  
  1332.     /*
  1333.      * Unlock the execute buffer.
  1334.      */
  1335.     lpd3dExecuteBuffer->lpVtbl->Unlock(lpd3dExecuteBuffer);
  1336.  
  1337.     return DD_OK;
  1338. }
  1339.  
  1340. /***********************************************************************/
  1341.  
  1342. /*
  1343.  * Create the elements making up the 3D scene.
  1344.  *
  1345.  * In this sample the scene consists of the single light, the viewport,
  1346.  * the background and surface material, the three transformation matrices
  1347.  * and the execute buffer holding the state changes and drawing primitives.
  1348.  */
  1349. static HRESULT
  1350. CreateScene(void)
  1351. {
  1352.     HRESULT              hRes;
  1353.     D3DMATERIAL          d3dMaterial;
  1354.     D3DLIGHT             d3dLight;
  1355.     DWORD                dwVertexSize;
  1356.     DWORD                dwInstructionSize;
  1357.     DWORD                dwExecuteBufferSize;
  1358.     D3DEXECUTEBUFFERDESC d3dExecuteBufferDesc;
  1359.     D3DEXECUTEDATA       d3dExecuteData;
  1360.  
  1361.     ASSERT(NULL != lpd3d);
  1362.     ASSERT(NULL != lpd3dDevice);
  1363.     ASSERT(NULL == lpd3dViewport);
  1364.     ASSERT(NULL == lpd3dMaterial);
  1365.     ASSERT(NULL == lpd3dBackgroundMaterial);
  1366.     ASSERT(NULL == lpd3dExecuteBuffer);
  1367.     ASSERT(NULL == lpd3dLight);
  1368.     ASSERT(0UL  == hd3dWorldMatrix);
  1369.     ASSERT(0UL  == hd3dViewMatrix);
  1370.     ASSERT(0UL  == hd3dProjMatrix);
  1371.  
  1372.     /*
  1373.      * Create the light.
  1374.      */
  1375.     hRes = lpd3d->lpVtbl->CreateLight(lpd3d, &lpd3dLight, NULL);
  1376.     if (FAILED(hRes))
  1377.         return hRes;
  1378.  
  1379.     ZeroMemory(&d3dLight, sizeof(d3dLight));
  1380.     d3dLight.dwSize = sizeof(d3dLight);
  1381.     d3dLight.dltType = D3DLIGHT_POINT;
  1382.     d3dLight.dcvColor.dvR    = D3DVAL( 1.0);
  1383.     d3dLight.dcvColor.dvG    = D3DVAL( 1.0);
  1384.     d3dLight.dcvColor.dvB    = D3DVAL( 1.0);
  1385.     d3dLight.dcvColor.dvA    = D3DVAL( 1.0);
  1386.     d3dLight.dvPosition.dvX  = D3DVAL( 1.0);
  1387.     d3dLight.dvPosition.dvY  = D3DVAL(-1.0);
  1388.     d3dLight.dvPosition.dvZ  = D3DVAL(-1.0);
  1389.     d3dLight.dvAttenuation0  = D3DVAL( 1.0);
  1390.     d3dLight.dvAttenuation1  = D3DVAL( 0.1);
  1391.     d3dLight.dvAttenuation2  = D3DVAL( 0.0);
  1392.     hRes = lpd3dLight->lpVtbl->SetLight(lpd3dLight, &d3dLight);
  1393.     if (FAILED(hRes))
  1394.         return hRes;
  1395.  
  1396.     /*
  1397.      * Create the background material.
  1398.      */
  1399.     hRes = lpd3d->lpVtbl->CreateMaterial(lpd3d, &lpd3dBackgroundMaterial, NULL);
  1400.     if (FAILED(hRes))
  1401.         return hRes;
  1402.  
  1403.     ZeroMemory(&d3dMaterial, sizeof(d3dMaterial));
  1404.     d3dMaterial.dwSize = sizeof(d3dMaterial);
  1405.     d3dMaterial.dcvDiffuse.r  = D3DVAL(0.0);
  1406.     d3dMaterial.dcvDiffuse.g  = D3DVAL(0.0);
  1407.     d3dMaterial.dcvDiffuse.b  = D3DVAL(0.0);
  1408.     d3dMaterial.dcvAmbient.r  = D3DVAL(0.0);
  1409.     d3dMaterial.dcvAmbient.g  = D3DVAL(0.0);
  1410.     d3dMaterial.dcvAmbient.b  = D3DVAL(0.0);
  1411.     d3dMaterial.dcvSpecular.r = D3DVAL(0.0);
  1412.     d3dMaterial.dcvSpecular.g = D3DVAL(0.0);
  1413.     d3dMaterial.dcvSpecular.b = D3DVAL(0.0);
  1414.     d3dMaterial.dvPower       = D3DVAL(0.0);
  1415.  
  1416.     /*
  1417.      * As this is the background material we don't want a ramp allocated (we
  1418.      * are not going to be smooth shading the background).
  1419.      */
  1420.     d3dMaterial.dwRampSize    = 1UL;
  1421.     
  1422.     hRes = lpd3dBackgroundMaterial->lpVtbl->SetMaterial(lpd3dBackgroundMaterial,
  1423.                                                         &d3dMaterial);
  1424.     if (FAILED(hRes))
  1425.         return hRes;
  1426.     hRes = lpd3dBackgroundMaterial->lpVtbl->GetHandle(lpd3dBackgroundMaterial,
  1427.                                                       lpd3dDevice,
  1428.                                                       &hd3dBackgroundMaterial);
  1429.     if (FAILED(hRes))
  1430.         return hRes;
  1431.  
  1432.     /*
  1433.      * Create the viewport.
  1434.      *
  1435.      * The actual viewport parameter are set in the function UpdateViewport
  1436.      * which is called in response to WM_SIZE.
  1437.      */
  1438.     hRes = lpd3d->lpVtbl->CreateViewport(lpd3d, &lpd3dViewport, NULL);
  1439.     if (FAILED(hRes))
  1440.         return hRes;
  1441.     hRes = lpd3dDevice->lpVtbl->AddViewport(lpd3dDevice, lpd3dViewport);
  1442.     if (FAILED(hRes))
  1443.         return hRes;
  1444.     hRes = lpd3dViewport->lpVtbl->SetBackground(lpd3dViewport, hd3dBackgroundMaterial);
  1445.     if (FAILED(hRes))
  1446.         return hRes;
  1447.     hRes = lpd3dViewport->lpVtbl->AddLight(lpd3dViewport, lpd3dLight);
  1448.     if (FAILED(hRes))
  1449.         return hRes;
  1450.  
  1451.     /*
  1452.      * Create the matrices.
  1453.      */
  1454.     hRes = lpd3dDevice->lpVtbl->CreateMatrix(lpd3dDevice, &hd3dWorldMatrix);
  1455.     if (FAILED(hRes))
  1456.         return hRes;
  1457.     hRes = lpd3dDevice->lpVtbl->SetMatrix(lpd3dDevice, hd3dWorldMatrix, &d3dWorldMatrix);
  1458.     if (FAILED(hRes))
  1459.         return hRes;
  1460.     hRes = lpd3dDevice->lpVtbl->CreateMatrix(lpd3dDevice, &hd3dViewMatrix);
  1461.     if (FAILED(hRes))
  1462.         return hRes;
  1463.     hRes = lpd3dDevice->lpVtbl->SetMatrix(lpd3dDevice, hd3dViewMatrix, &d3dViewMatrix);
  1464.     if (FAILED(hRes))
  1465.         return hRes;
  1466.     hRes = lpd3dDevice->lpVtbl->CreateMatrix(lpd3dDevice, &hd3dProjMatrix);
  1467.     if (FAILED(hRes))
  1468.         return hRes;
  1469.     SetPerspectiveProjection(&d3dProjMatrix, HALF_HEIGHT, FRONT_CLIP, BACK_CLIP);
  1470.     hRes = lpd3dDevice->lpVtbl->SetMatrix(lpd3dDevice, hd3dProjMatrix, &d3dProjMatrix);
  1471.     if (FAILED(hRes))
  1472.         return hRes;
  1473.  
  1474.     /*
  1475.      * Create the surface material.
  1476.      */
  1477.     hRes = lpd3d->lpVtbl->CreateMaterial(lpd3d, &lpd3dMaterial, NULL);
  1478.     if (FAILED(hRes))
  1479.         return hRes;
  1480.     ZeroMemory(&d3dMaterial, sizeof(d3dMaterial));
  1481.     d3dMaterial.dwSize = sizeof(d3dMaterial);
  1482.  
  1483.     /*
  1484.      * Base green with white specular.
  1485.      */
  1486.     d3dMaterial.dcvDiffuse.r  = D3DVAL(0.0);
  1487.     d3dMaterial.dcvDiffuse.g  = D3DVAL(1.0);
  1488.     d3dMaterial.dcvDiffuse.b  = D3DVAL(0.0);
  1489.     d3dMaterial.dcvAmbient.r  = D3DVAL(0.0);
  1490.     d3dMaterial.dcvAmbient.g  = D3DVAL(0.4);
  1491.     d3dMaterial.dcvAmbient.b  = D3DVAL(0.0);
  1492.     d3dMaterial.dcvSpecular.r = D3DVAL(1.0);
  1493.     d3dMaterial.dcvSpecular.g = D3DVAL(1.0);
  1494.     d3dMaterial.dcvSpecular.b = D3DVAL(1.0);
  1495.     d3dMaterial.dvPower       = D3DVAL(20.0);
  1496.     d3dMaterial.dwRampSize    = 16UL;
  1497.     
  1498.     hRes = lpd3dMaterial->lpVtbl->SetMaterial(lpd3dMaterial, &d3dMaterial);
  1499.     if (FAILED(hRes))
  1500.         return hRes;
  1501.  
  1502.     hRes = lpd3dMaterial->lpVtbl->GetHandle(lpd3dMaterial, lpd3dDevice, &hd3dSurfaceMaterial);
  1503.     if (FAILED(hRes))
  1504.         return hRes;
  1505.  
  1506.     /*
  1507.      * Build the execute buffer.
  1508.      */
  1509.     dwVertexSize        = (NUM_VERTICES        * sizeof(D3DVERTEX));
  1510.     dwInstructionSize   = (NUM_INSTRUCTIONS    * sizeof(D3DINSTRUCTION))     +
  1511.                           (NUM_STATES          * sizeof(D3DSTATE))           +
  1512.                           (NUM_PROCESSVERTICES * sizeof(D3DPROCESSVERTICES)) +
  1513.                           (NUM_TRIANGLES       * sizeof(D3DTRIANGLE));
  1514.     dwExecuteBufferSize = dwVertexSize + dwInstructionSize;
  1515.     ZeroMemory(&d3dExecuteBufferDesc, sizeof(d3dExecuteBufferDesc));
  1516.     d3dExecuteBufferDesc.dwSize       = sizeof(d3dExecuteBufferDesc);
  1517.     d3dExecuteBufferDesc.dwFlags      = D3DDEB_BUFSIZE;
  1518.     d3dExecuteBufferDesc.dwBufferSize = dwExecuteBufferSize;
  1519.     hRes = lpd3dDevice->lpVtbl->CreateExecuteBuffer(lpd3dDevice,
  1520.                                                     &d3dExecuteBufferDesc,
  1521.                                                     &lpd3dExecuteBuffer,
  1522.                                                     NULL);
  1523.     if (FAILED(hRes))
  1524.         return hRes;
  1525.  
  1526.     /*
  1527.      * Fill the execute buffer with the required vertices, state
  1528.      * instructions and drawing primitives.
  1529.      */
  1530.     hRes = FillExecuteBuffer();
  1531.     if (FAILED(hRes))
  1532.         return hRes;
  1533.  
  1534.     /*
  1535.      * Set the execute data so Direct3D knows how many vertices are in the
  1536.      * buffer and where the instructions start.
  1537.      */
  1538.     ZeroMemory(&d3dExecuteData, sizeof(d3dExecuteData));
  1539.     d3dExecuteData.dwSize = sizeof(d3dExecuteData);
  1540.     d3dExecuteData.dwVertexCount       = NUM_VERTICES;
  1541.     d3dExecuteData.dwInstructionOffset = dwVertexSize;
  1542.     d3dExecuteData.dwInstructionLength = dwInstructionSize;
  1543.     hRes = lpd3dExecuteBuffer->lpVtbl->SetExecuteData(lpd3dExecuteBuffer, &d3dExecuteData);
  1544.     if (FAILED(hRes))
  1545.         return hRes;
  1546.  
  1547.     return DD_OK;
  1548. }
  1549.  
  1550. /***********************************************************************/
  1551.  
  1552. /*
  1553.  * Release all the objects comprising the 3D scene.
  1554.  */
  1555. static HRESULT
  1556. ReleaseScene(void)
  1557. {
  1558.     if (NULL != lpd3dExecuteBuffer)
  1559.     {
  1560.         lpd3dExecuteBuffer->lpVtbl->Release(lpd3dExecuteBuffer);
  1561.         lpd3dExecuteBuffer = NULL;
  1562.     }
  1563.     if (NULL != lpd3dBackgroundMaterial)
  1564.     {
  1565.         lpd3dBackgroundMaterial->lpVtbl->Release(lpd3dBackgroundMaterial);
  1566.         lpd3dBackgroundMaterial = NULL;
  1567.     }
  1568.     if (NULL != lpd3dMaterial)
  1569.     {
  1570.         lpd3dMaterial->lpVtbl->Release(lpd3dMaterial);
  1571.         lpd3dMaterial = NULL;
  1572.     }
  1573.     if (0UL != hd3dWorldMatrix)
  1574.     {
  1575.         lpd3dDevice->lpVtbl->DeleteMatrix(lpd3dDevice, hd3dWorldMatrix);
  1576.         hd3dWorldMatrix = 0UL;
  1577.     }
  1578.     if (0UL != hd3dViewMatrix)
  1579.     {
  1580.         lpd3dDevice->lpVtbl->DeleteMatrix(lpd3dDevice, hd3dViewMatrix);
  1581.         hd3dViewMatrix = 0UL;
  1582.     }
  1583.     if (0UL != hd3dProjMatrix)
  1584.     {
  1585.         lpd3dDevice->lpVtbl->DeleteMatrix(lpd3dDevice, hd3dProjMatrix);
  1586.         hd3dProjMatrix = 0UL;
  1587.     }
  1588.     if (NULL != lpd3dLight)
  1589.     {
  1590.         lpd3dLight->lpVtbl->Release(lpd3dLight);
  1591.         lpd3dLight = NULL;
  1592.     }
  1593.     if (NULL != lpd3dViewport)
  1594.     {
  1595.         lpd3dViewport->lpVtbl->Release(lpd3dViewport);
  1596.         lpd3dViewport = NULL;
  1597.     }
  1598.  
  1599.     return DD_OK;
  1600. }
  1601.  
  1602. /***********************************************************************/
  1603.  
  1604. /*
  1605.  * Animate the scene.
  1606.  *
  1607.  * The animation in this sample is simply a rotation about the Y axis.
  1608.  * So all we need to do is build a rotation matrix and set the world
  1609.  * matrix to that new rotation matrix.
  1610.  *
  1611.  * Note, we don't need to modify the execute buffer in any way to peform
  1612.  * this rotation. We simply set the matrix and resubmit the execute
  1613.  * buffer.
  1614.  */
  1615. static HRESULT
  1616. AnimateScene(void)
  1617. {
  1618.     HRESULT hRes;
  1619.  
  1620.     ASSERT(NULL != lpd3dDevice);
  1621.     ASSERT(0UL  != hd3dWorldMatrix);
  1622.  
  1623.     /*
  1624.      * We rotate the triangle by setting the world transform to a
  1625.      * rotation matrix.
  1626.      */
  1627.     SetRotationAboutY(&d3dWorldMatrix, dAngleOfRotation);
  1628.     dAngleOfRotation += ROTATE_ANGLE_DELTA;
  1629.     hRes = lpd3dDevice->lpVtbl->SetMatrix(lpd3dDevice,
  1630.                                           hd3dWorldMatrix,
  1631.                                           &d3dWorldMatrix);
  1632.     if (FAILED(hRes))
  1633.         return hRes;
  1634.  
  1635.     return DD_OK;
  1636. }
  1637.  
  1638. /***********************************************************************/
  1639.  
  1640. /*
  1641.  * Update the viewport in response to a change in window size. This
  1642.  * ensures that we render at a resolution which matches the client
  1643.  * area of the target window.
  1644.  */
  1645. static HRESULT
  1646. UpdateViewport(void)
  1647. {
  1648.     D3DVIEWPORT d3dViewport;
  1649.  
  1650.     ASSERT(NULL != lpd3dViewport);
  1651.  
  1652.     ZeroMemory(&d3dViewport, sizeof(d3dViewport));
  1653.     d3dViewport.dwSize   = sizeof(d3dViewport);
  1654.     d3dViewport.dwX      = 0UL;
  1655.     d3dViewport.dwY      = 0UL;
  1656.     d3dViewport.dwWidth  = (DWORD)rSrcRect.right;
  1657.     d3dViewport.dwHeight = (DWORD)rSrcRect.bottom;
  1658.     d3dViewport.dvScaleX = D3DVAL((float)d3dViewport.dwWidth / 2.0);
  1659.     d3dViewport.dvScaleY = D3DVAL((float)d3dViewport.dwHeight / 2.0);
  1660.     d3dViewport.dvMaxX   = D3DVAL(1.0);
  1661.     d3dViewport.dvMaxY   = D3DVAL(1.0);
  1662.     return lpd3dViewport->lpVtbl->SetViewport(lpd3dViewport, &d3dViewport);
  1663. }
  1664.  
  1665. /***********************************************************************/
  1666.  
  1667. /*
  1668.  * Render the 3D scene.
  1669.  *
  1670.  * Fundamentally this involved submitting our single execute buffer.
  1671.  * However, we also need to clear the back and z-buffers and demark
  1672.  * the start and end of the scene (which in this case is a single
  1673.  * execute).
  1674.  */
  1675. static HRESULT
  1676. RenderScene(void)
  1677. {
  1678.     HRESULT hRes;
  1679.     D3DRECT d3dRect;
  1680.  
  1681.     ASSERT(NULL != lpd3dViewport);
  1682.     ASSERT(NULL != lpd3dDevice);
  1683.     ASSERT(NULL != lpd3dExecuteBuffer);
  1684.  
  1685.     /*
  1686.      * Clear both back and z-buffer.
  1687.      *
  1688.      * NOTE: Its safe to specify the z-buffer clear flag even if we
  1689.      * don't have an attached z-buffer. Direct3D will simply discard
  1690.      * the flag if no z-buffer is being used.
  1691.      *
  1692.      * NOTE: For maximum efficiency we only want to clear those
  1693.      * regions of the device surface and z-buffer which we actually
  1694.      * rendered to in the last frame. This is the purpose of the
  1695.      * array of rectangles and count passed to this function. It is
  1696.      * possible to query Direct3D for the regions of the device
  1697.      * surface that were rendered to by that execute. The application
  1698.      * can then accumulate those rectangles and clear only those
  1699.      * regions. However this is a very simple sample and so, for
  1700.      * simplicity, we will just clear the entire device surface and
  1701.      * z-buffer. Probably not something you want to do in a real
  1702.      * application.
  1703.      */
  1704.     d3dRect.lX1 = rSrcRect.left;
  1705.     d3dRect.lX2 = rSrcRect.right;
  1706.     d3dRect.lY1 = rSrcRect.top;
  1707.     d3dRect.lY2 = rSrcRect.bottom;
  1708.     hRes = lpd3dViewport->lpVtbl->Clear(lpd3dViewport,
  1709.                                         1UL,
  1710.                                         &d3dRect,
  1711.                                         D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
  1712.     if (FAILED(hRes))
  1713.         return hRes;
  1714.  
  1715.     /*
  1716.      * Start the scene.
  1717.      *
  1718.      * This function must be called once and once only for every frame
  1719.      * of animation. If you have multiple execute buffers comprising a
  1720.      * single frame you must have one call to BeginScene() before
  1721.      * submitting those execute buffers.
  1722.      *
  1723.      * NOTE: If you have more than one device being rendered in a
  1724.      * single frame, say a rear view mirror in a racing game, call
  1725.      * BeginScene() and EndScene() once for each device.
  1726.      */
  1727.     hRes = lpd3dDevice->lpVtbl->BeginScene(lpd3dDevice);
  1728.     if (FAILED(hRes))
  1729.         return hRes;
  1730.  
  1731.     /*
  1732.      * Submit the execute buffer.
  1733.      *
  1734.      * We want Direct3D to clip the data on our behalf so we specify
  1735.      * D3DEXECUTE_CLIPPED.
  1736.      */
  1737.     hRes = lpd3dDevice->lpVtbl->Execute(lpd3dDevice,
  1738.                                         lpd3dExecuteBuffer,
  1739.                                         lpd3dViewport,
  1740.                                         D3DEXECUTE_CLIPPED);
  1741.     if (FAILED(hRes))
  1742.     {
  1743.         lpd3dDevice->lpVtbl->EndScene(lpd3dDevice);
  1744.         return hRes;
  1745.     }
  1746.  
  1747.     /*
  1748.      * End the scene.
  1749.      */
  1750.     hRes = lpd3dDevice->lpVtbl->EndScene(lpd3dDevice);
  1751.     if (FAILED(hRes))
  1752.         return hRes;
  1753.  
  1754.     /*
  1755.      * At this point the scene will have been rendered and the device
  1756.      * surface will hold the contents of the rendering.
  1757.      */
  1758.  
  1759.     return DD_OK;
  1760. }
  1761.  
  1762. /***********************************************************************/
  1763.  
  1764. /*
  1765.  * Render and show a single frame.
  1766.  *
  1767.  * This involves rendering the scene and blitting the result to client
  1768.  * area of the application window on the primary surface.
  1769.  *
  1770.  * NOTE: This function handles lost surfaces by attempting to restore
  1771.  * the applications surfaces and then retrying the rendering.
  1772.  */
  1773. static HRESULT
  1774. DoFrame(HWND hwnd)
  1775. {
  1776.     HRESULT hRes;
  1777.  
  1778.     /*
  1779.      * We keeping trying until we succeed or we fail for a reason
  1780.      * other than DDERR_SURFACELOST.
  1781.      */
  1782.     while (TRUE)
  1783.     {
  1784.         hRes = RenderScene();
  1785.         if (SUCCEEDED(hRes))
  1786.         {
  1787.         POINT pt;
  1788.         RECT rTmp;
  1789.  
  1790.         pt.x = pt.y = 0;
  1791.         ClientToScreen( hwnd, &pt );
  1792.  
  1793.         rTmp = rDstRect;
  1794.  
  1795.         // For multi-monitor systems, we need to translate
  1796.         // the Desktop coordinates into Device coordinates.
  1797.         pt.x -= rectMonitor.left;
  1798.         pt.y -= rectMonitor.top;
  1799.         OffsetRect(&rTmp, pt.x, pt.y);
  1800.  
  1801.             hRes = lpddPrimary->lpVtbl->Blt(lpddPrimary,
  1802.                                             &rTmp,
  1803.                                             lpddDevice,
  1804.                                             &rSrcRect,
  1805.                                             DDBLT_WAIT,
  1806.                                             NULL);
  1807.             if (SUCCEEDED(hRes))
  1808.                 /*
  1809.                  * It worked. Bail.
  1810.                  */
  1811.                 return hRes;
  1812.         }
  1813.         while (DDERR_SURFACELOST == hRes)
  1814.             /*
  1815.              * The surfaces are lost. Restore them.
  1816.              */
  1817.             hRes = RestoreSurfaces();
  1818.         if (FAILED(hRes))
  1819.             /*
  1820.              * Something went wrong and it wasn't DDERR_SURFACELOST.
  1821.              */
  1822.             return hRes;
  1823.     }
  1824. }
  1825.  
  1826. /***********************************************************************/
  1827.  
  1828. /*
  1829.  * The application suspends when in the background or when handling and
  1830.  * error. We signal this fact by drawing a notification string in the
  1831.  * client area of the window.
  1832.  */
  1833. static void
  1834. PaintSuspended(HWND hwnd, HDC hdc)
  1835. {
  1836.     HPEN     hOldPen;
  1837.     HBRUSH   hOldBrush;
  1838.     COLORREF crOldTextColor;
  1839.     int      oldMode;
  1840.     int      x;
  1841.     int      y;
  1842.     SIZE     size;
  1843.     RECT     rect;
  1844.     int      nStrLen;
  1845.  
  1846.     /*
  1847.      * Black background.
  1848.      */
  1849.     hOldPen   = SelectObject(hdc, GetStockObject(NULL_PEN));
  1850.     hOldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
  1851.  
  1852.     /*
  1853.      * White text.
  1854.      */
  1855.     oldMode = SetBkMode(hdc, TRANSPARENT);
  1856.     crOldTextColor = SetTextColor(hdc, RGB(255, 255, 255));
  1857.  
  1858.     GetClientRect(hwnd, &rect);
  1859.  
  1860.     /*
  1861.      * Clear the client area.
  1862.      */
  1863.     Rectangle(hdc, rect.left, rect.top, rect.right + 1, rect.bottom + 1);
  1864.  
  1865.     /*
  1866.      * Draw the string centered in the client area.
  1867.      */
  1868.     nStrLen = strlen(PAUSED_STRING);
  1869.     GetTextExtentPoint32(hdc, PAUSED_STRING, nStrLen, &size);
  1870.     x = (rect.right  - size.cx) / 2;
  1871.     y = (rect.bottom - size.cy) / 2;
  1872.     TextOut(hdc, x, y, PAUSED_STRING, nStrLen);
  1873.  
  1874.     SetTextColor(hdc, crOldTextColor);
  1875.     SetBkMode(hdc, oldMode);
  1876.  
  1877.     SelectObject(hdc, hOldBrush);
  1878.     SelectObject(hdc, hOldPen);
  1879. }
  1880.  
  1881. /***********************************************************************/
  1882.  
  1883. static LRESULT
  1884. OnMove(HWND hwnd, int x, int y)
  1885. {
  1886.     HRESULT hRes;
  1887.  
  1888.     hRes = CheckMonitors(hwnd, FALSE);
  1889.     if (FAILED(hRes))
  1890.     {
  1891.     return 0L;
  1892.     }
  1893.  
  1894.     /*
  1895.      * No action if the device has not yet been created or if we are
  1896.      * suspended.
  1897.      */
  1898.     if ((NULL != lpd3dDevice) && !fSuspended)
  1899.     {
  1900.         /*
  1901.          * Repaint the client area.
  1902.          */
  1903.         hRes = DoFrame(hwnd);
  1904.         if (FAILED(hRes))
  1905.         {
  1906.             FatalError(hwnd, IDS_ERRMSG_RENDERSCENE, hRes);
  1907.             return 0L;
  1908.         }
  1909.     }
  1910.  
  1911.     return 0L;
  1912. }
  1913.  
  1914. /***********************************************************************/
  1915. #define FORCE_RESET TRUE
  1916.  
  1917. static HRESULT
  1918. CheckMonitors(HWND hwnd, BOOL fReset)
  1919. {   
  1920.     HRESULT     hRes;
  1921.     char        szBuffer[128];
  1922.  
  1923.     if (!fReset && hMonitor == DirectDrawDeviceFromWindow(hwnd, NULL, NULL))
  1924.     return S_OK;
  1925.  
  1926.     // If we do, then first release what we have so far
  1927.     ReleaseScene();
  1928.     ReleaseDevice();
  1929.     ReleasePrimary();
  1930.     ReleaseDirect3D();
  1931.  
  1932.     // Update our monitor information
  1933.     hMonitor = DirectDrawDeviceFromWindow(hwnd, szMonitor, &rectMonitor);
  1934.  
  1935.     // Now start from scratch
  1936.     hRes = CreateDirect3D(hwnd);
  1937.     if (FAILED(hRes))
  1938.     {
  1939.         ReportError(hwnd, IDS_ERRMSG_CREATEDEVICE, hRes);
  1940.         ReleaseDirect3D();
  1941.         return -1L;
  1942.     }
  1943.  
  1944.     hRes = CreatePrimary(hwnd);
  1945.     if (FAILED(hRes))
  1946.     {
  1947.         ReportError(hwnd, IDS_ERRMSG_INITSCREEN, hRes);
  1948.         ReleasePrimary();
  1949.         ReleaseDirect3D();
  1950.         return -1L;
  1951.     }
  1952.  
  1953.     hRes = ChooseDevice();
  1954.     if (FAILED(hRes))
  1955.     {
  1956.         ReportError(hwnd, IDS_ERRMSG_NODEVICE, hRes);
  1957.         ReleasePrimary();
  1958.         ReleaseDirect3D();
  1959.         return -1L;
  1960.     }
  1961.  
  1962.     hRes = CreateDevice((DWORD)rSrcRect.right, (DWORD)rSrcRect.bottom);
  1963.     if (FAILED(hRes))
  1964.     {
  1965.         FatalError(hwnd, IDS_ERRMSG_CREATEDEVICE, hRes);
  1966.     ReleaseDevice();
  1967.         ReleasePrimary();
  1968.         ReleaseDirect3D();
  1969.         return 0L;
  1970.     }
  1971.     hRes = CreateScene();
  1972.     if (FAILED(hRes))
  1973.     {
  1974.         FatalError(hwnd, IDS_ERRMSG_BUILDSCENE, hRes);
  1975.     ReleaseDevice();
  1976.         ReleasePrimary();
  1977.         ReleaseDirect3D();
  1978.         return 0L;
  1979.     }
  1980.  
  1981.     hRes = UpdateViewport();
  1982.     if (FAILED(hRes))
  1983.     {
  1984.         FatalError(hwnd, IDS_ERRMSG_UPDATEVIEWPORT, hRes);
  1985.     ReleaseScene();
  1986.     ReleaseDevice();
  1987.         ReleasePrimary();
  1988.         ReleaseDirect3D();
  1989.         return 0L;
  1990.     }
  1991.  
  1992.  
  1993.     /*
  1994.      * Update the title to show the name of the chosen device.
  1995.      */
  1996.     wsprintf(szBuffer, "%s: %s", WINDOW_TITLE, szDeviceName);
  1997.     SetWindowText(hwnd, szBuffer);
  1998.  
  1999.     return 0L;
  2000. }
  2001.  
  2002. /***********************************************************************/
  2003.  
  2004. /***********************************************************************/
  2005.  
  2006. static LRESULT
  2007. OnSize(HWND hwnd, int w, int h)
  2008. {
  2009.     HRESULT       hRes;
  2010.     DDSURFACEDESC ddsd;
  2011.  
  2012.     // Check if we need to update our monitor information
  2013.     // This can happen if our window is being sized onto
  2014.     // another monitor.
  2015.     hRes = CheckMonitors(hwnd, FALSE);
  2016.     if (FAILED(hRes))
  2017.     {
  2018.     return 0L;
  2019.     }
  2020.  
  2021.  
  2022.     /*
  2023.      * Nothing to do if we are suspended.
  2024.      */
  2025.     if (!fSuspended)
  2026.     {
  2027.         /*
  2028.          * Update the source and destination rectangles (used by the
  2029.          * blit which shows the rendering in the client area).
  2030.          */
  2031.         rDstRect.right  = rDstRect.left + w;
  2032.         rDstRect.bottom = rDstRect.top  + h;
  2033.  
  2034.     // If the window is sized to something larger than our initial size
  2035.     // then just use DDraw stretch. If it is something smaller
  2036.     // then reduce the complexity for Direct3D since the stretch
  2037.     // will just drop pixels anyhow.
  2038.         rSrcRect.right  = min(w, WINDOW_WIDTH);
  2039.         rSrcRect.bottom = min(h, WINDOW_HEIGHT);
  2040.  
  2041.         if (NULL != lpd3dDevice)
  2042.         {
  2043.             /*
  2044.              * We already have a device. But is it big enough for the the
  2045.              * new window client size?
  2046.              *
  2047.              * NOTE: As this window is fixed size we should not ever be
  2048.              * end up being resized. But just in case we will handle it.
  2049.              * This will be useful when we make the application resizable.
  2050.              */
  2051.             ZeroMemory(&ddsd, sizeof(ddsd));
  2052.             ddsd.dwSize = sizeof(ddsd);
  2053.             hRes = lpddDevice->lpVtbl->GetSurfaceDesc(lpddDevice, &ddsd);
  2054.             if (FAILED(hRes))
  2055.             {
  2056.                 FatalError(hwnd, IDS_ERRMSG_DEVICESIZE, hRes);
  2057.                 return 0L;
  2058.             }
  2059.     
  2060.             if ((w > (int)ddsd.dwWidth) || (h > (int)ddsd.dwHeight))
  2061.             {
  2062.                 /*
  2063.                  * Nope, the device is too small. We need to shut it down
  2064.                  * and rebuild it.
  2065.                  */
  2066.  
  2067.                 /*
  2068.                  * Execute buffers are bound to devices so when we release
  2069.                  * the device we must release the execute buffer.
  2070.                  */
  2071.                 ReleaseScene();
  2072.                 ReleaseDevice();
  2073.             }
  2074.         }
  2075.  
  2076.         if (NULL == lpd3dDevice)
  2077.         {
  2078.             /*
  2079.              * No Direct3D device yet. This is either because this is the
  2080.              * first time through the loop or because we discarded the
  2081.              * existing device because it was not big enough for the new
  2082.              * window client size.
  2083.              */
  2084.             hRes = CreateDevice((DWORD)w, (DWORD)h);
  2085.             if (FAILED(hRes))
  2086.             {
  2087.                 FatalError(hwnd, IDS_ERRMSG_CREATEDEVICE, hRes);
  2088.                 return 0L;
  2089.             }
  2090.             hRes = CreateScene();
  2091.             if (FAILED(hRes))
  2092.             {
  2093.                 FatalError(hwnd, IDS_ERRMSG_BUILDSCENE, hRes);
  2094.                 return 0L;
  2095.             }
  2096.         }
  2097.  
  2098.         hRes = UpdateViewport();
  2099.         if (FAILED(hRes))
  2100.         {
  2101.             FatalError(hwnd, IDS_ERRMSG_UPDATEVIEWPORT, hRes);
  2102.             return 0L;
  2103.         }
  2104.  
  2105.         /*
  2106.          * Render at the new size and show the results in the window's
  2107.          * client area.
  2108.          */
  2109.         hRes = DoFrame(hwnd);
  2110.         if (FAILED(hRes))
  2111.         {
  2112.             FatalError(hwnd, IDS_ERRMSG_RENDERSCENE, hRes);
  2113.             return 0L;
  2114.         }
  2115.     }
  2116.  
  2117.     return 0L;
  2118. }
  2119.  
  2120. /***********************************************************************/
  2121.  
  2122. static LRESULT
  2123. OnPaint(HWND hwnd, HDC hdc, LPPAINTSTRUCT lpps)
  2124. {
  2125.     HRESULT hRes;
  2126.  
  2127.     USE_PARAM(lpps);
  2128.  
  2129.     if (!fSuspended && (NULL != lpd3dDevice))
  2130.     {
  2131.         /*
  2132.          * NOTE: DoFrame() re-renders the scene as well as blitting the
  2133.          * result to the primary. As all we really want to do here is
  2134.          * repaint the client area we don't really need to re-render -
  2135.          * just re-blit. For this simple sample this inefficiency
  2136.          * doesn't matter but for real applications not re-rendering
  2137.          * may be a useful optimization.
  2138.          */
  2139.         hRes = DoFrame(hwnd);
  2140.         if (FAILED(hRes))
  2141.         {
  2142.             FatalError(hwnd, IDS_ERRMSG_RENDERSCENE, hRes);
  2143.             return 0L;
  2144.         }
  2145.     }
  2146.     else
  2147.     {
  2148.         /*
  2149.          * Show the suspended image if we are not active, or suspended or
  2150.          * if we have not yet created the device.
  2151.          */
  2152.         PaintSuspended(hwnd, hdc);
  2153.     }
  2154.  
  2155.     return 0L;
  2156. }
  2157.  
  2158. /***********************************************************************/
  2159.  
  2160. static LRESULT
  2161. OnIdle(HWND hwnd)
  2162. {
  2163.     HRESULT hRes;
  2164.  
  2165.     /*
  2166.      * Only animate if we aren't suspended
  2167.      * and we have completed initialization.
  2168.      */
  2169.     if ( !fSuspended && (NULL != lpd3dDevice))
  2170.     {
  2171.         hRes = AnimateScene();
  2172.         if (FAILED(hRes))
  2173.         {
  2174.             FatalError(hwnd, IDS_ERRMSG_ANIMATESCENE, hRes);
  2175.             return 0L;
  2176.         }
  2177.  
  2178.         hRes = DoFrame(hwnd);
  2179.         if (FAILED(hRes))
  2180.         {
  2181.             FatalError(hwnd, IDS_ERRMSG_RENDERSCENE, hRes);
  2182.             return 0L;
  2183.         }
  2184.     }
  2185.  
  2186.     return 0L;
  2187. }
  2188.  
  2189. /***********************************************************************/
  2190.  
  2191. LRESULT CALLBACK
  2192. WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  2193. {
  2194.     HDC         hdc;
  2195.     PAINTSTRUCT ps;
  2196.     LRESULT     lResult;
  2197.     HRESULT     hRes;
  2198.  
  2199.     switch (msg)
  2200.     {
  2201.         case WM_CREATE:
  2202.  
  2203.         hRes = CheckMonitors(hwnd, FORCE_RESET);
  2204.         if (FAILED(hRes))
  2205.         return -1;
  2206.  
  2207.             return 0L;
  2208.  
  2209.         case WM_MOVE:
  2210.             return OnMove(hwnd, (int)(signed short)LOWORD(lParam), (int)(signed short)HIWORD(lParam));
  2211.  
  2212.         case WM_SIZE:
  2213.             return OnSize(hwnd, (int)LOWORD(lParam), (int)HIWORD(lParam));
  2214.  
  2215.         case WM_ERASEBKGND:
  2216.             /*
  2217.              * Our rendering fills the entire viewport so we won't bother
  2218.              * erasing the background.
  2219.              */
  2220.             return 1L;
  2221.  
  2222.         case WM_PAINT:
  2223.             hdc = BeginPaint(hwnd, &ps);
  2224.  
  2225.             lResult = OnPaint(hwnd, hdc, &ps);
  2226.  
  2227.             EndPaint(hwnd, &ps);
  2228.             return lResult;
  2229.  
  2230.         case WM_ACTIVATEAPP:
  2231.             fActive = (BOOL)wParam;
  2232.             if (fActive && !fSuspended && (NULL != lpddPalette))
  2233.             {
  2234.                 /*
  2235.                  * Realizing the palette using DirectDraw is quite different
  2236.                  * from GDI. To realize the palette we call SetPalette()
  2237.                  * each time our application is activated.
  2238.                  *
  2239.                  * NOTE: DirectDraw spots the fact that the new palette is the
  2240.                  * same as the old one and so does not increase the reference
  2241.                  * count of the palette.
  2242.                  */
  2243.                 hRes = lpddPrimary->lpVtbl->SetPalette(lpddPrimary, lpddPalette);
  2244.                 if (FAILED(hRes))
  2245.                 {
  2246.                     FatalError(hwnd, IDS_ERRMSG_REALIZEPALETTE, hRes);
  2247.                     return 0L;
  2248.                 }
  2249.  
  2250.             }
  2251.             else
  2252.             {
  2253.                 /*
  2254.                  * If we have been deactived invalidate to show the suspended
  2255.                  * display.
  2256.                  */
  2257.                 InvalidateRect(hwnd, NULL, FALSE);
  2258.             }
  2259.             return 0L;
  2260.  
  2261.         case WM_KEYUP:
  2262.             /*
  2263.              * We use the escape key as a quick way of getting out of the
  2264.              * application.
  2265.              */
  2266.             if (VK_ESCAPE == (int)wParam)
  2267.             {
  2268.                 DestroyWindow(hwnd);
  2269.                 return 0L;
  2270.             }
  2271.             break;
  2272.  
  2273.         case WM_CLOSE:
  2274.             DestroyWindow(hwnd);
  2275.             return 0L;
  2276.  
  2277.         case WM_DESTROY:
  2278.             /*
  2279.              * All cleanup is done here when terminating normally or
  2280.              * shutting down due to an error.
  2281.              */
  2282.             ReleaseScene();
  2283.             ReleaseDevice();
  2284.             ReleasePrimary();
  2285.             ReleaseDirect3D();
  2286.  
  2287.             PostQuitMessage(0);
  2288.             return 0L;
  2289.     }
  2290.  
  2291.     return DefWindowProc(hwnd, msg, wParam, lParam);
  2292. }
  2293.                         
  2294. /***********************************************************************/
  2295.  
  2296. int PASCAL
  2297. WinMain(HINSTANCE hInstance,
  2298.         HINSTANCE hPrevInstance,
  2299.         LPSTR     lpszCommandLine,
  2300.         int       cmdShow)
  2301. {
  2302.     WNDCLASS wndClass;
  2303.     HWND     hwnd;
  2304.     MSG      msg;
  2305.  
  2306.     USE_PARAM(hPrevInstance);
  2307.  
  2308.     /*
  2309.      * Record the instance handle.
  2310.      */
  2311.     hAppInstance = hInstance;
  2312.  
  2313.     /*
  2314.      * Very, very primitive command line processing. We only have one
  2315.      * option, debug so we will just assume that if anything was
  2316.      * specified on the command line that means debug mode (no hardware
  2317.      * all surfaces explicitly in system memory).
  2318.      */
  2319.     if (0 != *lpszCommandLine)
  2320.         fDebug = TRUE;
  2321.  
  2322.     /*
  2323.      * Register the window class.
  2324.      */
  2325.     wndClass.style         = 0;
  2326.     wndClass.lpfnWndProc   = WndProc;
  2327.     wndClass.cbClsExtra    = 0;
  2328.     wndClass.cbWndExtra    = 0;
  2329.     wndClass.hInstance     = hInstance;
  2330.     wndClass.hIcon         = LoadIcon(hAppInstance, MAKEINTRESOURCE(IDI_APPICON));
  2331.     wndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  2332.     wndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
  2333.     wndClass.lpszMenuName  = NULL;
  2334.     wndClass.lpszClassName = WINDOW_CLASSNAME;
  2335.  
  2336.     RegisterClass(&wndClass);
  2337.  
  2338.     /*
  2339.      * Create the main window of the instance.
  2340.      */
  2341.     hwnd = CreateWindow(WINDOW_CLASSNAME,
  2342.                         WINDOW_TITLE,
  2343.                         WS_OVERLAPPED | WS_SYSMENU | WS_SIZEBOX,
  2344.                         CW_USEDEFAULT, CW_USEDEFAULT,
  2345.                         WINDOW_WIDTH, WINDOW_HEIGHT,
  2346.                         NULL,
  2347.                         NULL,
  2348.                         hInstance,
  2349.                         NULL);
  2350.  
  2351.     ShowWindow(hwnd, cmdShow);
  2352.     UpdateWindow(hwnd);
  2353.  
  2354.     /*
  2355.      * The main message dispatch loop.
  2356.      *
  2357.      * NOTE: For simplicity we handle the message loop with a
  2358.      * simple PeekMessage scheme. This might not be the best
  2359.      * mechanism for a real application (a separate render worker
  2360.      * thread might be better). 
  2361.      */
  2362.     while (TRUE)
  2363.     {
  2364.         if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
  2365.         {
  2366.             /*
  2367.              * Message pending. If its QUIT then exit the message
  2368.              * loop. Otherwise, process the message.
  2369.              */
  2370.             if (WM_QUIT == msg.message)
  2371.             {
  2372.                 break;
  2373.             }
  2374.             else
  2375.             {
  2376.                 TranslateMessage(&msg);
  2377.                 DispatchMessage(&msg);
  2378.             }
  2379.         }
  2380.         else
  2381.         {
  2382.             /*
  2383.              * Animate the scene.
  2384.              */
  2385.             OnIdle(hwnd);
  2386.         }
  2387.     }
  2388.  
  2389.     return msg.wParam;
  2390. }
  2391.  
  2392. /***********************************************************************/
  2393.  
  2394. /***********************************************************************
  2395.  *
  2396.  * End of file
  2397.  *
  2398.  ***********************************************************************/
  2399.