home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / atl / direct3d / d3dwnd.h < prev    next >
C/C++ Source or Header  |  1998-03-26  |  42KB  |  1,545 lines

  1. // D3DWnd.h : Declaration of CDirect3DWindow & CD3DMatrix
  2. //
  3. // This is a part of the Active Template Library.
  4. // Copyright (C) 1996-1998 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Active Template Library Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Active Template Library product.
  12.  
  13. #include <math.h>
  14. #include <ddraw.h>
  15. #include <d3d.h>
  16.  
  17. #include "resource.h"
  18.  
  19. /***********************************************************************
  20.  *
  21.  * Constants
  22.  *
  23.  ***********************************************************************/
  24.  
  25. /*
  26.  * Half height of the view window.
  27.  */
  28. #define HALF_HEIGHT           D3DVAL(0.5)
  29.  
  30. /*
  31.  * Front and back clipping planes.
  32.  */
  33. #define FRONT_CLIP            D3DVAL(1.0)
  34. #define BACK_CLIP             D3DVAL(1000.0)
  35.  
  36. #define MAX_DEVICE_NAME       256
  37. #define MAX_DEVICE_DESC       256
  38.  
  39. /*
  40.  * Amount to rotate per frame.
  41.  */
  42. #define M_PI                  3.14159265359
  43. #define M_2PI                 6.28318530718
  44. #define ROTATE_ANGLE_DELTA    (M_2PI / 150.0)
  45.  
  46. /*
  47.  * Execute buffer contents
  48.  */
  49. #define NUM_VERTICES          3UL
  50. #define NUM_INSTRUCTIONS      6UL
  51. #define NUM_STATES            8UL
  52. #define NUM_PROCESSVERTICES   1UL
  53. #define NUM_TRIANGLES         1UL
  54.  
  55. /***********************************************************************
  56.  *
  57.  * Macro funtions.
  58.  *
  59.  ***********************************************************************/
  60.  
  61. /*
  62.  * Extract the error code from an HRESULT
  63.  */
  64. #define CODEFROMHRESULT(hRes) ((hRes) & 0x0000FFFFUL)
  65.  
  66. /*
  67.  * Globals used for selecting the Direct3D device. They are
  68.  * globals as it makes it easy for the enumeration callback
  69.  * to read and write from them.
  70.  */
  71. extern BOOL          fDeviceFound;
  72. extern DWORD         dwDeviceBitDepth;
  73. extern GUID          guidDevice;
  74. extern char          szDeviceName[MAX_DEVICE_NAME];
  75. extern char          szDeviceDesc[MAX_DEVICE_DESC];
  76. extern D3DDEVICEDESC d3dHWDeviceDesc;
  77. extern D3DDEVICEDESC d3dSWDeviceDesc;
  78.  
  79. class CD3DMatrix : public _D3DMATRIX
  80. {
  81. public:
  82.     CD3DMatrix(
  83.         D3DVALUE v11, D3DVALUE v12, D3DVALUE v13, D3DVALUE v14,
  84.         D3DVALUE v21, D3DVALUE v22, D3DVALUE v23, D3DVALUE v24,
  85.         D3DVALUE v31, D3DVALUE v32, D3DVALUE v33, D3DVALUE v34,
  86.         D3DVALUE v41, D3DVALUE v42, D3DVALUE v43, D3DVALUE v44)
  87.     {
  88.         _11 = v11;
  89.         _12 = v12;
  90.         _13 = v13;
  91.         _14 = v14;
  92.         _21 = v21;
  93.         _22 = v22;
  94.         _23 = v23;
  95.         _24 = v24;
  96.         _31 = v31;
  97.         _32 = v32;
  98.         _33 = v33;
  99.         _34 = v34;
  100.         _41 = v41;
  101.         _42 = v42;
  102.         _43 = v43;
  103.         _44 = v44;
  104.     }
  105. };
  106.  
  107. class CDirect3DWindow
  108. {
  109. public:
  110.     CDirect3DWindow();
  111.  
  112.     ~CDirect3DWindow()
  113.     {
  114.         // Clean everything up.
  115.         ReleaseScene();
  116.         ReleaseDevice();
  117.         ReleasePrimary();
  118.         ReleaseDirect3D();
  119.     }
  120.  
  121.     void ReportError(HWND hwnd, LPSTR lpszMessage, HRESULT hRes)
  122.     {
  123.         TCHAR szBuffer[256];
  124.         TCHAR szError[128];
  125.         int  nStrID;
  126.  
  127.         // Turn the animation loop off.
  128.         m_bIsSuspended = TRUE;
  129.  
  130.         // We issue sensible error messages for common run time errors. For
  131.         // errors which are internal or coding errors we simply issue an
  132.         // error number (they should never occur).
  133.         switch (hRes)
  134.         {
  135.             case DDERR_EXCEPTION:        nStrID = IDS_ERR_EXCEPTION;        break;
  136.             case DDERR_GENERIC:          nStrID = IDS_ERR_GENERIC;          break;
  137.             case DDERR_OUTOFMEMORY:      nStrID = IDS_ERR_OUTOFMEMORY;      break;
  138.             case DDERR_OUTOFVIDEOMEMORY: nStrID = IDS_ERR_OUTOFVIDEOMEMORY; break;
  139.             case DDERR_SURFACEBUSY:      nStrID = IDS_ERR_SURFACEBUSY;      break;
  140.             case DDERR_SURFACELOST:      nStrID = IDS_ERR_SURFACELOST;      break;
  141.             case DDERR_WRONGMODE:        nStrID = IDS_ERR_WRONGMODE;        break;
  142.             default:                     nStrID = IDS_ERR_INTERNALERROR;    break;
  143.         }
  144.         LoadString(_Module.GetResourceInstance(), nStrID, szError, sizeof(szError));
  145.  
  146.         // Convert the error code into a string.
  147.         wsprintf(szBuffer, _T("%s\n%s (Error #%d)"), lpszMessage, szError, CODEFROMHRESULT(hRes));
  148.         MessageBox(hwnd, szBuffer, _T(""), MB_OK | MB_APPLMODAL);
  149.     }
  150.  
  151.     /***********************************************************************/
  152.  
  153.     void FatalError(HWND hwnd, LPSTR lpszMessage, HRESULT hRes)
  154.     {
  155.         // Report the error.
  156.         ReportError(hwnd, lpszMessage, hRes);
  157.  
  158.         // And shut down.
  159.         // NOTE: We don't attempt to clean up. That will be done
  160.         // in the destructor
  161.         m_bShuttingDown = TRUE;
  162.     }
  163.  
  164.     /***********************************************************************/
  165.  
  166.     DWORD BitDepthToFlags(DWORD dwBitDepth)
  167.     {
  168.         switch (dwBitDepth)
  169.         {
  170.             case  1UL: return DDBD_1;
  171.             case  2UL: return DDBD_2;
  172.             case  4UL: return DDBD_4;
  173.             case  8UL: return DDBD_8;
  174.             case 16UL: return DDBD_16;
  175.             case 24UL: return DDBD_24;
  176.             case 32UL: return DDBD_32;
  177.             default:   return 0UL;
  178.         }
  179.     }
  180.  
  181.     /***********************************************************************/
  182.  
  183.     /*
  184.      * Convert bit depth flags to an acutal bit count. Selects the smallest
  185.      * bit count in the mask if more than one flag is present.
  186.      */
  187.     DWORD FlagsToBitDepth(DWORD dwFlags)
  188.     {
  189.         if (dwFlags & DDBD_1)
  190.             return 1UL;
  191.         else if (dwFlags & DDBD_2)
  192.             return 2UL;
  193.         else if (dwFlags & DDBD_4)
  194.             return 4UL;
  195.         else if (dwFlags & DDBD_8)
  196.             return 8UL;
  197.         else if (dwFlags & DDBD_16)
  198.             return 16UL;
  199.         else if (dwFlags & DDBD_24)
  200.             return 24UL;
  201.         else if (dwFlags & DDBD_32)
  202.             return 32UL;
  203.         else
  204.             return 0UL; /* Oh, please... */
  205.     }
  206.  
  207.     /***********************************************************************/
  208.  
  209.     void SetPerspectiveProjection(LPD3DMATRIX lpd3dMatrix,
  210.                              double      dHalfHeight,
  211.                              double      dFrontClipping,
  212.                              double      dBackClipping)
  213.     {
  214.         double dTmp1;
  215.         double dTmp2;
  216.  
  217.         ATLASSERT(NULL != lpd3dMatrix);
  218.  
  219.         dTmp1 = dHalfHeight / dFrontClipping;
  220.         dTmp2 = dBackClipping / (dBackClipping - dFrontClipping);
  221.  
  222.         lpd3dMatrix->_11 =  D3DVAL(2.0);
  223.         lpd3dMatrix->_12 =  D3DVAL(0.0);
  224.         lpd3dMatrix->_13 =  D3DVAL(0.0);
  225.         lpd3dMatrix->_14 =  D3DVAL(0.0);
  226.         lpd3dMatrix->_21 =  D3DVAL(0.0);
  227.         lpd3dMatrix->_22 =  D3DVAL(2.0);
  228.         lpd3dMatrix->_23 =  D3DVAL(0.0);
  229.         lpd3dMatrix->_24 =  D3DVAL(0.0);
  230.         lpd3dMatrix->_31 =  D3DVAL(0.0);
  231.         lpd3dMatrix->_32 =  D3DVAL(0.0);
  232.         lpd3dMatrix->_33 =  D3DVAL(dTmp1 * dTmp2);
  233.         lpd3dMatrix->_34 =  D3DVAL(dTmp1);
  234.         lpd3dMatrix->_41 =  D3DVAL(0.0);
  235.         lpd3dMatrix->_42 =  D3DVAL(0.0);
  236.         lpd3dMatrix->_43 =  D3DVAL(-dHalfHeight * dTmp2);
  237.         lpd3dMatrix->_44 =  D3DVAL(0.0);
  238.     }
  239.  
  240.  
  241.     /***********************************************************************/
  242.  
  243.     void SetRotationAboutY(LPD3DMATRIX lpd3dMatrix, double dAngleOfRotation)
  244.     {
  245.         D3DVALUE dvCos;
  246.         D3DVALUE dvSin;
  247.  
  248.         ATLASSERT(NULL != lpd3dMatrix);
  249.  
  250.         dvCos = D3DVAL(cos(dAngleOfRotation));
  251.         dvSin = D3DVAL(sin(dAngleOfRotation));
  252.  
  253.         lpd3dMatrix->_11 =  dvCos;
  254.         lpd3dMatrix->_12 =  D3DVAL(0.0);
  255.         lpd3dMatrix->_13 = -dvSin;
  256.         lpd3dMatrix->_14 =  D3DVAL(0.0);
  257.         lpd3dMatrix->_21 =  D3DVAL(0.0);
  258.         lpd3dMatrix->_22 =  D3DVAL(1.0);
  259.         lpd3dMatrix->_23 =  D3DVAL(0.0);
  260.         lpd3dMatrix->_24 =  D3DVAL(0.0);
  261.         lpd3dMatrix->_31 =  dvSin;
  262.         lpd3dMatrix->_32 =  D3DVAL(0.0);
  263.         lpd3dMatrix->_33 =  dvCos;
  264.         lpd3dMatrix->_34 =  D3DVAL(0.0);
  265.         lpd3dMatrix->_41 =  D3DVAL(0.0);
  266.         lpd3dMatrix->_42 =  D3DVAL(0.0);
  267.         lpd3dMatrix->_43 =  D3DVAL(0.0);
  268.         lpd3dMatrix->_44 =  D3DVAL(1.0);
  269.     }
  270.  
  271.     /***********************************************************************/
  272.  
  273.     HRESULT CreateDirect3D(HWND hwnd)
  274.     {
  275.         HRESULT hRes;
  276.  
  277.         ATLASSERT(NULL == lpdd);
  278.         ATLASSERT(NULL == lpd3d);
  279.  
  280.         hRes = DirectDrawCreate(NULL, &lpdd, NULL);
  281.         if (FAILED(hRes))
  282.             return hRes;
  283.  
  284.         hRes = lpdd->SetCooperativeLevel(hwnd, DDSCL_NORMAL);
  285.         if (FAILED(hRes))
  286.             return hRes;
  287.  
  288.         hRes = lpdd->QueryInterface(IID_IDirect3D, (void**)&lpd3d);
  289.         if (FAILED(hRes))
  290.             return hRes;
  291.  
  292.         return DD_OK;
  293.     }
  294.  
  295.     /***********************************************************************/
  296.  
  297.     HRESULT ReleaseDirect3D(void)
  298.     {
  299.         if (NULL != lpd3d)
  300.         {
  301.             lpd3d->Release();
  302.             lpd3d = NULL;
  303.         }
  304.         if (NULL != lpdd)
  305.         {
  306.             lpdd->Release();
  307.             lpdd = NULL;
  308.         }
  309.  
  310.         return DD_OK;
  311.     }
  312.  
  313.     /***********************************************************************/
  314.  
  315.     HRESULT CreatePrimary(HWND hwnd)
  316.     {
  317.         HRESULT             hRes;
  318.         DDSURFACEDESC       ddsd;
  319.         LPDIRECTDRAWCLIPPER lpddClipper;
  320.         HDC                 hdc;
  321.         int                 i;
  322.         PALETTEENTRY        peColorTable[256];
  323.  
  324.         ATLASSERT(NULL != hwnd);
  325.         ATLASSERT(NULL != lpdd);
  326.         ATLASSERT(NULL == lpddPrimary);
  327.         ATLASSERT(NULL == lpddPalette);
  328.  
  329.         /*
  330.          * Create the primary surface.
  331.          */
  332.         ZeroMemory(&ddsd, sizeof(ddsd));
  333.         ddsd.dwSize         = sizeof(ddsd);
  334.         ddsd.dwFlags        = DDSD_CAPS;
  335.         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  336.         hRes = lpdd->CreateSurface(&ddsd, &lpddPrimary, NULL);
  337.         if (FAILED(hRes))
  338.             return hRes;
  339.  
  340.         /*
  341.          * Create the clipper. We bind the application's window to the
  342.          * clipper and attach it to the primary. This ensures then when we
  343.          * blit from the rendering surface to the primary we don't write
  344.          * outside the visible region of the window.
  345.          */
  346.         hRes = DirectDrawCreateClipper(0UL, &lpddClipper, NULL);
  347.         if (FAILED(hRes))
  348.             return hRes;
  349.         hRes = lpddClipper->SetHWnd(0UL, hwnd);
  350.         if (FAILED(hRes))
  351.         {
  352.             lpddClipper->Release();
  353.             return hRes;
  354.         }
  355.         hRes = lpddPrimary->SetClipper(lpddClipper);
  356.         if (FAILED(hRes))
  357.         {
  358.             lpddClipper->Release();
  359.             return hRes;
  360.         }
  361.  
  362.         /*
  363.          * We release the clipper interface after attaching it to the surface
  364.          * as we don't need to use it again and the surface holds a reference
  365.          * to the clipper when its been attached. The clipper will therefore
  366.          * be released when the surface is released.
  367.          */
  368.         lpddClipper->Release();
  369.  
  370.         /*
  371.          * If the primary is palettized then so will the rendering target (we
  372.          * ensure the rendering target has the same pixel format as the primary
  373.          * for optimal performance). Hence, if the primary is palettized we
  374.          * need to create a palette and attach it to the primary (and eventually
  375.          * to the rendering target).
  376.          *
  377.          * NOTE: We don't initialize the color table of the palette. We leave
  378.          * that upto Direct3D.
  379.          */
  380.         ZeroMemory(&ddsd, sizeof(ddsd));
  381.         ddsd.dwSize = sizeof(ddsd);
  382.         hRes = lpddPrimary->GetSurfaceDesc(&ddsd);
  383.         if (FAILED(hRes))
  384.             return hRes;
  385.         if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
  386.         {
  387.             /*
  388.              * The primary is palettized so create a palette and attach it to
  389.              * the primary.
  390.              */
  391.             hdc = GetDC(NULL);
  392.             GetSystemPaletteEntries(hdc, 0, 256, peColorTable);
  393.             ReleaseDC(NULL, hdc);
  394.             for (i = 0; i < 10; i++)
  395.                 peColorTable[i].peFlags = D3DPAL_READONLY;
  396.             for (i = 10; i < 246; i++)
  397.                 peColorTable[i].peFlags = D3DPAL_FREE | PC_RESERVED;
  398.             for (i = 246; i < 256; i++)
  399.                 peColorTable[i].peFlags = D3DPAL_READONLY;
  400.             hRes = lpdd->CreatePalette(DDPCAPS_8BIT,
  401.                                        peColorTable,
  402.                                        &lpddPalette,
  403.                                        NULL);
  404.             if (FAILED(hRes))
  405.                 return hRes;
  406.  
  407.             hRes = lpddPrimary->SetPalette(lpddPalette);
  408.                 return hRes;
  409.         }
  410.  
  411.         return DD_OK;
  412.     }
  413.  
  414.     /***********************************************************************/
  415.  
  416.     HRESULT RestorePrimary(void)
  417.     {
  418.         ATLASSERT(NULL != lpddPrimary);
  419.  
  420.         return lpddPrimary->Restore();
  421.     }
  422.  
  423.     /***********************************************************************/
  424.  
  425.     HRESULT ReleasePrimary(void)
  426.     {
  427.         if (NULL != lpddPalette)
  428.         {
  429.             lpddPalette->Release();
  430.             lpddPalette = NULL;
  431.         }
  432.         if (NULL != lpddPrimary)
  433.         {
  434.             lpddPrimary->Release();
  435.             lpddPrimary = NULL;
  436.         }
  437.  
  438.         return DD_OK;
  439.     }
  440.  
  441.     /***********************************************************************/
  442.  
  443.     static HRESULT WINAPI EnumDeviceCallback(
  444.                         LPGUID          lpGUID,
  445.                         LPSTR           lpszDeviceDesc,
  446.                         LPSTR           lpszDeviceName,
  447.                         LPD3DDEVICEDESC lpd3dHWDeviceDesc,
  448.                         LPD3DDEVICEDESC lpd3dSWDeviceDesc,
  449.                         LPVOID          /* lpUserArg */)
  450.     {
  451.         BOOL            fIsHardware;
  452.         LPD3DDEVICEDESC lpd3dDeviceDesc;
  453.  
  454.         /*
  455.          * If there is no hardware support then the color model is zero.
  456.          */
  457.         fIsHardware     = (0UL != lpd3dHWDeviceDesc->dcmColorModel);
  458.         lpd3dDeviceDesc = (fIsHardware ? lpd3dHWDeviceDesc : lpd3dSWDeviceDesc);
  459.  
  460.  
  461.         /*
  462.          * Does the device render at the depth we want?
  463.          */
  464.         if (0UL == (lpd3dDeviceDesc->dwDeviceRenderBitDepth & dwDeviceBitDepth))
  465.         {
  466.             /*
  467.              * No skip this device.
  468.              */
  469.             return D3DENUMRET_OK;
  470.         }
  471.  
  472.         /*
  473.          * The device must support gouraud shaded triangles.
  474.          */
  475.         if (D3DCOLOR_MONO == lpd3dDeviceDesc->dcmColorModel)
  476.         {
  477.             if (!(lpd3dDeviceDesc->dpcTriCaps.dwShadeCaps & D3DPSHADECAPS_COLORGOURAUDMONO))
  478.             {
  479.                 /*
  480.                  * No gouraud shading. Skip this device.
  481.                  */
  482.                 return D3DENUMRET_OK;
  483.             }
  484.         }
  485.         else
  486.         {
  487.             if (!(lpd3dDeviceDesc->dpcTriCaps.dwShadeCaps & D3DPSHADECAPS_COLORGOURAUDRGB))
  488.             {
  489.                 /*
  490.                  * No gouraud shading. Skip this device.
  491.                  */
  492.                 return D3DENUMRET_OK;
  493.             }
  494.         }
  495.  
  496.         if (!fIsHardware && fDeviceFound && (D3DCOLOR_RGB == lpd3dDeviceDesc->dcmColorModel))
  497.         {
  498.             /*
  499.              * If this is software RGB and we already have found a software
  500.              * mono already then we are not interested. Skip it.
  501.              */
  502.             return D3DENUMRET_OK;
  503.         }
  504.  
  505.         /*
  506.          * This is a device we are interested in. Cache its details away.
  507.          */
  508.         fDeviceFound = TRUE;
  509.         CopyMemory(&guidDevice, lpGUID, sizeof(GUID));
  510.         strcpy(szDeviceDesc, lpszDeviceDesc);
  511.         strcpy(szDeviceName, lpszDeviceName);
  512.         CopyMemory(&d3dHWDeviceDesc, lpd3dHWDeviceDesc, sizeof(D3DDEVICEDESC));
  513.         CopyMemory(&d3dSWDeviceDesc, lpd3dSWDeviceDesc, sizeof(D3DDEVICEDESC));
  514.  
  515.         /*
  516.          * If this is a hardware device we have found what we are looking
  517.          * for.
  518.          */
  519.         if (fIsHardware)
  520.             return D3DENUMRET_CANCEL;
  521.  
  522.         /*
  523.          * Keep going.
  524.          */
  525.         return D3DENUMRET_OK;
  526.     }
  527.  
  528.     /***********************************************************************/
  529.  
  530.     HRESULT ChooseDevice(void)
  531.     {
  532.         DDSURFACEDESC ddsd;
  533.         HRESULT       hRes;
  534.  
  535.         ATLASSERT(NULL != lpd3d);
  536.         ATLASSERT(NULL != lpddPrimary);
  537.  
  538.         /*
  539.          * As we are running in a window we will not be changing the screen
  540.          * depth and hence the pixel format of the rendering target must match
  541.          * the pixel format of the current primary. Therefore, we need to
  542.          * determine the pixel format of the primary.
  543.          */
  544.         ZeroMemory(&ddsd, sizeof(ddsd));
  545.         ddsd.dwSize = sizeof(ddsd);
  546.         hRes = lpddPrimary->GetSurfaceDesc(&ddsd);
  547.         if (FAILED(hRes))
  548.             return hRes;
  549.  
  550.         dwDeviceBitDepth = BitDepthToFlags(ddsd.ddpfPixelFormat.dwRGBBitCount);
  551.  
  552.         /*
  553.          * Now we will enumerate the devices and pick the best match. The
  554.          * criteria for selecting the device are pretty simple. They are
  555.          * as follows:
  556.          *
  557.          * 1) Discard any device which does not support rendering at the
  558.          *    primary's display depth.
  559.          * 2) Favour hardware rasterizers over software ones unless we
  560.          *    are debugging (fDebug == TRUE) in which case we always
  561.          *    pick a software device.
  562.          */
  563.         fDeviceFound = FALSE;
  564.         hRes = lpd3d->EnumDevices(EnumDeviceCallback, &fDeviceFound);
  565.         if (FAILED(hRes))
  566.             return hRes;
  567.  
  568.         if (!fDeviceFound)
  569.         {
  570.             /*
  571.              * No suitable device was found. We have not alternative but to
  572.              * fail creation entirely.
  573.              */
  574.             return DDERR_NOTFOUND;
  575.         }
  576.  
  577.         return DD_OK;
  578.     }
  579.  
  580.     /***********************************************************************/
  581.  
  582.     HRESULT CreateDevice(DWORD dwWidth, DWORD dwHeight)
  583.     {
  584.         LPD3DDEVICEDESC      lpd3dDeviceDesc;
  585.         DWORD                dwDeviceMemType;
  586.         DWORD                dwZBufferMemType;
  587.         DDSURFACEDESC        ddsd;
  588.         HRESULT              hRes;
  589.         DWORD                dwZBufferBitDepth;
  590.  
  591.         ATLASSERT(NULL != lpdd);
  592.         ATLASSERT(NULL != lpd3d);
  593.         ATLASSERT(NULL != lpddPrimary);
  594.         ATLASSERT(NULL == lpddDevice);
  595.  
  596.         /*
  597.          * The first step is to determine the kind of memory (system or
  598.          * video) from which the rendering target surface should be
  599.          * allocated.
  600.          */
  601.         if (0UL != d3dHWDeviceDesc.dcmColorModel)
  602.         {
  603.             lpd3dDeviceDesc = &d3dHWDeviceDesc;
  604.  
  605.             /*
  606.              * Device has a hardware rasterizer. Currently this means that
  607.              * the rendering target must be in video memory.
  608.              */
  609.             dwDeviceMemType  = DDSCAPS_VIDEOMEMORY;
  610.             dwZBufferMemType = DDSCAPS_VIDEOMEMORY;
  611.         }
  612.         else
  613.         {
  614.             lpd3dDeviceDesc = &d3dSWDeviceDesc;
  615.  
  616.             /*
  617.              * Device has a software rasterizer. We will let DirectDraw
  618.              * decide where the rendering target resides unless we are
  619.              * running in debug mode in which case we will force it into
  620.              * system memory. For a software rasterizer the z-buffer should
  621.              * always go into system memory. A z-buffer in video memory will
  622.              * kill performance.
  623.              */
  624.             dwDeviceMemType  = (m_bDebug ? DDSCAPS_SYSTEMMEMORY : 0UL);
  625.             dwZBufferMemType = DDSCAPS_SYSTEMMEMORY;
  626.         }
  627.  
  628.         /*
  629.          * Create the rendering target. The pixel format will be identical
  630.          * to the primary so we don't have to explicitly specify it. We do
  631.          * need to explicity specify the size, memory type and capabilities
  632.          * of the surface.
  633.          */
  634.         ZeroMemory(&ddsd, sizeof(ddsd));
  635.         ddsd.dwSize         = sizeof(ddsd);
  636.         ddsd.dwFlags        = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
  637.         ddsd.dwWidth        = dwWidth;
  638.         ddsd.dwHeight       = dwHeight;
  639.         ddsd.ddsCaps.dwCaps = DDSCAPS_3DDEVICE | DDSCAPS_OFFSCREENPLAIN | dwDeviceMemType;
  640.         hRes = lpdd->CreateSurface(&ddsd, &lpddDevice, NULL);
  641.         if (FAILED(hRes))
  642.             return hRes;
  643.  
  644.         /*
  645.          * If we have created a palette then we have already determined that
  646.          * the primary (and hence the rendering target) is palettized so
  647.          * attach the palette to the back buffer (its already attached to the
  648.          * front buffer).
  649.          */
  650.         if (NULL != lpddPalette)
  651.         {
  652.             hRes = lpddDevice->SetPalette(lpddPalette);
  653.             if (FAILED(hRes))
  654.                 return hRes;
  655.         }
  656.  
  657.         /*
  658.          * We now determine whether we need a z-buffer or not and if so
  659.          * its depth and the kind of memory from which the z-buffer should
  660.          * be allocated.
  661.          */
  662.         if (0UL != lpd3dDeviceDesc->dwDeviceZBufferBitDepth)
  663.         {
  664.             /*
  665.              * The device supports z-buffering. Determine the depth. We
  666.              * select the lowest supported z-buffer resolution to save
  667.              * memory. Accuracy is not too important for this demo.
  668.              */
  669.             dwZBufferBitDepth = FlagsToBitDepth(lpd3dDeviceDesc->dwDeviceZBufferBitDepth);
  670.  
  671.             /*
  672.              * Create the z-buffer.
  673.              */
  674.             ZeroMemory(&ddsd, sizeof(ddsd));
  675.             ddsd.dwSize            = sizeof(ddsd);
  676.             ddsd.dwFlags           = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_ZBUFFERBITDEPTH;
  677.             ddsd.ddsCaps.dwCaps    = DDSCAPS_ZBUFFER | dwZBufferMemType;
  678.             ddsd.dwWidth           = dwWidth;
  679.             ddsd.dwHeight          = dwHeight;
  680.             ddsd.dwZBufferBitDepth = dwZBufferBitDepth;
  681.             hRes = lpdd->CreateSurface(&ddsd, &lpddZBuffer, NULL);
  682.             if (FAILED(hRes))
  683.                 return hRes;
  684.  
  685.             /*
  686.              * Attach it to the rendering target.
  687.              */
  688.             hRes = lpddDevice->AddAttachedSurface(lpddZBuffer);
  689.             if (FAILED(hRes))
  690.                 return hRes;
  691.         }
  692.  
  693.         /*
  694.          * Now we can actually get the Direct3D device interface.
  695.          */
  696.         hRes = lpddDevice->QueryInterface(guidDevice, (void**)&lpd3dDevice);
  697.         if (FAILED(hRes))
  698.             return hRes;
  699.  
  700.         return DD_OK;
  701.     }
  702.  
  703.     /***********************************************************************/
  704.  
  705.     HRESULT RestoreDevice(void)
  706.     {
  707.         HRESULT hRes;
  708.  
  709.         ATLASSERT(NULL != lpddZBuffer);
  710.         ATLASSERT(NULL != lpddDevice);
  711.  
  712.         hRes = lpddZBuffer->Restore();
  713.         if (FAILED(hRes))
  714.             return hRes;
  715.  
  716.         hRes = lpddDevice->Restore();
  717.         if (FAILED(hRes))
  718.             return hRes;
  719.  
  720.         return DD_OK;
  721.     }
  722.  
  723.     /***********************************************************************/
  724.  
  725.     HRESULT ReleaseDevice(void)
  726.     {
  727.         if (NULL != lpd3dDevice)
  728.         {
  729.             lpd3dDevice->Release();
  730.             lpd3dDevice = NULL;
  731.         }
  732.         if (NULL != lpddZBuffer)
  733.         {
  734.             lpddZBuffer->Release();
  735.             lpddZBuffer = NULL;
  736.         }
  737.         if (NULL != lpddDevice)
  738.         {
  739.             lpddDevice->Release();
  740.             lpddDevice = NULL;
  741.         }
  742.  
  743.         return DD_OK;
  744.     }
  745.  
  746.     /***********************************************************************/
  747.  
  748.     HRESULT FillExecuteBuffer(void)
  749.     {
  750.         HRESULT              hRes;
  751.         D3DEXECUTEBUFFERDESC d3dExeBufDesc;
  752.         LPD3DVERTEX          lpVertex;
  753.         LPD3DINSTRUCTION     lpInstruction;
  754.         LPD3DPROCESSVERTICES lpProcessVertices;
  755.         LPD3DTRIANGLE        lpTriangle;
  756.         LPD3DSTATE           lpState;
  757.  
  758.         ATLASSERT(NULL != lpd3dExecuteBuffer);
  759.         ATLASSERT(0UL  != hd3dSurfaceMaterial);
  760.         ATLASSERT(0UL  != hd3dWorldMatrix);
  761.         ATLASSERT(0UL  != hd3dViewMatrix);
  762.         ATLASSERT(0UL  != hd3dProjMatrix);
  763.  
  764.         /*
  765.          * Lock the execute buffer.
  766.          */
  767.         ZeroMemory(&d3dExeBufDesc, sizeof(d3dExeBufDesc));
  768.         d3dExeBufDesc.dwSize = sizeof(d3dExeBufDesc);
  769.         hRes = lpd3dExecuteBuffer->Lock(&d3dExeBufDesc);
  770.         if (FAILED(hRes))
  771.             return hRes;
  772.  
  773.         lpVertex = (LPD3DVERTEX)d3dExeBufDesc.lpData;
  774.  
  775.         /*
  776.          * First vertex.
  777.          */
  778.         lpVertex->dvX  = D3DVAL( 0.0);
  779.         lpVertex->dvY  = D3DVAL( 1.0);
  780.         lpVertex->dvZ  = D3DVAL( 0.0);
  781.         lpVertex->dvNX = D3DVAL( 0.0);
  782.         lpVertex->dvNY = D3DVAL( 0.0);
  783.         lpVertex->dvNZ = D3DVAL(-1.0);
  784.         lpVertex->dvTU = D3DVAL( 0.0);
  785.         lpVertex->dvTV = D3DVAL( 1.0);
  786.         lpVertex++;
  787.  
  788.         /*
  789.          * Second vertex.
  790.          */
  791.         lpVertex->dvX  = D3DVAL(-1.0);
  792.         lpVertex->dvY  = D3DVAL(-1.0);
  793.         lpVertex->dvZ  = D3DVAL( 0.0); // -0.3
  794.         lpVertex->dvNX = D3DVAL( 0.0);
  795.         lpVertex->dvNY = D3DVAL( 0.0);
  796.         lpVertex->dvNZ = D3DVAL(-1.0);
  797.         lpVertex->dvTU = D3DVAL( 1.0);
  798.         lpVertex->dvTV = D3DVAL( 1.0);
  799.         lpVertex++;
  800.  
  801.         /*
  802.          * Third vertex.
  803.          */
  804.         lpVertex->dvX  = D3DVAL( 1.0);
  805.         lpVertex->dvY  = D3DVAL(-1.0);
  806.         lpVertex->dvZ  = D3DVAL( 0.0); // -0.3
  807.         lpVertex->dvNX = D3DVAL( 0.0);
  808.         lpVertex->dvNY = D3DVAL( 0.0);
  809.         lpVertex->dvNZ = D3DVAL(-1.0);
  810.         lpVertex->dvTU = D3DVAL( 1.0);
  811.         lpVertex->dvTV = D3DVAL( 0.0);
  812.         lpVertex++;
  813. #if 0
  814.         /*
  815.          * Fourth vertex.
  816.          */
  817.         lpVertex->dvX  = D3DVAL( 0.0);
  818.         lpVertex->dvY  = D3DVAL(-1.0);
  819.         lpVertex->dvZ  = D3DVAL( 1.044);
  820.         lpVertex->dvNX = D3DVAL( 0.0);
  821.         lpVertex->dvNY = D3DVAL( 0.0);
  822.         lpVertex->dvNZ = D3DVAL(-1.0);
  823.         lpVertex->dvTU = D3DVAL( 1.0);
  824.         lpVertex->dvTV = D3DVAL( 0.0);
  825.         lpVertex++;
  826. #endif
  827.         /*
  828.          * Transform state - world, view and projection.
  829.          */
  830.         lpInstruction = (LPD3DINSTRUCTION)lpVertex;
  831.         lpInstruction->bOpcode = D3DOP_STATETRANSFORM;
  832.         lpInstruction->bSize   = sizeof(D3DSTATE);
  833.         lpInstruction->wCount  = 3U;
  834.         lpInstruction++;
  835.         lpState = (LPD3DSTATE)lpInstruction;
  836.         lpState->dtstTransformStateType = D3DTRANSFORMSTATE_WORLD;
  837.         lpState->dwArg[0] = hd3dWorldMatrix;
  838.         lpState++;
  839.         lpState->dtstTransformStateType = D3DTRANSFORMSTATE_VIEW;
  840.         lpState->dwArg[0] = hd3dViewMatrix;
  841.         lpState++;
  842.         lpState->dtstTransformStateType = D3DTRANSFORMSTATE_PROJECTION;
  843.         lpState->dwArg[0] = hd3dProjMatrix;
  844.         lpState++;
  845.  
  846.         /*
  847.          * Lighting state.
  848.          */
  849.         lpInstruction = (LPD3DINSTRUCTION)lpState;
  850.         lpInstruction->bOpcode = D3DOP_STATELIGHT;
  851.         lpInstruction->bSize   = sizeof(D3DSTATE);
  852.         lpInstruction->wCount  = 2U;
  853.         lpInstruction++;
  854.         lpState = (LPD3DSTATE)lpInstruction;
  855.         lpState->dlstLightStateType = D3DLIGHTSTATE_MATERIAL;
  856.         lpState->dwArg[0] = hd3dSurfaceMaterial;
  857.         lpState++;
  858.         lpState->dlstLightStateType = D3DLIGHTSTATE_AMBIENT;
  859.         lpState->dwArg[0] = RGBA_MAKE(128, 128, 128, 128);
  860.         lpState++;
  861.  
  862.         /*
  863.          * Render state.
  864.          */
  865.         lpInstruction = (LPD3DINSTRUCTION)lpState;
  866.         lpInstruction->bOpcode = D3DOP_STATERENDER;
  867.         lpInstruction->bSize = sizeof(D3DSTATE);
  868.         lpInstruction->wCount = 3U;
  869.         lpInstruction++;
  870.         lpState = (LPD3DSTATE)lpInstruction;
  871.         lpState->drstRenderStateType = D3DRENDERSTATE_FILLMODE;
  872.         lpState->dwArg[0] = D3DFILL_SOLID;
  873.         lpState++;
  874.         lpState->drstRenderStateType = D3DRENDERSTATE_SHADEMODE;
  875.         lpState->dwArg[0] = D3DSHADE_GOURAUD;
  876.         lpState++;
  877.         lpState->drstRenderStateType = D3DRENDERSTATE_DITHERENABLE;
  878.         lpState->dwArg[0] = FALSE;
  879.         lpState++;
  880.  
  881.         lpInstruction = (LPD3DINSTRUCTION)lpState;
  882.         lpInstruction->bOpcode = D3DOP_PROCESSVERTICES;
  883.         lpInstruction->bSize   = sizeof(D3DPROCESSVERTICES);
  884.         lpInstruction->wCount  = 1U;
  885.         lpInstruction++;
  886.         lpProcessVertices = (LPD3DPROCESSVERTICES)lpInstruction;
  887.         lpProcessVertices->dwFlags    = D3DPROCESSVERTICES_TRANSFORMLIGHT;
  888.         lpProcessVertices->wStart     = 0U;
  889.         lpProcessVertices->wDest      = 0U;
  890.         lpProcessVertices->dwCount    = NUM_VERTICES;
  891.         lpProcessVertices->dwReserved = 0UL;
  892.         lpProcessVertices++;
  893.  
  894.         /*
  895.          * Triangle.
  896.          */
  897.         lpInstruction = (LPD3DINSTRUCTION)lpProcessVertices;
  898.         lpInstruction->bOpcode = D3DOP_TRIANGLE;
  899.         lpInstruction->bSize   = sizeof(D3DTRIANGLE);
  900.         lpInstruction->wCount  = NUM_TRIANGLES;
  901.         lpInstruction++;
  902.         lpTriangle = (LPD3DTRIANGLE)lpInstruction;
  903.         lpTriangle->wV1    = 2U;
  904.         lpTriangle->wV2    = 1U;
  905.         lpTriangle->wV3    = 0U;
  906.         lpTriangle->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
  907.         lpTriangle++;
  908. #if 0
  909.         lpTriangle->wV1    = 2U;
  910.         lpTriangle->wV2    = 0U;
  911.         lpTriangle->wV3    = 3U;
  912.         lpTriangle->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE || D3DTRIFLAG_EVEN;
  913.         lpTriangle++;
  914.  
  915.         lpTriangle->wV1    = 3U;
  916.         lpTriangle->wV2    = 0U;
  917.         lpTriangle->wV3    = 1U;
  918.         lpTriangle->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE || D3DTRIFLAG_ODD;
  919.         lpTriangle++;
  920. #endif
  921.         lpInstruction = (LPD3DINSTRUCTION)lpTriangle;
  922.         lpInstruction->bOpcode = D3DOP_EXIT;
  923.         lpInstruction->bSize   = 0UL;
  924.         lpInstruction->wCount  = 0U;
  925.  
  926.         /*
  927.          * Unlock the execute buffer.
  928.          */
  929.         lpd3dExecuteBuffer->Unlock();
  930.  
  931.         return DD_OK;
  932.     }
  933.  
  934.     /***********************************************************************/
  935.  
  936.     HRESULT CreateScene(void)
  937.     {
  938.         HRESULT              hRes;
  939.         D3DMATERIAL          d3dMaterial;
  940.         D3DLIGHT             d3dLight;
  941.         DWORD                dwVertexSize;
  942.         DWORD                dwInstructionSize;
  943.         DWORD                dwExecuteBufferSize;
  944.         D3DEXECUTEBUFFERDESC d3dExecuteBufferDesc;
  945.         D3DEXECUTEDATA       d3dExecuteData;
  946.  
  947.         ATLASSERT(NULL != lpd3d);
  948.         ATLASSERT(NULL != lpd3dDevice);
  949.         ATLASSERT(NULL == lpd3dViewport);
  950.         ATLASSERT(NULL == lpd3dMaterial);
  951.         ATLASSERT(NULL == lpd3dBackgroundMaterial);
  952.         ATLASSERT(NULL == lpd3dExecuteBuffer);
  953.         ATLASSERT(NULL == lpd3dLight);
  954.         ATLASSERT(0UL  == hd3dWorldMatrix);
  955.         ATLASSERT(0UL  == hd3dViewMatrix);
  956.         ATLASSERT(0UL  == hd3dProjMatrix);
  957.  
  958.         /*
  959.          * Create a light.
  960.          */
  961.         hRes = lpd3d->CreateLight(&lpd3dLight, NULL);
  962.         if (FAILED(hRes))
  963.             return hRes;
  964.  
  965.         ZeroMemory(&d3dLight, sizeof(d3dLight));
  966.         d3dLight.dwSize = sizeof(d3dLight);
  967.         d3dLight.dltType = D3DLIGHT_POINT;
  968.         d3dLight.dcvColor.dvR    = D3DVAL( 1.0);
  969.         d3dLight.dcvColor.dvG    = D3DVAL( 1.0);
  970.         d3dLight.dcvColor.dvB    = D3DVAL( 1.0);
  971.         d3dLight.dcvColor.dvA    = D3DVAL( 1.0);
  972.         d3dLight.dvPosition.dvX  = D3DVAL( 1.0);
  973.         d3dLight.dvPosition.dvY  = D3DVAL(-1.0);
  974.         d3dLight.dvPosition.dvZ  = D3DVAL(-1.0);
  975.         d3dLight.dvAttenuation0  = D3DVAL( 1.0);
  976.         d3dLight.dvAttenuation1  = D3DVAL( 0.1);
  977.         d3dLight.dvAttenuation2  = D3DVAL( 0.0);
  978.         hRes = lpd3dLight->SetLight(&d3dLight);
  979.         if (FAILED(hRes))
  980.             return hRes;
  981.  
  982.         /*
  983.          * Create the background material.
  984.          */
  985.         hRes = lpd3d->CreateMaterial(&lpd3dBackgroundMaterial, NULL);
  986.         if (FAILED(hRes))
  987.             return hRes;
  988.  
  989.         ZeroMemory(&d3dMaterial, sizeof(d3dMaterial));
  990.         d3dMaterial.dwSize = sizeof(d3dMaterial);
  991.         d3dMaterial.dcvDiffuse.r  = D3DVAL(0.0);
  992.         d3dMaterial.dcvDiffuse.g  = D3DVAL(0.0);
  993.         d3dMaterial.dcvDiffuse.b  = D3DVAL(0.0);
  994.         d3dMaterial.dcvAmbient.r  = D3DVAL(0.0);
  995.         d3dMaterial.dcvAmbient.g  = D3DVAL(0.0);
  996.         d3dMaterial.dcvAmbient.b  = D3DVAL(0.0);
  997.         d3dMaterial.dcvSpecular.r = D3DVAL(0.0);
  998.         d3dMaterial.dcvSpecular.g = D3DVAL(0.0);
  999.         d3dMaterial.dcvSpecular.b = D3DVAL(0.0);
  1000.         d3dMaterial.dvPower       = D3DVAL(0.0);
  1001.         d3dMaterial.dwRampSize    = 1UL;
  1002.  
  1003.         hRes = lpd3dBackgroundMaterial->SetMaterial(&d3dMaterial);
  1004.         if (FAILED(hRes))
  1005.             return hRes;
  1006.         hRes = lpd3dBackgroundMaterial->GetHandle(lpd3dDevice, &hd3dBackgroundMaterial);
  1007.         if (FAILED(hRes))
  1008.             return hRes;
  1009.  
  1010.         /*
  1011.          * Create the viewport.
  1012.          */
  1013.         hRes = lpd3d->CreateViewport(&lpd3dViewport, NULL);
  1014.         if (FAILED(hRes))
  1015.             return hRes;
  1016.         hRes = lpd3dDevice->AddViewport(lpd3dViewport);
  1017.         if (FAILED(hRes))
  1018.             return hRes;
  1019.         hRes = lpd3dViewport->SetBackground(hd3dBackgroundMaterial);
  1020.         if (FAILED(hRes))
  1021.             return hRes;
  1022.         hRes = lpd3dViewport->AddLight(lpd3dLight);
  1023.         if (FAILED(hRes))
  1024.             return hRes;
  1025.  
  1026.         /*
  1027.          * Create the matrices.
  1028.          */
  1029.         hRes = lpd3dDevice->CreateMatrix(&hd3dWorldMatrix);
  1030.         if (FAILED(hRes))
  1031.             return hRes;
  1032.         hRes = lpd3dDevice->SetMatrix(hd3dWorldMatrix, &d3dWorldMatrix);
  1033.         if (FAILED(hRes))
  1034.             return hRes;
  1035.         hRes = lpd3dDevice->CreateMatrix(&hd3dViewMatrix);
  1036.         if (FAILED(hRes))
  1037.             return hRes;
  1038.         hRes = lpd3dDevice->SetMatrix(hd3dViewMatrix, &d3dViewMatrix);
  1039.         if (FAILED(hRes))
  1040.             return hRes;
  1041.         hRes = lpd3dDevice->CreateMatrix(&hd3dProjMatrix);
  1042.         if (FAILED(hRes))
  1043.             return hRes;
  1044.         SetPerspectiveProjection(&d3dProjMatrix, HALF_HEIGHT, FRONT_CLIP, BACK_CLIP);
  1045.         hRes = lpd3dDevice->SetMatrix(hd3dProjMatrix, &d3dProjMatrix);
  1046.         if (FAILED(hRes))
  1047.             return hRes;
  1048.  
  1049.         /*
  1050.          * Create the material.
  1051.          */
  1052.         hRes = lpd3d->CreateMaterial(&lpd3dMaterial, NULL);
  1053.         if (FAILED(hRes))
  1054.             return hRes;
  1055.         ZeroMemory(&d3dMaterial, sizeof(d3dMaterial));
  1056.         d3dMaterial.dwSize = sizeof(d3dMaterial);
  1057.  
  1058.         /*
  1059.          * Base green with white specular.
  1060.          */
  1061.         d3dMaterial.dcvDiffuse.r  = D3DVAL(0.0);
  1062.         d3dMaterial.dcvDiffuse.g  = D3DVAL(1.0);
  1063.         d3dMaterial.dcvDiffuse.b  = D3DVAL(0.0);
  1064.         d3dMaterial.dcvAmbient.r  = D3DVAL(0.0);
  1065.         d3dMaterial.dcvAmbient.g  = D3DVAL(0.4);
  1066.         d3dMaterial.dcvAmbient.b  = D3DVAL(0.0);
  1067.         d3dMaterial.dcvSpecular.r = D3DVAL(1.0);
  1068.         d3dMaterial.dcvSpecular.g = D3DVAL(1.0);
  1069.         d3dMaterial.dcvSpecular.b = D3DVAL(1.0);
  1070.         d3dMaterial.dvPower       = D3DVAL(20.0);
  1071.         d3dMaterial.dwRampSize    = 256UL;
  1072.  
  1073.         hRes = lpd3dMaterial->SetMaterial(&d3dMaterial);
  1074.         if (FAILED(hRes))
  1075.             return hRes;
  1076.  
  1077.         hRes = lpd3dMaterial->GetHandle(lpd3dDevice, &hd3dSurfaceMaterial);
  1078.         if (FAILED(hRes))
  1079.             return hRes;
  1080.  
  1081.         /*
  1082.          * Build the execute buffer.
  1083.          */
  1084.         dwVertexSize        = (NUM_VERTICES        * sizeof(D3DVERTEX));
  1085.         dwInstructionSize   = (NUM_INSTRUCTIONS    * sizeof(D3DINSTRUCTION))     +
  1086.                               (NUM_STATES          * sizeof(D3DSTATE))           +
  1087.                               (NUM_PROCESSVERTICES * sizeof(D3DPROCESSVERTICES)) +
  1088.                               (NUM_TRIANGLES       * sizeof(D3DTRIANGLE));
  1089.         dwExecuteBufferSize = dwVertexSize + dwInstructionSize;
  1090.         ZeroMemory(&d3dExecuteBufferDesc, sizeof(d3dExecuteBufferDesc));
  1091.         d3dExecuteBufferDesc.dwSize       = sizeof(d3dExecuteBufferDesc);
  1092.         d3dExecuteBufferDesc.dwFlags      = D3DDEB_BUFSIZE;
  1093.         d3dExecuteBufferDesc.dwBufferSize = dwExecuteBufferSize;
  1094.         hRes = lpd3dDevice->CreateExecuteBuffer(&d3dExecuteBufferDesc,
  1095.                                                 &lpd3dExecuteBuffer,
  1096.                                                 NULL);
  1097.         if (FAILED(hRes))
  1098.             return hRes;
  1099.  
  1100.         hRes = FillExecuteBuffer();
  1101.         if (FAILED(hRes))
  1102.             return hRes;
  1103.  
  1104.         ZeroMemory(&d3dExecuteData, sizeof(d3dExecuteData));
  1105.         d3dExecuteData.dwSize = sizeof(d3dExecuteData);
  1106.         d3dExecuteData.dwVertexCount       = NUM_VERTICES;
  1107.         d3dExecuteData.dwInstructionOffset = dwVertexSize;
  1108.         d3dExecuteData.dwInstructionLength = dwInstructionSize;
  1109.         hRes = lpd3dExecuteBuffer->SetExecuteData(&d3dExecuteData);
  1110.         if (FAILED(hRes))
  1111.             return hRes;
  1112.  
  1113.         return DD_OK;
  1114.     }
  1115.  
  1116.     /***********************************************************************/
  1117.  
  1118.     HRESULT ReleaseScene(void)
  1119.     {
  1120.         if (NULL != lpd3dExecuteBuffer)
  1121.         {
  1122.             lpd3dExecuteBuffer->Release();
  1123.             lpd3dExecuteBuffer = NULL;
  1124.         }
  1125.         if (NULL != lpd3dBackgroundMaterial)
  1126.         {
  1127.             lpd3dBackgroundMaterial->Release();
  1128.             lpd3dBackgroundMaterial = NULL;
  1129.         }
  1130.         if (NULL != lpd3dMaterial)
  1131.         {
  1132.             lpd3dMaterial->Release();
  1133.             lpd3dMaterial = NULL;
  1134.         }
  1135.         if (0UL != hd3dWorldMatrix)
  1136.         {
  1137.             lpd3dDevice->DeleteMatrix(hd3dWorldMatrix);
  1138.             hd3dWorldMatrix = 0UL;
  1139.         }
  1140.         if (0UL != hd3dViewMatrix)
  1141.         {
  1142.             lpd3dDevice->DeleteMatrix(hd3dViewMatrix);
  1143.             hd3dViewMatrix = 0UL;
  1144.         }
  1145.         if (0UL != hd3dProjMatrix)
  1146.         {
  1147.             lpd3dDevice->DeleteMatrix(hd3dProjMatrix);
  1148.             hd3dProjMatrix = 0UL;
  1149.         }
  1150.         if (NULL != lpd3dLight)
  1151.         {
  1152.             lpd3dLight->Release();
  1153.             lpd3dLight = NULL;
  1154.         }
  1155.         if (NULL != lpd3dViewport)
  1156.         {
  1157.             lpd3dViewport->Release();
  1158.             lpd3dViewport = NULL;
  1159.         }
  1160.  
  1161.         return DD_OK;
  1162.     }
  1163.  
  1164.     /***********************************************************************/
  1165.  
  1166.     HRESULT TickScene(void)
  1167.     {
  1168.         HRESULT hRes;
  1169.  
  1170.         ATLASSERT(NULL != lpd3dDevice);
  1171.         ATLASSERT(0UL  != hd3dWorldMatrix);
  1172.  
  1173.         /*
  1174.          * We rotate the triangle by setting thr world transform to a
  1175.          * rotation matrix.
  1176.          */
  1177.         SetRotationAboutY(&d3dWorldMatrix, m_dAngleOfRotation);
  1178.         m_dAngleOfRotation += ROTATE_ANGLE_DELTA;
  1179.         hRes = lpd3dDevice->SetMatrix(hd3dWorldMatrix, &d3dWorldMatrix);
  1180.         if (FAILED(hRes))
  1181.             return hRes;
  1182.  
  1183.         return DD_OK;
  1184.     }
  1185.  
  1186.     /***********************************************************************/
  1187.  
  1188.     HRESULT UpdateViewport(void)
  1189.     {
  1190.         D3DVIEWPORT d3dViewport;
  1191.  
  1192.         ATLASSERT(NULL != lpd3dViewport);
  1193.  
  1194.         ZeroMemory(&d3dViewport, sizeof(d3dViewport));
  1195.         d3dViewport.dwSize   = sizeof(d3dViewport);
  1196.         d3dViewport.dwX      = 0UL;
  1197.         d3dViewport.dwY      = 0UL;
  1198.         d3dViewport.dwWidth  = (DWORD)m_rcSrc.right;
  1199.         d3dViewport.dwHeight = (DWORD)m_rcSrc.bottom;
  1200.         d3dViewport.dvScaleX = D3DVAL((float)d3dViewport.dwWidth / 2.0);
  1201.         d3dViewport.dvScaleY = D3DVAL((float)d3dViewport.dwHeight / 2.0);
  1202.         d3dViewport.dvMaxX   = D3DVAL(1.0);
  1203.         d3dViewport.dvMaxY   = D3DVAL(1.0);
  1204.         return lpd3dViewport->SetViewport(&d3dViewport);
  1205.     }
  1206.  
  1207.     /***********************************************************************/
  1208.  
  1209.     HRESULT RenderScene(void)
  1210.     {
  1211.         HRESULT hRes;
  1212.         D3DRECT d3dRect;
  1213.  
  1214.         ATLASSERT(NULL != lpd3dViewport);
  1215.         ATLASSERT(NULL != lpd3dDevice);
  1216.         ATLASSERT(NULL != lpd3dExecuteBuffer);
  1217.  
  1218.         /*
  1219.          * Clear both back and z-buffer.
  1220.          */
  1221.         d3dRect.lX1 = m_rcSrc.left;
  1222.         d3dRect.lX2 = m_rcSrc.right;
  1223.         d3dRect.lY1 = m_rcSrc.top;
  1224.         d3dRect.lY2 = m_rcSrc.bottom;
  1225.         hRes = lpd3dViewport->Clear(1UL,
  1226.                                     &d3dRect,
  1227.                                     D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
  1228.         if (FAILED(hRes))
  1229.             return hRes;
  1230.  
  1231.         /*
  1232.          * Start the scene.
  1233.          */
  1234.         hRes = lpd3dDevice->BeginScene();
  1235.         if (FAILED(hRes))
  1236.             return hRes;
  1237.  
  1238.         /*
  1239.          * Submit the execute buffer.
  1240.          */
  1241.         hRes = lpd3dDevice->Execute(lpd3dExecuteBuffer,
  1242.                                     lpd3dViewport,
  1243.                                     D3DEXECUTE_CLIPPED);
  1244.         if (FAILED(hRes))
  1245.         {
  1246.             lpd3dDevice->EndScene();
  1247.             return hRes;
  1248.         }
  1249.  
  1250.         /*
  1251.          * End the scene.
  1252.          */
  1253.         hRes = lpd3dDevice->EndScene();
  1254.         if (FAILED(hRes))
  1255.             return hRes;
  1256.  
  1257.         return DD_OK;
  1258.     }
  1259.  
  1260.     /***********************************************************************/
  1261.  
  1262.     HRESULT DoFrame(void)
  1263.     {
  1264.         HRESULT hRes;
  1265.  
  1266.         hRes = RenderScene();
  1267.         if (SUCCEEDED(hRes))
  1268.             hRes = PaintClient();
  1269.         while (DDERR_SURFACELOST == hRes)
  1270.         {
  1271.             hRes = RestoreSurfaces();
  1272.             if (SUCCEEDED(hRes))
  1273.                 hRes = RenderScene();
  1274.                 if (SUCCEEDED(hRes))
  1275.                     hRes = PaintClient();
  1276.         }
  1277.  
  1278.         return hRes;
  1279.     }
  1280.  
  1281.     /***********************************************************************/
  1282.  
  1283.     HRESULT PaintClient(void)
  1284.     {
  1285.         if ((NULL != lpddPrimary) && (NULL != lpddDevice))
  1286.         {
  1287.             return lpddPrimary->Blt(&m_rcDst,
  1288.                                    lpddDevice,
  1289.                                    &m_rcSrc,
  1290.                                    DDBLT_WAIT,
  1291.                                    NULL);
  1292.         }
  1293.         else
  1294.         {
  1295.             return DD_OK;
  1296.         }
  1297.     }
  1298.  
  1299.     /***********************************************************************/
  1300.  
  1301.     LRESULT RestoreSurfaces(void)
  1302.     {
  1303.         HRESULT hRes;
  1304.  
  1305.         hRes = RestorePrimary();
  1306.         if (FAILED(hRes))
  1307.             return hRes;
  1308.  
  1309.         hRes = RestoreDevice();
  1310.         if (FAILED(hRes))
  1311.             return hRes;
  1312.  
  1313.         return DD_OK;
  1314.     }
  1315.  
  1316.     /***********************************************************************/
  1317.  
  1318.     LRESULT OnCreate(HWND hwnd, const RECT& rcPos)
  1319.     {
  1320.         HRESULT hRes;
  1321.  
  1322.         // Store our initial position
  1323.         m_rcDst = rcPos;
  1324.  
  1325.         hRes = CreateDirect3D(hwnd);
  1326.         if (FAILED(hRes))
  1327.         {
  1328.             ReportError(hwnd, "Could not initialize DirectDraw and Direct3D", hRes);
  1329.             return -1L;
  1330.         }
  1331.  
  1332.         hRes = CreatePrimary(hwnd);
  1333.         if (FAILED(hRes))
  1334.         {
  1335.             ReportError(hwnd, "Could not create the primary surface", hRes);
  1336.             return -1L;
  1337.         }
  1338.  
  1339.         hRes = ChooseDevice();
  1340.         if (FAILED(hRes))
  1341.         {
  1342.             ReportError(hwnd, "Could not find a suitable Direct3D device", hRes);
  1343.             return -1L;
  1344.         }
  1345.  
  1346.         return 0L;
  1347.     }
  1348.  
  1349.     /***********************************************************************/
  1350.  
  1351.     LRESULT OnMove(HWND /* hwnd */, int x, int y)
  1352.     {
  1353.         int     xDelta;
  1354.         int     yDelta;
  1355.  
  1356.         /*
  1357.          * Don't bother doing any of this stuff if we are shutting down.
  1358.          */
  1359.         if (!m_bShuttingDown)
  1360.         {
  1361.             /*
  1362.              * Update the destination rectangle for the new client position.
  1363.              */
  1364.             xDelta = x - m_rcDst.left;
  1365.             yDelta = y - m_rcDst.top;
  1366.  
  1367.             m_rcDst.left   += xDelta;
  1368.             m_rcDst.top    += yDelta;
  1369.             m_rcDst.right  += xDelta;
  1370.             m_rcDst.bottom += yDelta;
  1371.         }
  1372.         return 0L;
  1373.     }
  1374.  
  1375.     /***********************************************************************/
  1376.  
  1377.     LRESULT OnSize(HWND hwnd, int w, int h)
  1378.     {
  1379.         HRESULT       hRes;
  1380.         DDSURFACEDESC ddsd;
  1381.  
  1382.         /*
  1383.          * Again no point in doing this stuff if we are in the process
  1384.          * of shutting down.
  1385.          */
  1386.         if (!m_bIsSuspended && !m_bShuttingDown)
  1387.         {
  1388.             m_rcDst.right  = m_rcDst.left + w;
  1389.             m_rcDst.bottom = m_rcDst.top  + h;
  1390.             m_rcSrc.top = 0;
  1391.             m_rcSrc.left    = 0;
  1392.             m_rcSrc.right  = w;
  1393.             m_rcSrc.bottom = h;
  1394.  
  1395.             if (NULL != lpd3dDevice)
  1396.             {
  1397.                 /*
  1398.                  * We already have a device. But is it big enough for the the
  1399.                  * new window client size?
  1400.                  */
  1401.                 ZeroMemory(&ddsd, sizeof(ddsd));
  1402.                 ddsd.dwSize = sizeof(ddsd);
  1403.                 hRes = lpddDevice->GetSurfaceDesc(&ddsd);
  1404.                 if (FAILED(hRes))
  1405.                 {
  1406.                     FatalError(hwnd, "Could not get the size of the 3D surface", hRes);
  1407.                     return 0L;
  1408.                 }
  1409.  
  1410.                 if ((w > (int)ddsd.dwWidth) || (h > (int)ddsd.dwHeight))
  1411.                 {
  1412.                     /*
  1413.                      * Nope, the device is too small. We need to shut it down
  1414.                      * and rebuild it.
  1415.                      */
  1416.                     ReleaseScene();
  1417.                     ReleaseDevice();
  1418.                 }
  1419.             }
  1420.  
  1421.             if (NULL == lpd3dDevice)
  1422.             {
  1423.                 /*
  1424.                  * No Direct3D device yet. This is either because this is the
  1425.                  * first time through the loop or because we discarded the
  1426.                  * existing device because it was not big enough for the new
  1427.                  * window client size.
  1428.                  */
  1429.                 hRes = CreateDevice((DWORD)w, (DWORD)h);
  1430.                 if (FAILED(hRes))
  1431.                 {
  1432.                     FatalError(hwnd, "Could not recreate the Direct3D device", hRes);
  1433.                     return 0L;
  1434.                 }
  1435.                 hRes = CreateScene();
  1436.                 if (FAILED(hRes))
  1437.                 {
  1438.                     FatalError(hwnd, "Could not recreate the 3D scene", hRes);
  1439.                     return 0L;
  1440.                 }
  1441.             }
  1442.  
  1443.             hRes = UpdateViewport();
  1444.             if (FAILED(hRes))
  1445.             {
  1446.                 FatalError(hwnd, "Could not update the 3D viewport", hRes);
  1447.                 return 0L;
  1448.             }
  1449.  
  1450. #if 0
  1451.             hRes = DoFrame();
  1452.             if (FAILED(hRes))
  1453.             {
  1454.                 FatalError(hwnd, "Could not show the 3D scene", hRes);
  1455.                 return 0L;
  1456.             }
  1457. #endif
  1458.         }
  1459.  
  1460.         return 0L;
  1461.     }
  1462.  
  1463.     /***********************************************************************/
  1464.  
  1465.     LRESULT OnPaint(HWND hwnd, HDC /* hdc */, LPPAINTSTRUCT /* lpps */)
  1466.     {
  1467.         HRESULT hRes;
  1468.  
  1469.         if (m_bIsActive && !m_bIsSuspended & !m_bShuttingDown)
  1470.         {
  1471.             hRes = DoFrame();
  1472.             if (FAILED(hRes))
  1473.             {
  1474.                 FatalError(hwnd, "Could not show the 3D scene", hRes);
  1475.                 return 0L;
  1476.             }
  1477.         }
  1478.  
  1479.         return 0L;
  1480.     }
  1481.  
  1482.     /***********************************************************************/
  1483.  
  1484.     LRESULT SetPalette()
  1485.     {
  1486.         if (m_bIsActive && !m_bIsSuspended && !m_bShuttingDown)
  1487.         {
  1488.             if (NULL != lpddPalette)
  1489.                 lpddPrimary->SetPalette(lpddPalette);
  1490.         }
  1491.  
  1492.         return 0L;
  1493.     }
  1494.  
  1495.     /***********************************************************************/
  1496.  
  1497. private:
  1498.     // DirectDraw interfaces
  1499.     LPDIRECTDRAW            lpdd;
  1500.     LPDIRECTDRAWSURFACE     lpddPrimary;
  1501.     LPDIRECTDRAWSURFACE     lpddDevice;
  1502.     LPDIRECTDRAWSURFACE     lpddZBuffer;
  1503.     LPDIRECTDRAWPALETTE     lpddPalette;
  1504.  
  1505.     // Direct3D interfaces
  1506.     LPDIRECT3D              lpd3d;
  1507.     LPDIRECT3DDEVICE        lpd3dDevice;
  1508.     LPDIRECT3DMATERIAL      lpd3dMaterial;
  1509.     LPDIRECT3DMATERIAL      lpd3dBackgroundMaterial;
  1510.     LPDIRECT3DVIEWPORT      lpd3dViewport;
  1511.     LPDIRECT3DLIGHT         lpd3dLight;
  1512.     LPDIRECT3DEXECUTEBUFFER lpd3dExecuteBuffer;
  1513.  
  1514.     // Direct3D handles
  1515.     D3DMATRIXHANDLE         hd3dWorldMatrix;
  1516.     D3DMATRIXHANDLE         hd3dViewMatrix;
  1517.     D3DMATRIXHANDLE         hd3dProjMatrix;
  1518.     D3DMATERIALHANDLE       hd3dSurfaceMaterial;
  1519.     D3DMATERIALHANDLE       hd3dBackgroundMaterial;
  1520.  
  1521.     // The screen coordinates of the client area of the window. This
  1522.     // rectangle defines the destination into which we blit to update
  1523.     // the client area of the window with the results of the 3D rendering.
  1524.     RECT m_rcDst;
  1525.  
  1526.     // This rectangle defines the portion of the rendering target surface
  1527.     // into which we render. The top left coordinates of this rectangle
  1528.     // are always zero and the right and bottom give the size of the
  1529.     // viewport.
  1530.     RECT m_rcSrc;
  1531.  
  1532.     BOOL m_bIsActive;
  1533.     BOOL m_bIsSuspended;
  1534.     BOOL m_bShuttingDown;
  1535.     BOOL m_bDebug;
  1536.  
  1537.     // Angle of rotation of the world matrix.
  1538.     double m_dAngleOfRotation;
  1539.  
  1540.     // Predefined transformations
  1541.     CD3DMatrix d3dWorldMatrix;
  1542.     CD3DMatrix d3dViewMatrix;
  1543.     CD3DMatrix d3dProjMatrix;
  1544. };
  1545.