D3DEX2.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:73k
源码类别:

Windows编程

开发平台:

Visual C++

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