home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / directx / pplane / d3dwin.cpp < prev    next >
C/C++ Source or Header  |  1997-07-14  |  58KB  |  2,397 lines

  1. /*
  2. **-----------------------------------------------------------------------------
  3. **  Name:       D3DWin.cpp
  4. **  Purpose:    Shows how to set up a windowed D3D framework
  5. **  Notes:
  6. **
  7. **    Basic Initialization proceeds as follows:
  8. **
  9. **    1.  Enumerate all Driver, modes, D3D devices (see DrvMgr.cpp for details)
  10. **    2.  Choose a starting driver, mode, D3D device
  11. **            - default driver = primary display driver (lpGuidDD = NULL)
  12. **            - default mode   = current desktop
  13. **            - default device = D3D device compatible with desktop mode
  14. **    3.  Validate driver, mode, D3D device
  15. **    4.  Create interfaces (from DD driver)
  16. **  5.  Set window (from associated window handle)
  17. **  6.  Create DD/D3D interfaces (lpDD, lpDD2, lpD3D)
  18. **  7.  Create Primary surface (primary palette, if necessary)
  19. **            - Attach a clipper to primary surface
  20. **  8.  Create Render surface 
  21. **            - Render surface (and associated Z-buffer)
  22. **            - D3D Device 
  23. **            - D3D Viewport
  24. **
  25. **  After initialization is complete, we have the
  26. **    following objects necessary for rendering:
  27. **
  28. **        lpDD2 - DirectDraw interface, used for creating texture surfaces
  29. **        lpD3D - Direct3D interface, used for creating materials, lights, viewports
  30. **        lpD3DDevice - D3D device (current material, current viewport, etc.)
  31. **        lpViewport - current viewport
  32. **        lpPrimary  - front buffer
  33. **        lpRender   - render target
  34. **
  35. **  Copyright (c) 1995 - 1997 by Microsoft, all rights reserved
  36. **-----------------------------------------------------------------------------
  37. */
  38.  
  39. /*
  40. **-----------------------------------------------------------------------------
  41. ** Includes
  42. **-----------------------------------------------------------------------------
  43. */
  44.  
  45. #include "D3DWin.h"
  46. #include "WinProc.h"
  47. #include "D3DScene.h"
  48. #include "Debug.h"
  49.  
  50.  
  51.  
  52. /*
  53. **-----------------------------------------------------------------------------
  54. **    D3DWindow Methods
  55. **-----------------------------------------------------------------------------
  56. */
  57.  
  58. /*
  59. **-----------------------------------------------------------------------------
  60. ** Name:    D3DWindow::D3DWindow
  61. ** Purpose: Default Constructor
  62. **-----------------------------------------------------------------------------
  63. */
  64.  
  65. D3DWindow::D3DWindow (void)
  66. {
  67.     ZeroMemory (this, sizeof(D3DWindow));
  68.     this->dwSize = sizeof(D3DWindow);
  69.  
  70.     // Default to creating a z-buffer
  71.     createZBufferOn ();    
  72. } // End D3DWindow::D3DWindow ()
  73.  
  74.  
  75.   
  76. /*
  77. **-----------------------------------------------------------------------------
  78. ** Name:    D3DWindow::~D3DWindow
  79. ** Purpose: Destructor
  80. **-----------------------------------------------------------------------------
  81. */
  82.  
  83. D3DWindow::~D3DWindow (void)
  84. {
  85.     // Destroy all objects
  86.     Fini ();
  87.  
  88.     // Mark all other pointers as invalid
  89.     // In case user tries to reuse this object incorrectly
  90.     lpCurrDriver = NULL;
  91.     lpCurrMode     = NULL;
  92.     lpCurrDevice = NULL;
  93.     hWindow         = NULL;
  94.     lpd3dScene     = NULL;
  95.  
  96. } // End D3DWindow::~D3DWindow
  97.  
  98.  
  99.  
  100. /*
  101. **-----------------------------------------------------------------------------
  102. ** Name:    D3DWindow::Create
  103. ** Purpose: Creates a D3DWindow 
  104. **
  105. ** Basic Algorithm:
  106. **    - Validate parameters
  107. **    - Choose (and validate choices) for driver, mode, device
  108. **    - Create Interfaces
  109. **    - Set Window
  110. **    - Create Primary surface (and palette)
  111. **    - Create Render surface (and D3D device)
  112. **-----------------------------------------------------------------------------
  113. */
  114.  
  115. HRESULT D3DWindow::Create (
  116.     HWND   hWnd,        /* In:  Window */
  117.     LPGUID lpGuidDD,    /* In:  Requested DirectDraw Device */
  118.     DWORD  dwW,            /* In:    Requested Mode */
  119.     DWORD  dwH,            
  120.     DWORD  dwBPP,
  121.     DWORD  dwRefresh,
  122.     LPGUID lpGuidD3D,    /* In:  Requested D3D device */
  123.     BOOL   fUseZBuffer, /* In:    Create Z-buffer */
  124.     LPRECT lprSurf)        /* In:  requested surface size (NULL => use client area) */
  125. {
  126.     HRESULT         hResult;
  127.  
  128.     // Check parameters
  129.     if ((! hWnd) || (! IsWindow (hWnd)))
  130.     {
  131.         REPORTERR (DDERR_INVALIDPARAMS);
  132.         return DDERR_INVALIDPARAMS;
  133.     }
  134.  
  135.     // Set Current Window
  136.     hWindow = hWnd;
  137.  
  138.     // Set Use Z-Buffer On/Off
  139.     if (fUseZBuffer)
  140.         createZBufferOn ();
  141.     else
  142.         createZBufferOff ();
  143.  
  144.     // Choose Default Driver, Mode, device 
  145.     hResult = ChooseDriverDefaults (lpGuidDD,
  146.                                     dwW, dwH, dwBPP, dwRefresh,
  147.                                     lpGuidD3D,
  148.                                     FALSE,
  149.                                     &lpCurrDriver,
  150.                                     &lpCurrMode,
  151.                                     &lpCurrDevice);
  152.     if (FAILED (hResult))
  153.         return hResult;
  154.     
  155.     // Create DD/D3D Interface objects
  156.     hResult = InitInterfaces ();
  157.     if (FAILED (hResult))
  158.         return hResult;
  159.  
  160.     // Attach window to DD interface
  161.     hResult = InitWindow ();
  162.     if (FAILED (hResult))
  163.         goto lblCLEANUP;
  164.  
  165.     // Create Primary Surface (and palette)
  166.     hResult = InitPrimary ();
  167.     if (FAILED (hResult))
  168.         goto lblCLEANUP;
  169.  
  170.     // Get initial surface size
  171.     if (lprSurf)
  172.         rSurf = *lprSurf;
  173.     else
  174.         GetClientRect (hWindow, &rSurf);
  175.  
  176.     // Create the Render Surface (and D3D Device)
  177.     hResult = InitRender ();
  178.     if (FAILED (hResult))
  179.         goto lblCLEANUP;
  180.  
  181.     // Notify the window of a successful initialization
  182.     SendMessage (hWindow, D3DWIN_INIT, 0, (LPARAM)(void *)this);
  183.  
  184.     // Success
  185.     return DD_OK;
  186.  
  187. lblCLEANUP:
  188.     // Cleanup
  189.     Fini ();
  190.  
  191.     return hResult;
  192. } // End D3DWindow::Create
  193.  
  194.  
  195.  
  196. /*
  197. **-----------------------------------------------------------------------------
  198. ** Name:    D3DWindow::Init
  199. ** Purpose: 
  200. **
  201. ** Basic Algorithm:
  202. **    - Validate driver, mode, device
  203. **    - Create Interfaces
  204. **    - Attach Window
  205. **    - Create Primary surface (and palette)
  206. **    - Create Render surface (and D3D device)
  207. **
  208. ** Notes:
  209. **        1.  Assumes that a valid window handle has already
  210. **            been associated with this D3DWindow
  211. **        2.  Assumes that driver, mode, device already choosen
  212. **            - however if not, reasonable defaults will be choosen
  213. **-----------------------------------------------------------------------------
  214. */
  215.  
  216. HRESULT D3DWindow::Init (void)
  217. {
  218.     HRESULT         hResult;
  219.  
  220.     // Check parameters
  221.     if ((! hWindow) || (! IsWindow (hWindow)))
  222.     {
  223.         // Error, we absolutely need a valid window
  224.         REPORTERR (DDERR_INVALIDPARAMS);
  225.         return DDERR_INVALIDPARAMS;
  226.     }
  227.  
  228.     // Validate Curr Driver, mode, device
  229.     hResult = ValidateDefaults ();
  230.     if (FAILED (hResult))
  231.         return hResult;
  232.  
  233.     // Create DD/D3D Interface objects
  234.     hResult = InitInterfaces ();
  235.     if (FAILED (hResult))
  236.         goto lblCLEANUP;
  237.  
  238.     // Attach the window to the DD interface
  239.     hResult = InitWindow ();
  240.     if (FAILED (hResult))
  241.         goto lblCLEANUP;
  242.  
  243.     // Create Primary Surface (and palette)
  244.     hResult = InitPrimary ();
  245.     if (FAILED (hResult))
  246.         goto lblCLEANUP;
  247.  
  248.     // Create Render surface (and D3D device)
  249.     hResult = InitRender ();
  250.     if (FAILED (hResult))
  251.         goto lblCLEANUP;
  252.  
  253.     // Notify the window of a successful initialization
  254.     SendMessage (hWindow, D3DWIN_INIT, 0, (LPARAM)(void *)this);
  255.  
  256.     // Success
  257.     return DD_OK;
  258.  
  259. lblCLEANUP:
  260.     // Cleanup
  261.     Fini ();
  262.     return hResult;
  263. } // End D3DWindow::Init
  264.  
  265.  
  266.  
  267. /*
  268. **-----------------------------------------------------------------------------
  269. ** Name:    D3DWindow::Fini
  270. ** Purpose: Destroys a D3DWindow
  271. **-----------------------------------------------------------------------------
  272. */
  273.  
  274. HRESULT D3DWindow::Fini (void)
  275. {
  276.     // Notify the window that we are cleaning up
  277.     SendMessage (hWindow, D3DWIN_FINI, 0, (LPARAM)(void *)this);
  278.  
  279.     // Cleanup
  280.     FiniRender ();
  281.     FiniPrimary ();
  282. //    FiniWindow ();
  283.     FiniInterfaces ();
  284.  
  285.     // Success
  286.     return DD_OK;
  287. } // End D3DWindow::Fini
  288.  
  289.  
  290.   
  291.   
  292. /*
  293. **-----------------------------------------------------------------------------
  294. ** Name:    D3DWindow::ValidateDefaults
  295. ** Purpose: Verify's current driver, mode, and device
  296. ** Notes:   
  297. **
  298. **    1.  Rather than fail completely, this will pick new defaults
  299. **      if the current defaults don't work.
  300. **
  301. **-----------------------------------------------------------------------------
  302. */
  303.  
  304. HRESULT D3DWindow::ValidateDefaults (void)
  305. {
  306.     LPGUID            lpGuidDD, lpGuidD3D;
  307.     HRESULT            hResult;
  308.     LPDDDrvInfo        lpDrvNew;
  309.     LPDDModeInfo    lpModeNew;
  310.     LPD3DDevInfo    lpDevNew;
  311.  
  312.     // Initialize Driver Manager, if necessary
  313.     if (! DDDrvMgr::isInitialized ())
  314.     {
  315.         hResult = DDDrvMgr::Init ();
  316.         if (FAILED (hResult))
  317.             return DDERR_INVALIDPARAMS;
  318.     }
  319.     
  320.     // Get DD Guid
  321.     if (lpCurrDriver)
  322.         lpGuidDD = lpCurrDriver->GetGuid ();
  323.     else
  324.         lpGuidDD = NULL;
  325.  
  326.     // Get D3D Guid
  327.     if (lpCurrDevice)
  328.         lpGuidD3D = &(lpCurrDevice->guid);
  329.     else
  330.         lpGuidD3D = NULL;
  331.  
  332.     // Get Driver corresponding to DD Guid
  333.     lpDrvNew = ValidateDriver (lpGuidDD);
  334.     if (! lpDrvNew)
  335.     {
  336.         // Error, invalid DD Guid
  337.         REPORTERR (DDERR_INVALIDPARAMS);
  338.         return DDERR_INVALIDPARAMS;
  339.     }
  340.  
  341.     // Get Desktop mode and compatible D3D device
  342.     if (! GetDesktopMode (lpDrvNew, lpGuidD3D, &lpModeNew, &lpDevNew))
  343.     {
  344.         REPORTERR (DDERR_GENERIC);
  345.         return DDERR_GENERIC;
  346.     }
  347.  
  348.     // Note:  Instead of complaining let's go ahead
  349.     //          and use the new defaults
  350.     // Save new defaults
  351.     lpCurrDriver = lpDrvNew;
  352.     lpCurrMode     = lpModeNew;
  353.     lpCurrDevice = lpDevNew;
  354.  
  355.     // Success
  356.     return DD_OK;
  357. } // End D3DWindow::ValidateDefaults
  358.  
  359.  
  360.   
  361. /*
  362. **-----------------------------------------------------------------------------
  363. ** Name:    D3DWindow::CreateInterfaces
  364. ** Purpose: Creates DD/D3D interfaces from specified Guid
  365. **-----------------------------------------------------------------------------
  366. */
  367.  
  368. HRESULT D3DWindow::CreateInterfaces (LPGUID lpDDGuid)
  369. {
  370.     LPDDDrvInfo lpDrvNew;
  371.     HRESULT        hResult;
  372.  
  373.     // Verify Guid
  374.     lpDrvNew = ValidateDriver (lpDDGuid);
  375.     if (! lpDrvNew)
  376.     {
  377.         REPORTERR (DDERR_GENERIC);
  378.         return DDERR_GENERIC;
  379.     }
  380.  
  381.     lpCurrDriver = lpDrvNew;
  382.  
  383.     hResult = D3DWindow::InitInterfaces ();
  384.     if (FAILED (hResult))
  385.         return hResult;
  386.  
  387.     // Success
  388.     return DD_OK;
  389. } // End D3DWindow::CreateInterfaces
  390.  
  391.   
  392.  
  393. /*
  394. **-----------------------------------------------------------------------------
  395. ** Name:    D3DWindow::InitInterfaces
  396. ** Purpose: Creates DD/D3D interfaces
  397. **-----------------------------------------------------------------------------
  398. */
  399.  
  400. HRESULT D3DWindow::InitInterfaces (void)
  401. {
  402.     HRESULT         hResult;
  403.     LPGUID          lpGuid;
  404.  
  405.     // Do we have a current DD Driver
  406.     if (! lpCurrDriver)
  407.     {
  408.         // Try to grab the Primary DD driver instead
  409.         lpCurrDriver = ValidateDriver (NULL);
  410.         if (! lpCurrDriver)
  411.         {
  412.             REPORTERR (DDERR_GENERIC);
  413.             return DDERR_GENERIC;
  414.         }
  415.     }
  416.  
  417.     // Get DD Guid
  418.     lpGuid = lpCurrDriver->GetGuid ();
  419.     
  420.     // Create DD interface
  421.     hResult = DirectDrawCreate (lpGuid, &lpDD, NULL);
  422.     if (FAILED (hResult))
  423.     {
  424.         // Error
  425.         REPORTERR (hResult);
  426.         goto lblERROR;
  427.     }
  428.  
  429.     // Get DD2 interface
  430.     hResult = lpDD->QueryInterface ((REFIID)IID_IDirectDraw2, (void **)&lpDD2);
  431.     if (FAILED (hResult))
  432.     {
  433.         // Error
  434.         REPORTERR (hResult);
  435.         goto lblERROR;
  436.     }
  437.  
  438.     // Get D3D interface
  439.     hResult = lpDD2->QueryInterface ((REFIID)IID_IDirect3D2, (void **)&lpD3D);
  440.     if (FAILED (hResult))
  441.     {
  442.         // Error
  443.         REPORTERR (hResult);
  444.         goto lblERROR;
  445.     }
  446.  
  447.     // Mark this stage as done
  448.     turnValidInterfaceOn ();
  449.  
  450.     // Success
  451.     return DD_OK;
  452.  
  453. lblERROR:
  454.     // Failure
  455.     FiniInterfaces ();
  456.  
  457.     return hResult;
  458. } // End InitInterfaces
  459.  
  460.  
  461.  
  462.   
  463. /*
  464. **-----------------------------------------------------------------------------
  465. ** Name:    D3DWindow::FiniInterfaces
  466. ** Purpose: Destroys DD/D3D interfaces
  467. **-----------------------------------------------------------------------------
  468. */
  469.  
  470. HRESULT D3DWindow::FiniInterfaces (void)
  471. {
  472.     // Mark this stage as invalid
  473.     turnValidInterfaceOff ();
  474.  
  475.     // Release Direct3D Interface
  476.     if (lpD3D)
  477.     {
  478.         lpD3D->Release ();
  479.         lpD3D = NULL;
  480.     }
  481.  
  482.     // Release DirectDraw2 Interface
  483.     if (lpDD2)
  484.     {
  485.         lpDD2->Release ();
  486.         lpDD2 = NULL;
  487.     }
  488.  
  489.     // Release DirectDraw Interface
  490.     if (lpDD)
  491.     {
  492.         lpDD->Release ();
  493.         lpDD = NULL;
  494.     }
  495.  
  496.     // Success
  497.     return DD_OK;
  498. } // End D3DWindow::FiniInterfaces
  499.  
  500.  
  501.  
  502. /*
  503. **-----------------------------------------------------------------------------
  504. **    Name:        D3DWindow::InitWindow
  505. **    Purpose:    Attaches Window to Direct Draw Interface
  506. **    Notes:        Assumes window handle already associated with this D3DWindow.
  507. **-----------------------------------------------------------------------------
  508. */
  509.  
  510. HRESULT D3DWindow::InitWindow (void)
  511. {
  512.     HRESULT hResult;
  513.     DWORD    dwFlags;
  514.  
  515.     // Check Initialization
  516.     if ((! hWindow) || (! IsWindow (hWindow)))
  517.     {
  518.         // Error, we have to have an associated window to continue
  519.         REPORTERR (DDERR_GENERIC);
  520.         return DDERR_GENERIC;
  521.     }
  522.  
  523.     // Get Cooperative Flags
  524.     dwFlags = DDSCL_NORMAL;
  525.  
  526.     // Set Cooperative Level
  527.     hResult = lpDD2->SetCooperativeLevel (hWindow, dwFlags);
  528.     if (FAILED (hResult))
  529.     {
  530.         // Error
  531.         REPORTERR (hResult);
  532.         return hResult;
  533.     }
  534.  
  535.     // Success
  536.     return DD_OK;
  537. } // End D3DWindow::InitWindow
  538.  
  539.  
  540.   
  541. /*
  542. **-----------------------------------------------------------------------------
  543. ** Name:    D3DWindow::FiniWindow
  544. ** Purpose: Cleanups window
  545. **-----------------------------------------------------------------------------
  546. */
  547.  
  548. HRESULT D3DWindow::FiniWindow (void)
  549. {
  550.     // Currently does nothing
  551.  
  552.     // Success
  553.     return DD_OK;
  554. } // End D3DWindow::FiniWindow
  555.  
  556.  
  557.   
  558. /*
  559. **-----------------------------------------------------------------------------
  560. **    Name:    D3DWindow::InitPrimary
  561. **    Purpose: Creates a primary surface
  562. **
  563. **    Basic Algorithm:
  564. **        1.  Create primary surface (from desktop mode)
  565. **        2.  Create and attach a clipper object
  566. **        3.  Create and attach a palette object, if desktop is palettized
  567. **-----------------------------------------------------------------------------
  568. */
  569.  
  570. HRESULT D3DWindow::InitPrimary (void)
  571. {
  572.     HRESULT                hResult;
  573.     DDSURFACEDESC        ddsd;
  574.     LPDIRECTDRAWCLIPPER lpddcClipper = NULL;    
  575.  
  576.     // Check Initialization
  577.     if ((! lpCurrMode) || (! lpDD2))
  578.     {
  579.         // Error
  580.         REPORTERR (DDERR_GENERIC);
  581.         return DDERR_GENERIC;
  582.     }
  583.  
  584.     // 
  585.     // Step 1.  Create Primary Surface
  586.     //
  587.  
  588.     // Note:  No need to fill in width, height, etc.
  589.     //        They system knows how to do it automatically
  590.     //          for a primary surface
  591.     ddsd.dwSize         = sizeof(ddsd);
  592.     ddsd.dwFlags        = DDSD_CAPS;
  593.     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  594.  
  595.     // Create Primary surface
  596.     hResult = lpDD2->CreateSurface (&ddsd, &lpddsPrimary, NULL);
  597.     if (FAILED (hResult))
  598.     {
  599.         // Error
  600.         REPORTERR (hResult);
  601.         return hResult;
  602.     }
  603.  
  604.  
  605.     // 
  606.     // Step 2.   Create and attach clipper
  607.     //
  608.     // Note:    This needs to be done to prevent drawing outside
  609.     //            of the windows current client area
  610.  
  611.     // Create Clipper object
  612.     hResult = DirectDrawCreateClipper (0L, &lpddcClipper, 0);
  613.     if (FAILED (hResult))
  614.     {
  615.         // Error
  616.         REPORTERR (hResult);
  617.         goto lblCLEANUP;
  618.     }
  619.     
  620.     // Attach window to clipper
  621.     hResult = lpddcClipper->SetHWnd (0L, hWindow);
  622.     if (FAILED (hResult))
  623.     {
  624.         // Error
  625.         REPORTERR (hResult);
  626.         goto lblCLEANUP;
  627.     }
  628.  
  629.     // Attach clipper to primary surface
  630.     hResult = lpddsPrimary->SetClipper (lpddcClipper);
  631.     if (FAILED (hResult))
  632.     {
  633.         // Error
  634.         REPORTERR (hResult);
  635.         goto lblCLEANUP;
  636.     }
  637.  
  638.     // Go ahead and release the clipper interface, 
  639.     // we don't need it anymore and it will be
  640.     // destroyed automatically with the surface
  641.     lpddcClipper->Release ();
  642.  
  643.     // Create and attach palette, if necessary
  644.     hResult = InitPalette ();
  645.     if (FAILED (hResult))
  646.         goto lblCLEANUP;
  647.  
  648.     // Mark as Valid
  649.     turnValidPrimaryOn ();
  650.  
  651.     // Success
  652.     return DD_OK;
  653.  
  654. lblCLEANUP:
  655.     // Failure
  656.  
  657.     // Cleanup before leaving
  658.     if (lpddcClipper)
  659.         lpddcClipper->Release ();
  660.     
  661.     FiniPrimary ();
  662.  
  663.     return hResult;
  664. } // End D3DWindow::InitPrimary
  665.  
  666.  
  667.  
  668. /*
  669. **-----------------------------------------------------------------------------
  670. ** Name:    D3DWindow::FiniPrimary
  671. ** Purpose: Destroys the Primary Surface
  672. **-----------------------------------------------------------------------------
  673. */
  674.  
  675. HRESULT D3DWindow::FiniPrimary (void)
  676. {
  677.     // Mark as Invalid
  678.     turnValidPrimaryOff ();
  679.  
  680.     // Cleanup palette
  681.     FiniPalette ();
  682.  
  683.     // Release Primary Surface Object
  684.     if (lpddsPrimary)
  685.     {
  686.         lpddsPrimary->Release ();
  687.         lpddsPrimary = NULL;
  688.     }
  689.  
  690.     // Success
  691.     return DD_OK;
  692. } // End D3DWindow::FiniPrimary
  693.  
  694.  
  695.  
  696. /*
  697. **-----------------------------------------------------------------------------
  698. ** Name:    D3DWindow::InitPalette
  699. ** Purpose: Creates a primary palette if necessary
  700. **-----------------------------------------------------------------------------
  701. */
  702.  
  703. HRESULT D3DWindow::InitPalette ()
  704. {
  705.     HRESULT             hResult;
  706.     HDC                 hdc;
  707.     DWORD               ii;
  708.     PALETTEENTRY        pePalette[256];
  709.     DWORD               cPal;
  710.     DWORD               cbSize;
  711.     DWORD               dwFlags;
  712.     DDSURFACEDESC       ddsd;
  713.  
  714.     // Destroy old palette
  715.     FiniPalette ();
  716.  
  717.     // Make sure we are properly intialized 
  718.     // for this to work
  719.     if ((! lpDD2) || (! lpddsPrimary))
  720.     {
  721.         // Error
  722.         REPORTERR (DDERR_GENERIC);
  723.         return DDERR_GENERIC;
  724.     }
  725.  
  726.     // Get primary surface caps
  727.     ZeroMemory(&ddsd, sizeof(ddsd));
  728.     ddsd.dwSize = sizeof(ddsd);
  729.     hResult = lpddsPrimary->GetSurfaceDesc(&ddsd);
  730.     if (FAILED (hResult))
  731.     {
  732.         // Error
  733.         REPORTERR (hResult);
  734.         return hResult;
  735.     }
  736.  
  737.     // Make sure it is a palettized surface
  738.     if (! isPalettized (&(ddsd.ddpfPixelFormat)))
  739.     {
  740.         // Success, primary isn't palettized
  741.         // So we don't need to create a palette
  742.         return DD_OK;
  743.     }
  744.  
  745.     // Create and save System palette
  746.     hdc = GetDC (NULL);
  747.     cPal = GetDeviceCaps (hdc, SIZEPALETTE);
  748.     if (cPal)
  749.     {
  750.         if (cPal > 256)
  751.             cPal = 256;
  752.  
  753.         // Get memory for palette entries
  754.         lppePalette = new PALETTEENTRY[cPal];
  755.         if (! lppePalette)
  756.         {
  757.             // Error, not enough memory
  758.             ReleaseDC (NULL, hdc);
  759.  
  760.             hResult = DDERR_OUTOFMEMORY;
  761.             REPORTERR (hResult);
  762.             goto lblCLEANUP;
  763.         }
  764.  
  765.         // Save system palette
  766.         GetSystemPaletteEntries (hdc, 0, cPal, lppePalette);
  767.  
  768.         // Copy system palette to temporary values
  769.         cbSize = cPal * sizeof (PALETTEENTRY);
  770.         CopyMemory (pePalette, lppePalette, cbSize);
  771.     }
  772.     ReleaseDC (NULL, hdc);
  773.  
  774.     if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED1)
  775.     {
  776.         dwFlags = DDPCAPS_1BIT;
  777.  
  778.         // Only 2 palette entries, we need them all
  779.         for (ii = 0; ii < 2; ii++)
  780.             pePalette[ii].peFlags = D3DPAL_FREE | PC_RESERVED;
  781.  
  782.     }
  783.     else if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED2)
  784.     {
  785.         // Only 4 palette entries, we need them all
  786.         for (ii = 0; ii < 4; ii++)
  787.             pePalette[ii].peFlags = D3DPAL_FREE | PC_RESERVED;
  788.  
  789.         dwFlags = DDPCAPS_2BIT;
  790.     }
  791.     else if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4)
  792.     {
  793.         // Only 16 palette entries, we will save black and white
  794.         // and keep the rest for ourselves.
  795.  
  796.         pePalette[0].peFlags = D3DPAL_READONLY;
  797.         pePalette[15].peFlags = D3DPAL_READONLY;
  798.  
  799.         for (ii = 1; ii < 15; ii++)
  800.             pePalette[ii].peFlags = D3DPAL_FREE | PC_RESERVED;
  801.  
  802.         dwFlags = DDPCAPS_4BIT;
  803.     }
  804.     else if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
  805.     {
  806.         // 256 palette entries, we can afford to be nice
  807.         // and save the first 10 and last 10 palette entries
  808.         // for system use 
  809.         for (ii = 0; ii < 10; ii++)
  810.         {
  811.             pePalette[ii].peFlags = D3DPAL_READONLY;
  812.             pePalette[246+ii].peFlags = D3DPAL_READONLY;
  813.         }
  814.  
  815.         for (ii = 10; ii < 246; ii++)
  816.             pePalette[ii].peFlags = D3DPAL_FREE | PC_RESERVED;
  817.  
  818.         dwFlags = DDPCAPS_8BIT;        
  819.     }
  820.     else
  821.     {
  822.         // Error, programming (unknown palette type)
  823.         hResult = DDERR_GENERIC;
  824.         REPORTERR (hResult);
  825.         goto lblCLEANUP;
  826.     }
  827.  
  828.     // Create Primary Palette
  829.     hResult = lpDD2->CreatePalette (dwFlags,
  830.                                     pePalette,
  831.                                     &lpddpPalette,
  832.                                     NULL);
  833.     if (FAILED (hResult))
  834.     {
  835.         // Error
  836.         REPORTERR (hResult);
  837.         goto lblCLEANUP;
  838.     }
  839.  
  840.     // Attach palette to primary surface
  841.     hResult = lpddsPrimary->SetPalette (lpddpPalette);
  842.     if (FAILED (hResult))
  843.     {
  844.         // Error
  845.         REPORTERR (hResult);
  846.         goto lblCLEANUP;
  847.     }
  848.  
  849.     // Success
  850.     return DD_OK;
  851.  
  852. lblCLEANUP:
  853.     // Cleanup before leaving
  854.     FiniPalette ();
  855.  
  856.     // Failure
  857.     return hResult;
  858. } // D3DWindow::InitPalette
  859.  
  860.  
  861.  
  862. /*
  863. **-----------------------------------------------------------------------------
  864. ** Name:    D3DWindow::FiniPalette
  865. ** Purpose: Destroys primary palette
  866. **-----------------------------------------------------------------------------
  867. */
  868.  
  869. HRESULT D3DWindow::FiniPalette (void)
  870. {
  871.     // Note:  Should we Detach Palette object from surfaces
  872.     // No way to do this that I know of...
  873.     
  874.     // Cleanup up DD Palette object
  875.     if (lpddpPalette)
  876.     {
  877.         lpddpPalette->Release ();
  878.         lpddpPalette = NULL;
  879.     }
  880.  
  881.     // Cleanup System Palette
  882.     if (lppePalette)
  883.     {
  884.         // Note:  Should we try and restore system palette here ?!?
  885.  
  886.         // Destroy system palette
  887.         delete [] lppePalette;
  888.         lppePalette = NULL;
  889.     }
  890.  
  891.     // Success
  892.     return DD_OK;
  893. } // End FiniPalette
  894.  
  895.  
  896.  
  897. /*
  898. **-----------------------------------------------------------------------------
  899. ** Name:    D3DWindow::ValidateSize
  900. ** Purpose: Validate Surface Size
  901. **-----------------------------------------------------------------------------
  902. */
  903.  
  904. HRESULT D3DWindow::ValidateSize (void)
  905. {
  906.     long x, y, w,h;
  907.     long wwMax, whMax;  // maximum windows width, height
  908.     long wwMin, whMin;  // minimum windows width, height
  909.  
  910.     // Get Min, max window sizes
  911.     wwMax = GetSystemMetrics (SM_CXMAXTRACK);
  912.     whMax = GetSystemMetrics (SM_CYMAXTRACK);
  913.     wwMin = GetSystemMetrics (SM_CXMIN);
  914.     whMin = GetSystemMetrics (SM_CYMIN);
  915.  
  916.     // Null Size => use client area of window for size
  917.     w = abs (rSurf.right - rSurf.left);
  918.     h = abs (rSurf.bottom - rSurf.top);
  919.     if ((w == 0) || (h == 0))
  920.     {
  921.         if ((! hWindow) || (! IsWindow (hWindow)))
  922.             return DDERR_GENERIC;
  923.  
  924.         GetClientRect (hWindow, &rSurf);
  925.     }
  926.  
  927.     // Get canonical pos, size
  928.     if (rSurf.right < rSurf.left)
  929.     {
  930.         x = rSurf.right;
  931.         w = rSurf.left - rSurf.right;
  932.     }
  933.     else
  934.     {
  935.         x = rSurf.left;
  936.         w = rSurf.right - rSurf.left;
  937.     }
  938.     
  939.     if (rSurf.bottom < rSurf.top)
  940.     {
  941.         y = rSurf.bottom;
  942.         h = rSurf.top - rSurf.bottom;
  943.     }
  944.     else
  945.     {
  946.         y = rSurf.top;
  947.         h = rSurf.bottom - rSurf.top;
  948.     }
  949.  
  950.  
  951.     // Clamp to min,max sizes
  952.     if (w < D3DWIN_MIN_SIZE)
  953.         w = D3DWIN_MIN_SIZE;
  954.     if (w < wwMin)
  955.         w = wwMin;
  956.     if (w > wwMax)
  957.         w = wwMax;
  958.  
  959.     if (h < D3DWIN_MIN_SIZE)
  960.         h = D3DWIN_MIN_SIZE;
  961.     if (h < whMin)
  962.         h = whMin;
  963.     if (h > whMax)
  964.         h = whMax;
  965.  
  966.     // Save validated surface
  967.     rSurf.left   = x;
  968.     rSurf.right  = x + w;
  969.     rSurf.top    = y;
  970.     rSurf.bottom = y + h;
  971.  
  972.     // Success
  973.     return DD_OK;
  974. } // End D3DWindow::ValidateSize
  975.  
  976.  
  977.     
  978. /*
  979. **-----------------------------------------------------------------------------
  980. ** Name:    D3DWindow::CreateRender
  981. ** Purpose: Creates the rendering surface from requested device and 
  982. **            surface size
  983. **-----------------------------------------------------------------------------
  984. */
  985.  
  986. HRESULT D3DWindow::CreateRender (LPGUID lpD3DGuid, LPRECT lprSurf)
  987. {
  988.     HRESULT         hResult;
  989.     LPD3DDevInfo lpDevNew;
  990.  
  991.     // Check Initialization
  992.     if ((! lpCurrDriver) || (! lpCurrMode))
  993.     {
  994.         REPORTERR (DDERR_GENERIC);
  995.         return DDERR_GENERIC;
  996.     }
  997.  
  998.     // Make sure this D3D device works with this mode
  999.     lpDevNew = ValidateDevice (lpCurrDriver, lpD3DGuid, lpCurrMode);
  1000.     if (! lpDevNew)
  1001.     {
  1002.         REPORTERR (DDERR_INVALIDPARAMS);
  1003.         return DDERR_INVALIDPARAMS;
  1004.     }
  1005.     // Save new D3D device
  1006.     lpCurrDevice = lpDevNew;
  1007.  
  1008.  
  1009.     // Get Surface Size
  1010.     if (! lprSurf)
  1011.         GetClientRect (hWindow, &rSurf);
  1012.     else
  1013.         rSurf = *lprSurf;
  1014.  
  1015.     // Cleanup old render surface
  1016.     FiniRender ();
  1017.  
  1018.     // Create new Render surface (using new Device)
  1019.     hResult = InitRender ();
  1020.     if (FAILED (hResult))
  1021.         return hResult;
  1022.  
  1023.     // Success
  1024.     return DD_OK;
  1025. }
  1026.  
  1027.  
  1028.  
  1029. /*
  1030. **-----------------------------------------------------------------------------
  1031. ** Name:    D3DWindow::InitRender
  1032. ** Purpose: Creates the rendering surface and D3D device
  1033. ** Notes:
  1034. **
  1035. **    1. The main problem here is a catch 22 situation.  In order to create the
  1036. **       D3D device you need a valid render surface.   However, in order to create
  1037. **     a render surface properly, you need to know some D3D device caps 
  1038. **            - Does the device support Z-buffers
  1039. **            - Video vs. System memory
  1040. **            - etc.
  1041. **
  1042. **       Fortunately, our Driver Manager already has all that information.
  1043. **       So we can break the catch 22.  Without having to resort to some extra
  1044. **     complexity in the code here.
  1045. **        
  1046. ** 
  1047. ** Basic Algorithm:
  1048. **
  1049. **  1. Validate Device
  1050. **  2. Validate Surface size
  1051. **  3. Setup Surface Desc (width, height, bpp)
  1052. **    4. Create Render Surface (from surface desc)
  1053. **  5. Create Z-buffer (optional)
  1054. **    6. Create D3D Device
  1055. **    7. Create Viewport
  1056. **    8. InitScene (optional)
  1057. **
  1058. **-----------------------------------------------------------------------------
  1059. */
  1060.  
  1061. HRESULT D3DWindow::InitRender (void)
  1062. {
  1063.     HRESULT         hResult;
  1064.     DWORD           dwMemType;
  1065.     LPD3DDEVICEDESC lpDeviceDesc;
  1066.     DDSURFACEDESC   ddsd;
  1067.     DWORD           dwWidth, dwHeight, dwBPP;
  1068.     LPGUID            lpGuidD3D;
  1069.     LPD3DDevInfo    lpDevNew;
  1070.  
  1071.     // Check Initialization
  1072.     if ((! hWindow) || (! IsWindow (hWindow)) ||
  1073.         (! lpCurrDevice) || (! lpCurrMode) || 
  1074.         (! lpDD2) || (! lpD3D) || (! lpddsPrimary))
  1075.     {
  1076.         // Error, Not initialized properly
  1077.         REPORTERR (DDERR_GENERIC);
  1078.         return DDERR_GENERIC;
  1079.     }
  1080.  
  1081.     
  1082.     //
  1083.     // Step 1.  Validate Device
  1084.     //
  1085.     if (lpCurrDevice)
  1086.         lpGuidD3D = &(lpCurrDevice->guid);
  1087.     else
  1088.         lpGuidD3D = NULL;
  1089.  
  1090.     lpDevNew = ValidateDevice (lpCurrDriver, lpGuidD3D, lpCurrMode);
  1091.     if (! lpDevNew)
  1092.     {
  1093.         REPORTERR (DDERR_GENERIC);
  1094.         return DDERR_GENERIC;
  1095.     }
  1096.  
  1097.     // Save new D3D device
  1098.     lpCurrDevice = lpDevNew;
  1099.  
  1100.  
  1101.     // 
  1102.     // Step 2. Validate Surface size
  1103.     //
  1104.     hResult = ValidateSize ();
  1105.     if (FAILED (hResult))
  1106.         return hResult;
  1107.  
  1108.     dwWidth     = rSurf.right - rSurf.left;
  1109.     dwHeight = rSurf.bottom - rSurf.top;
  1110.  
  1111.  
  1112.     //
  1113.     // Step 3.  Setup DD surface desc (width, height, BPP)
  1114.     //
  1115.  
  1116.     // Get Memory Type
  1117.     if (lpCurrDevice->isHardware ())
  1118.     {
  1119.         // Hardware device
  1120.         dwMemType = DDSCAPS_VIDEOMEMORY;
  1121.         lpDeviceDesc = &(lpCurrDevice->d3dHalDesc);
  1122.     }
  1123.     else
  1124.     {
  1125.         // Software device 
  1126.         // Note:  It doesn't have to be in system memory but
  1127.         //        it makes debugging a lot easier 
  1128.         //          (Win16locks don't get in the way)
  1129.         dwMemType = DDSCAPS_SYSTEMMEMORY;
  1130.         lpDeviceDesc = &(lpCurrDevice->d3dHelDesc);
  1131.     }
  1132.  
  1133.     // Get primary surface caps
  1134.     ZeroMemory(&ddsd, sizeof(ddsd));
  1135.     ddsd.dwSize = sizeof (DDSURFACEDESC);
  1136.     hResult = lpddsPrimary->GetSurfaceDesc (&ddsd);
  1137.     if (FAILED (hResult))
  1138.     {
  1139.       // Error
  1140.       REPORTERR (hResult);
  1141.       return hResult;
  1142.     }
  1143.  
  1144.     // Create device surface
  1145.     // Note: We don't need to specify the pixel format, it will
  1146.     //       automatically default to same format as primary
  1147.     ddsd.dwSize         = sizeof(ddsd);
  1148.     ddsd.dwFlags        = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;// | DDSD_PIXELFORMAT;
  1149.     ddsd.dwWidth        = dwWidth;
  1150.     ddsd.dwHeight       = dwHeight;
  1151.     ddsd.ddsCaps.dwCaps = DDSCAPS_3DDEVICE | DDSCAPS_OFFSCREENPLAIN | dwMemType;
  1152.  
  1153.  
  1154.     // 
  1155.     // Step 2.  Create Rendering Surface (from dd surface desc)
  1156.     //
  1157.     hResult = lpDD2->CreateSurface (&ddsd, &lpddsRender, NULL);
  1158.     if (FAILED(hResult))
  1159.     {
  1160.         REPORTERR (hResult);
  1161.         return hResult;
  1162.     }
  1163.  
  1164.     // Attach palette, if any
  1165.     if (NULL != lpddpPalette)
  1166.     {
  1167.         hResult = lpddsRender->SetPalette (lpddpPalette);
  1168.         if (FAILED (hResult))
  1169.         {
  1170.             // Error
  1171.             REPORTERR (hResult);
  1172.             return hResult;
  1173.         }
  1174.     }
  1175.  
  1176.  
  1177.     //
  1178.     // Step 3.    Create and attach Z-buffer (optional)
  1179.     //
  1180.     if ((isCreateZBuffer ()) && 
  1181.         (0L != lpDeviceDesc->dwDeviceZBufferBitDepth))
  1182.     {
  1183.         dwBPP = FlagsToBitDepth (lpDeviceDesc->dwDeviceZBufferBitDepth);
  1184.  
  1185.         // Create the z-buffer.
  1186.         ZeroMemory (&ddsd, sizeof(ddsd));
  1187.         ddsd.dwSize            = sizeof(ddsd);
  1188.         ddsd.dwFlags           = DDSD_CAPS   |
  1189.                                  DDSD_WIDTH  |
  1190.                                  DDSD_HEIGHT |
  1191.                                  DDSD_ZBUFFERBITDEPTH;
  1192.         ddsd.ddsCaps.dwCaps    = DDSCAPS_ZBUFFER | dwMemType;
  1193.         ddsd.dwWidth           = dwWidth;
  1194.         ddsd.dwHeight          = dwHeight;
  1195.         ddsd.dwZBufferBitDepth = dwBPP;
  1196.         hResult = lpDD2->CreateSurface (&ddsd, &lpddsZBuff, NULL);
  1197.         if (FAILED(hResult))
  1198.         {
  1199.             // Note: we may be able to continue without a z buffer
  1200.             REPORTERR (hResult);
  1201.         }
  1202.         else
  1203.         {
  1204.             // Attach Z-buffer to rendering surface
  1205.             hResult = lpddsRender->AddAttachedSurface (lpddsZBuff);
  1206.             if (FAILED (hResult))
  1207.             {
  1208.                 // Note: we may be able to continue without a z buffer
  1209.                 REPORTERR (hResult);
  1210.                 if (lpddsZBuff)
  1211.                 {
  1212.                     lpddsZBuff->Release ();
  1213.                     lpddsZBuff = NULL;
  1214.                 }
  1215.             }
  1216.         }
  1217.     }
  1218.  
  1219.  
  1220.     //
  1221.     // Step 4.  Create the D3D device interface
  1222.     //
  1223.     hResult = lpD3D->CreateDevice (lpCurrDevice->guid,
  1224.                                     lpddsRender, 
  1225.                                     &lpd3dDevice);
  1226.     if (FAILED (hResult))
  1227.     {
  1228.         REPORTERR (hResult);
  1229.         return hResult;
  1230.     }
  1231.  
  1232.  
  1233.     //
  1234.     // Step 5.  Create the viewport
  1235.     //
  1236.     hResult = InitViewport ();
  1237.     if (FAILED (hResult))
  1238.         return hResult;
  1239.  
  1240.     // Mark as valid
  1241.     turnValidRenderOn ();
  1242.     turnCalcRectsOn ();
  1243.  
  1244.     
  1245.     // 
  1246.     // Step 6.    Initialize Scene (if attached)
  1247.     //
  1248.     if (lpd3dScene)
  1249.     {
  1250.         hResult = lpd3dScene->Init (this);
  1251.         if (FAILED (hResult))
  1252.             return hResult;
  1253.     }
  1254.  
  1255.     // Success
  1256.     return DD_OK;
  1257. } // End D3DWindow::InitRender
  1258.  
  1259.  
  1260.  
  1261. /*
  1262. **-----------------------------------------------------------------------------
  1263. ** Name:    D3DWindow::FiniRender
  1264. ** Purpose: Destroys the Rendering surface
  1265. **-----------------------------------------------------------------------------
  1266. */
  1267.  
  1268. HRESULT D3DWindow::FiniRender (void)
  1269. {
  1270.     // Mark as invalid
  1271.     turnValidRenderOff ();
  1272.  
  1273.     // Cleanup Associated Scene
  1274.     if (lpd3dScene)
  1275.     {
  1276.         lpd3dScene->Fini ();
  1277.     }
  1278.  
  1279.     // Cleanup viewport
  1280.     FiniViewport ();
  1281.  
  1282.     // Release D3D Device
  1283.     if (lpd3dDevice)
  1284.     {
  1285.         lpd3dDevice->Release ();
  1286.         lpd3dDevice = NULL;
  1287.     }
  1288.  
  1289.     // Release Z Buffer
  1290.     if (lpddsZBuff)
  1291.     {
  1292.         // Detach Z-Buffer from back buffer
  1293.         if (lpddsRender)
  1294.             lpddsRender->DeleteAttachedSurface (0L, lpddsZBuff);
  1295.         lpddsZBuff->Release ();
  1296.         lpddsZBuff = NULL;
  1297.     }
  1298.  
  1299.     // Release rendering surface
  1300.     if (lpddsRender)
  1301.     {
  1302.         lpddsRender->Release ();
  1303.         lpddsRender = NULL;
  1304.     }
  1305.  
  1306.     // Success
  1307.     return DD_OK;
  1308. } // End D3DWindow::FiniRender
  1309.  
  1310.  
  1311.  
  1312. /*
  1313. **-----------------------------------------------------------------------------
  1314. **  Name:       D3DWindow::InitViewport
  1315. **  Purpose:    
  1316. **-----------------------------------------------------------------------------
  1317. */
  1318.  
  1319. HRESULT D3DWindow::InitViewport (void)
  1320. {
  1321.     HRESULT hResult;
  1322.  
  1323.     // Check Initialization
  1324.     if ((! lpD3D) || (! lpd3dDevice))
  1325.     {
  1326.         REPORTERR (DDERR_GENERIC);
  1327.         return DDERR_GENERIC;
  1328.     }
  1329.  
  1330.     // Create Viewport
  1331.     hResult = lpD3D->CreateViewport (&lpd3dViewport, NULL);
  1332.     if (FAILED (hResult))
  1333.     {
  1334.         REPORTERR (hResult);
  1335.         return hResult;
  1336.     }
  1337.  
  1338.     // Attach viewport to D3D device
  1339.     hResult = lpd3dDevice->AddViewport (lpd3dViewport);
  1340.     if (FAILED (hResult))
  1341.     {
  1342.         REPORTERR (hResult);
  1343.         return hResult;
  1344.     }
  1345.  
  1346.     // Set up Initial Viewport parameters
  1347.     hResult = UpdateViewport ();
  1348.     if (FAILED (hResult))
  1349.         return hResult;
  1350.  
  1351.     /// Success
  1352.     return DD_OK;
  1353. } // End D3DWindow::InitViewport
  1354.   
  1355.  
  1356.  
  1357. /*
  1358. **-----------------------------------------------------------------------------
  1359. **  Name:       D3DWindow::FiniViewport
  1360. **  Purpose:    Cleanup viewport
  1361. **-----------------------------------------------------------------------------
  1362. */
  1363.  
  1364. HRESULT D3DWindow::FiniViewport (void)
  1365. {
  1366.     // Release D3D viewport
  1367.     if (lpd3dViewport)
  1368.     {
  1369.         lpd3dViewport->Release ();
  1370.         lpd3dViewport  = NULL;
  1371.     }
  1372.  
  1373.     // Success
  1374.     return DD_OK;
  1375. } // End D3DWindow::FiniViewport
  1376.  
  1377.   
  1378.  
  1379. /*
  1380. **-----------------------------------------------------------------------------
  1381. **  Name:       D3DWindow::UpdateViewport
  1382. **  Purpose:    Keeps viewport updated with current window size
  1383. **  Notes:        
  1384. **
  1385. **    1. The viewport construction here assumes that you are rendering 
  1386. **        Triangles using the D3DVERTEX and D3DIM is doing Transform,
  1387. **        lighting, and rasterization for you.
  1388. **
  1389. **    2. If you are rendering triangles using D3DTLVERTEX and doing your
  1390. **       own transform and lighting then you need to setup the viewport
  1391. **       differently.   As follows:
  1392. **
  1393. **      // Replace the following values below:
  1394. **        dvClipX            = 0.0f;
  1395. **        dvClipY            = 0.0f;
  1396. **        dvClipWidth        = dwSurfW;
  1397. **        dvClipHeight    = dvSurfH;
  1398. **
  1399. **  3. This perserves the aspect ratio.  If you don't need or want to
  1400. **     perserve the aspect ratio then set inv_aspect = 1.0 below and
  1401. **     work this constant through the rest of the viewport setup.
  1402. **
  1403. **-----------------------------------------------------------------------------
  1404. */
  1405.  
  1406. HRESULT D3DWindow::UpdateViewport (void)
  1407. {
  1408.     HRESULT            hResult;
  1409.     D3DVIEWPORT2    d3dViewport;
  1410.     DWORD            dwSurfW, dwSurfH;
  1411.  
  1412.     // Check Parameters
  1413.     if ((! lpd3dDevice) || (! lpd3dViewport))
  1414.     {
  1415.         // Not properly initialized.
  1416.         REPORTERR (DDERR_GENERIC);
  1417.         return DDERR_GENERIC;
  1418.     }
  1419.  
  1420.     // Get Surface Width and Height
  1421.     dwSurfW = abs (rSurf.right - rSurf.left);
  1422.     dwSurfH = abs (rSurf.bottom - rSurf.top);
  1423.  
  1424.     float inv_aspect;
  1425.     
  1426.     if (dwSurfW)
  1427.         inv_aspect = (float)dwSurfH/(float)dwSurfW;
  1428.     else
  1429.                 inv_aspect = 1.0f;
  1430.  
  1431.     // Update Viewport
  1432.     ZeroMemory (&d3dViewport, sizeof(d3dViewport));
  1433.     d3dViewport.dwSize        = sizeof(d3dViewport);     // Always set size of structure!!!
  1434.     d3dViewport.dwX            = 0UL;
  1435.     d3dViewport.dwY            = 0UL;
  1436.     d3dViewport.dwWidth        = dwSurfW;
  1437.     d3dViewport.dwHeight    = dwSurfH;
  1438.     d3dViewport.dvClipX        = -1.0f;
  1439.     d3dViewport.dvClipY        = inv_aspect;
  1440.     d3dViewport.dvClipWidth    = 2.0f;
  1441.     d3dViewport.dvClipHeight = 2.0f * inv_aspect;
  1442.     d3dViewport.dvMinZ        = 0.0f;
  1443.     d3dViewport.dvMaxZ        = 1.0f;
  1444.  
  1445.     // Update Viewport
  1446.     hResult = lpd3dViewport->SetViewport2 (&d3dViewport);
  1447.     if (FAILED (hResult))
  1448.     {
  1449.         REPORTERR (hResult);
  1450.         return hResult;
  1451.     }
  1452.  
  1453.     // Update D3D device to use this viewport
  1454.     hResult = lpd3dDevice->SetCurrentViewport (lpd3dViewport);
  1455.     if (FAILED (hResult))
  1456.     {
  1457.         REPORTERR (hResult);
  1458.         return hResult;
  1459.     }
  1460.  
  1461.     // Success
  1462.     return DD_OK;
  1463. } // End D3DWindow::UpdateViewport
  1464.  
  1465.   
  1466.  
  1467. /*
  1468. **-----------------------------------------------------------------------------
  1469. ** Name:    D3DWindow::DrawFrame
  1470. ** Purpose: Paints current surface to window
  1471. **-----------------------------------------------------------------------------
  1472. */
  1473.  
  1474. HRESULT D3DWindow::DrawFrame (void)
  1475. {
  1476.     HRESULT hResult = DD_OK;
  1477.  
  1478.     // Check Initialization
  1479.     if (! isValid ())
  1480.     {
  1481.         // Error, not properly initialized
  1482.         return DDERR_GENERIC;
  1483.     }
  1484.  
  1485.     if (isPaused ())
  1486.     {
  1487.         // Don't draw, if paused
  1488.         return DD_OK;
  1489.     }
  1490.  
  1491.     // Double check parameters
  1492.     if ((! lpddsPrimary) || (! lpddsRender))
  1493.     {
  1494.         // Error, not properly initialized
  1495.         return DDERR_GENERIC;
  1496.     }
  1497.     
  1498.     // Get current src, dest rectangles
  1499.     CalcRects ();
  1500.  
  1501.     if (! checkPaint ())
  1502.     {
  1503.         // Nothing to draw, so return immediately
  1504.         return DD_OK;
  1505.     }
  1506.  
  1507.     // Paint until we truly succeed or error out
  1508.     while (TRUE)
  1509.     {
  1510.         // Render D3D Scene
  1511.         if (lpd3dScene)
  1512.             hResult = lpd3dScene->Render ();
  1513.  
  1514.         if (SUCCEEDED (hResult))
  1515.         {
  1516.             // Blt Rendering surface onto primary surface
  1517.             hResult = lpddsPrimary->Blt (&rDrawDest,    // Dest Rect
  1518.                                          lpddsRender,   // Src Surface
  1519.                                          &rDrawSrc,     // Src Rect
  1520.                                          DDBLT_WAIT,    // Wait
  1521.                                          NULL);         // Blt Special Effects (none)
  1522.  
  1523.             // Did it work ?!?  
  1524.             if (SUCCEEDED (hResult))
  1525.             {
  1526.                 // Success, exit
  1527.                 return hResult;
  1528.             }
  1529.         }
  1530.  
  1531.         // Check if busy or drawing
  1532.         if ((DDERR_SURFACEBUSY == hResult) ||
  1533.             (DDERR_WASSTILLDRAWING == hResult))
  1534.         {
  1535.             // Try again
  1536.             continue;
  1537.         }
  1538.  
  1539.         // Check for lost surfaces
  1540.         while (DDERR_SURFACELOST == hResult)
  1541.         {
  1542.             // Restore surfaces
  1543.             hResult = Restore ();
  1544.         }
  1545.  
  1546.         // Check for real error
  1547.         if (FAILED (hResult))
  1548.         {
  1549.             // Error,
  1550.             REPORTERR (hResult);
  1551.             return hResult;
  1552.         }
  1553.     }
  1554.  
  1555.     // Success
  1556.     return DD_OK;
  1557. } // End D3DWindow::DrawFrame
  1558.  
  1559.  
  1560.  
  1561. /*
  1562. **-----------------------------------------------------------------------------
  1563. ** Name:    D3DWindow::Move
  1564. ** Purpose: Move window to new coordinates
  1565. ** Notes:   This used to be simpler. (See CalcRects)
  1566. **-----------------------------------------------------------------------------
  1567. */
  1568.  
  1569. HRESULT D3DWindow::Move (long x, long y)
  1570. {
  1571.     // Need to recalculate src, dest rectangles
  1572.     turnCalcRectsOn ();
  1573.  
  1574.     // Success
  1575.     return DD_OK;
  1576. } // D3DWindow::Move
  1577.  
  1578.  
  1579.  
  1580. /*
  1581. **-----------------------------------------------------------------------------
  1582. ** Name:    D3DWindow::Resize
  1583. ** Purpose: Resizes the Window
  1584. ** Notes:
  1585. **        We need to resize the render surface to stay in sync
  1586. **        with the new window size
  1587. **-----------------------------------------------------------------------------
  1588. */
  1589.  
  1590. HRESULT D3DWindow::Resize (DWORD dwWidth, DWORD dwHeight)
  1591. {
  1592.     HRESULT                hResult;
  1593.     RECT                rSurfOld;
  1594.  
  1595.     // Need to recalculate src, dest rectangles 
  1596.     turnCalcRectsOn ();
  1597.  
  1598.     // Save old Surface coordinates
  1599.     rSurfOld = rSurf;
  1600.  
  1601.     // Update the surface rectangle
  1602.     rSurf.left   = 0;
  1603.     rSurf.top    = 0;
  1604.     rSurf.right  = dwWidth;
  1605.     rSurf.bottom = dwHeight;
  1606.  
  1607.     // Check if properly initialized
  1608.     if (! isValid ())
  1609.     {
  1610.         // Try to re-initialize
  1611.         Fini ();
  1612.         hResult = Init ();
  1613.         if (FAILED (hResult))
  1614.             return hResult;
  1615.  
  1616.         // Successful re-initialization
  1617.         return DD_OK;
  1618.     }
  1619.  
  1620.     // Cleanup Render Surface (and D3D Device)
  1621.     FiniRender ();
  1622.  
  1623.     // Re-create Render Surface (at new size)
  1624.     hResult = InitRender ();
  1625.     if (FAILED (hResult))
  1626.     {
  1627.         if ((hResult == DDERR_OUTOFMEMORY) || 
  1628.             (hResult == DDERR_OUTOFVIDEOMEMORY))
  1629.         {
  1630.             // Try to restore old surface size
  1631.             rSurf = rSurfOld;
  1632.  
  1633.             FiniRender ();
  1634.             hResult = InitRender ();
  1635.             if (FAILED (hResult))
  1636.                 return hResult;
  1637.  
  1638.             // Successfully returned to previous size
  1639.             return DD_OK;
  1640.         }
  1641.  
  1642.         return hResult;
  1643.     }
  1644.  
  1645.     // Success
  1646.     return DD_OK;
  1647. } // End D3DWindow::Resize 
  1648.  
  1649.  
  1650.  
  1651. /*
  1652. **-----------------------------------------------------------------------------
  1653. **  Name:       D3DWindow::RealizePalette
  1654. **  Purpose:    
  1655. **-----------------------------------------------------------------------------
  1656. */
  1657.  
  1658. HRESULT D3DWindow::RealizePalette (void)
  1659. {
  1660.     HRESULT hResult;
  1661.  
  1662.     //
  1663.     // Realizing the palette using DirectDraw is quite different
  1664.     // from GDI. To realize the palette we call SetPalette()
  1665.     // each time our application is activated.
  1666.     //
  1667.     // NOTE: DirectDraw spots the fact that the new palette is the
  1668.     // same as the old one and so does not increase the reference
  1669.     // count of the palette.
  1670.     //
  1671.  
  1672.     if ((lpddsPrimary) && (lpddpPalette))
  1673.     {
  1674.         hResult = lpddsPrimary->SetPalette (lpddpPalette);
  1675.         if (FAILED (hResult))
  1676.         {
  1677.             REPORTERR (hResult);
  1678.             return hResult;
  1679.         }
  1680.     }
  1681.  
  1682.     // Success
  1683.     return DD_OK;
  1684. } // End D3DWindow::RealizePalette
  1685.  
  1686.  
  1687.  
  1688. /*
  1689. **-----------------------------------------------------------------------------
  1690. ** Name:    D3DWindow::Pause
  1691. ** Purpose: Pause any work on DD/D3D resources
  1692. **-----------------------------------------------------------------------------
  1693. */
  1694.  
  1695. HRESULT D3DWindow::Pause (BOOL fPause)
  1696. {
  1697.     // Turning pausing on/off ?!?
  1698.     if (fPause)
  1699.     {
  1700.         if (dwPaused == 0L)
  1701.         {
  1702.             // Very first time paused, do anything special here...
  1703.  
  1704.             // Force screen redraw
  1705.             if (hWindow)
  1706.                 InvalidateRect (hWindow, NULL, FALSE);
  1707.         }
  1708.         dwPaused++;
  1709.     }
  1710.     else
  1711.     {
  1712.         if (dwPaused == 0L)
  1713.         {
  1714.             // Programmer Error, already paused
  1715.             REPORTERR (DDERR_GENERIC);
  1716.             return DDERR_GENERIC;
  1717.         }
  1718.  
  1719.         // Decrement semaphore
  1720.         dwPaused--;
  1721.         if (dwPaused == 0L)
  1722.         {
  1723.             // Very last time unpaused, do anything special here...
  1724.  
  1725.             // Force screen redraw
  1726.             if (hWindow)
  1727.                 InvalidateRect (hWindow, NULL, FALSE);
  1728.         }
  1729.     }
  1730.  
  1731.     // Success
  1732.     return DD_OK;
  1733. } // D3DWindow::Pause
  1734.  
  1735.  
  1736.  
  1737. /*
  1738. **-----------------------------------------------------------------------------
  1739. ** Name:    D3DWindow::AttachScene
  1740. ** Purpose: 
  1741. **-----------------------------------------------------------------------------
  1742. */
  1743.  
  1744. HRESULT D3DWindow::AttachScene (LPD3DScene lpNewScene)
  1745. {
  1746.     // Check parameters
  1747.     if (! lpNewScene)
  1748.     {
  1749.         return DDERR_INVALIDPARAMS;
  1750.     }
  1751.  
  1752.     DetachScene ();
  1753.  
  1754.     // Save Scene pointer
  1755.     lpd3dScene = lpNewScene;
  1756.  
  1757.     // Initialize Scene ?!?
  1758.     if (isValid ())
  1759.     {
  1760.         lpd3dScene->Init (this);
  1761.     }
  1762.  
  1763.     // Success
  1764.     return DD_OK;
  1765. } // End D3DWindow::AttachScene
  1766.  
  1767.  
  1768.  
  1769. /*
  1770. **-----------------------------------------------------------------------------
  1771. ** Name:    D3DWindow::DetachScene
  1772. ** Purpose: 
  1773. **-----------------------------------------------------------------------------
  1774. */
  1775.  
  1776. HRESULT D3DWindow::DetachScene (void)
  1777. {
  1778.     // Cleanup Scene
  1779.     if (lpd3dScene)
  1780.     {
  1781.         lpd3dScene->Fini ();
  1782.         lpd3dScene = NULL;
  1783.     }
  1784.  
  1785.     // Success
  1786.     return DD_OK;
  1787. } // End D3DWindow::DetachScene
  1788.  
  1789.  
  1790.   
  1791. /*
  1792. **-----------------------------------------------------------------------------
  1793. ** Name:    D3DWindow::CalcRects
  1794. ** Purpose: Recalculate src,dest rectangles
  1795. **
  1796. ** Notes:    Without this protection we get a GPF when we drag the window
  1797. **            off the edge of the screen.  This is because we are trying to
  1798. **            write pixels to a non-existent location.   The clipper object
  1799. **            attached to the primary protects the primary surface from 
  1800. **            stray pixels outside of the window's client area.  However, it
  1801. **            doesn't stop us from trying to write outside the primary.  So
  1802. **            we need to protect ourselves.
  1803. ** 
  1804. ** Basic Algorithm:   
  1805. **
  1806. **     - Get Client rectangle
  1807. **     - Get Render Surface rectangle
  1808. **     - Intersect client with surface to get initial src rect
  1809. **
  1810. **     - Get Primary surface rectangle
  1811. **     - Map Src rect to primary surface coordinates
  1812. **
  1813. **     - Intersect primary with src to get dest rect.
  1814. **     - Map dest rect back into surface coordinates to get final src rect.
  1815. **
  1816. **-----------------------------------------------------------------------------
  1817. */
  1818.  
  1819. HRESULT D3DWindow::CalcRects (void)
  1820. {
  1821.     // Do we need to recalculate the rectangles
  1822.     // I.E. Can we avoid doing work
  1823.     if (checkCalcRects ())
  1824.     {
  1825.         HRESULT       hResult;
  1826.         DDSURFACEDESC ddsd;         // Surface desc.
  1827.         POINT         pnt;
  1828.         RECT          rClient;
  1829.         RECT          rSrc;
  1830.         RECT          rDest;
  1831.         RECT          rTemp;
  1832.         
  1833.         if (! isValid ())
  1834.         {
  1835.             // Error, not properly initialized
  1836.             return DDERR_GENERIC;
  1837.         }
  1838.  
  1839.         // Assume we are going to paint
  1840.         turnPaintOn ();
  1841.  
  1842.         // Get Client rectangle pos/size
  1843.         GetClientRect (hWindow, &rClient);
  1844.  
  1845.         // Get Surface rectangle size
  1846.         ddsd.dwSize = sizeof (DDSURFACEDESC);
  1847.         hResult = lpddsRender->GetSurfaceDesc (&ddsd);
  1848.         if (FAILED (hResult))
  1849.         {
  1850.             // Error
  1851.             REPORTERR (hResult);
  1852.             return hResult;
  1853.         }
  1854.         rSurf.right     = rSurf.left + ddsd.dwWidth;
  1855.         rSurf.bottom    = rSurf.top + ddsd.dwHeight;
  1856.  
  1857.         // Intersect client with surface to get initial Src Rect
  1858.         if (! IntersectRect (&rSrc, &rClient, &rSurf))
  1859.         {
  1860.             // No intersection, means nothing to draw
  1861.             turnPaintOff ();
  1862.             rSrc.left   = 0;
  1863.             rSrc.top    = 0;
  1864.             rSrc.right  = 0;
  1865.             rSrc.bottom = 0;
  1866.         }
  1867.  
  1868.         // Get Primary Rectangle
  1869.         ZeroMemory (&ddsd, sizeof(ddsd));
  1870.         ddsd.dwSize = sizeof (DDSURFACEDESC);
  1871.         hResult = lpddsPrimary->GetSurfaceDesc (&ddsd);
  1872.         if (FAILED (hResult))
  1873.         {
  1874.             // Error
  1875.             return hResult;
  1876.         }
  1877.  
  1878.         rPrim.left      = 0;
  1879.         rPrim.top       = 0;
  1880.         rPrim.right     = rPrim.left + ddsd.dwWidth;
  1881.         rPrim.bottom    = rPrim.top + ddsd.dwHeight;
  1882.  
  1883.         // Map src rectangle in surface coordinates to 
  1884.         // primary surface coordinates
  1885.         pnt.x = rSrc.left;
  1886.         pnt.y = rSrc.top;
  1887.         ClientToScreen (hWindow, &pnt);
  1888.  
  1889.         rTemp.left   = pnt.x;
  1890.         rTemp.top    = pnt.y;
  1891.         rTemp.right  = rTemp.left + (rSrc.right - rSrc.left);
  1892.         rTemp.bottom = rTemp.top + (rSrc.bottom - rSrc.top);
  1893.  
  1894.         // Intersect temp with primary to get dest Rect
  1895.         if (! IntersectRect (&rDest, &rPrim, &rTemp))
  1896.         {
  1897.             // No intersection, means nothing to draw
  1898.             turnPaintOff ();
  1899.             rDest.left   = 0;
  1900.             rDest.top    = 0;
  1901.             rDest.right  = 0;
  1902.             rDest.bottom = 0;
  1903.         }
  1904.  
  1905.         // Now we have to map the dest rectangle back into
  1906.         // surface space to to get the final src rectangle
  1907.         rSrc.left   = rSrc.left + (rDest.left - pnt.x);
  1908.         rSrc.top    = rSrc.top + (rDest.top - pnt.y);
  1909.         rSrc.right  = rSrc.left + (rDest.right - rDest.left);
  1910.         rSrc.bottom = rSrc.top + (rDest.bottom - rDest.top);
  1911.  
  1912.         // Save src and dest rectangles
  1913.         rDrawDest.left   = rDest.left;
  1914.         rDrawDest.top    = rDest.top;
  1915.         rDrawDest.right  = rDest.right;
  1916.         rDrawDest.bottom = rDest.bottom;
  1917.  
  1918.         rDrawSrc.left   = rSrc.left;
  1919.         rDrawSrc.top    = rSrc.top;
  1920.         rDrawSrc.right  = rSrc.right;
  1921.         rDrawSrc.bottom = rSrc.bottom;
  1922.  
  1923.         // No longer need to calculate rects
  1924.         turnCalcRectsOff ();
  1925.     }
  1926.  
  1927.     // Success
  1928.     return DD_OK;
  1929. } // End D3DWindow::CalcRects
  1930.  
  1931.  
  1932.  
  1933. /*
  1934. **-----------------------------------------------------------------------------
  1935. ** Name:    D3DWindow::Restore
  1936. ** Purpose: Restores lost surfaces
  1937. ** Note:    Eventually we should inform the user somehow that
  1938. **          they need to redraw the surface but for now punt
  1939. **-----------------------------------------------------------------------------
  1940. */
  1941.  
  1942. HRESULT D3DWindow::Restore (void)
  1943. {
  1944.     HRESULT hResult;
  1945.  
  1946.     // Check Initialization
  1947.     if (! isValid ())
  1948.         return DDERR_GENERIC;
  1949.  
  1950.     // Restore Primary Surface
  1951.     if (lpddsPrimary)
  1952.     {
  1953.         hResult = lpddsPrimary->Restore ();
  1954.         if (FAILED (hResult))
  1955.             return hResult;
  1956.     }
  1957.  
  1958.     // Restore Z Buffer
  1959.     if (lpddsZBuff)
  1960.     {
  1961.         hResult = lpddsZBuff->Restore ();
  1962.         if (FAILED (hResult))
  1963.             return hResult;
  1964.     }
  1965.  
  1966.     // Restore Rendering surface
  1967.     if (lpddsRender)
  1968.     {
  1969.         hResult = lpddsRender->Restore ();
  1970.         if (FAILED (hResult))
  1971.             return hResult;
  1972.     }
  1973.  
  1974.     // Allow D3D Scene to restore any surfaces
  1975.     if (lpd3dScene)
  1976.     {
  1977.         hResult = lpd3dScene->Restore ();
  1978.         if (FAILED (hResult))
  1979.             return hResult;
  1980.     }
  1981.  
  1982.     // Success
  1983.     return DD_OK;
  1984. } // End D3DWindow::Restore
  1985.  
  1986.  
  1987.   
  1988. /*
  1989. **-----------------------------------------------------------------------------
  1990. ** Name:    D3DWindow::GetSurfaceRect
  1991. ** Purpose: Get bounding rectangle of surface
  1992. **-----------------------------------------------------------------------------
  1993. */
  1994.  
  1995. HRESULT D3DWindow::GetSurfaceRect (RECT & rSurface)
  1996. {
  1997.     HRESULT hResult;
  1998.  
  1999.     if (! isValid ())
  2000.     {
  2001.         // Error
  2002.         return DDERR_GENERIC;
  2003.     }
  2004.  
  2005.     // Force update of rectangle coordinates
  2006.     hResult = CalcRects ();
  2007.     if (FAILED (hResult))
  2008.         return hResult;
  2009.  
  2010.     // Return Surface rectangle
  2011.     rSurface = rSurf;
  2012.  
  2013.     // Success
  2014.     return DD_OK;
  2015. } // D3DWindow::GetSurfaceRect
  2016.  
  2017.  
  2018.  
  2019. /*
  2020. **-----------------------------------------------------------------------------
  2021. ** Name:    D3DWindow::GetPrimaryRect
  2022. ** Purpose: Get bounding rectangle of primary surface
  2023. **-----------------------------------------------------------------------------
  2024. */
  2025.  
  2026. HRESULT D3DWindow::GetPrimaryRect (RECT & rPrimary)
  2027. {
  2028.     HRESULT hResult;
  2029.  
  2030.     if (! isValid ())
  2031.     {
  2032.         // Error
  2033.         return DDERR_GENERIC;
  2034.     }
  2035.  
  2036.     // Force update of rectangle coordinates
  2037.     hResult = CalcRects ();
  2038.     if (FAILED (hResult))
  2039.     {
  2040.         // Error
  2041.         REPORTERR (hResult);
  2042.         return hResult;
  2043.     }
  2044.  
  2045.     // Return Primary rectangle
  2046.     rPrimary = rPrim;
  2047.  
  2048.     // Success
  2049.     return DD_OK;
  2050. } // GetPrimaryRect
  2051.   
  2052.  
  2053.   
  2054. /*
  2055. **-----------------------------------------------------------------------------
  2056. ** Name:    D3DWindow::GetSrcRect
  2057. ** Purpose: Get current Src Rectangle
  2058. **-----------------------------------------------------------------------------
  2059. */
  2060.  
  2061. HRESULT D3DWindow::GetSrcRect (RECT & rSrc)
  2062. {
  2063.     HRESULT hResult;
  2064.  
  2065.     if (! isValid ())
  2066.     {
  2067.         // Error
  2068.         return DDERR_GENERIC;
  2069.     }
  2070.  
  2071.     // Force update of rectangle coordinates
  2072.     hResult = CalcRects ();
  2073.     if (FAILED (hResult))
  2074.         return hResult;
  2075.  
  2076.     // Return Surface rectangle
  2077.     rSrc = rDrawSrc;
  2078.  
  2079.     // Success
  2080.     return DD_OK;
  2081. } // D3DWindow::GetSrcRect
  2082.  
  2083.  
  2084.   
  2085. /*
  2086. **-----------------------------------------------------------------------------
  2087. ** Name:    D3DWindow::GetDestRect
  2088. ** Purpose: Get current Dest Rectangle
  2089. **-----------------------------------------------------------------------------
  2090. */
  2091.  
  2092. HRESULT D3DWindow::GetDestRect (RECT & rDest)
  2093. {
  2094.     HRESULT hResult;
  2095.  
  2096.     if (! isValid ())
  2097.     {
  2098.         // Error
  2099.         return DDERR_GENERIC;
  2100.     }
  2101.  
  2102.     // Force update of rectangle coordinates
  2103.     hResult = CalcRects ();
  2104.     if (FAILED (hResult))
  2105.         return hResult;
  2106.  
  2107.     // Return Surface rectangle
  2108.     rDest = rDrawDest;
  2109.  
  2110.     // Success
  2111.     return DD_OK;
  2112. } // D3DWindow::GetDestRect
  2113.   
  2114.  
  2115. /*
  2116. **-----------------------------------------------------------------------------
  2117. **  Name:       D3DWindow::ChangeDesktop
  2118. **  Purpose:    The Primary Desktop has changed Modes, so we need
  2119. **                to update our current mode to stay in sync
  2120. **-----------------------------------------------------------------------------
  2121. */
  2122.  
  2123. HRESULT D3DWindow::ChangeDesktop (void)
  2124. {
  2125.     HRESULT         hResult;
  2126.     LPDDDrvInfo  lpDrvOld;
  2127.     LPDDModeInfo lpModeOld, lpModeNew;
  2128.     LPD3DDevInfo lpDevOld, lpDevNew;
  2129.     LPGUID         lpGuidD3D;
  2130.  
  2131.     // Check Initialization
  2132.     if ((! hWindow) || (! IsWindow (hWindow)))
  2133.     {
  2134.         REPORTERR (DDERR_INVALIDPARAMS);
  2135.         return DDERR_INVALIDPARAMS;
  2136.     }
  2137.  
  2138.     lpDrvOld  = lpCurrDriver;
  2139.     lpModeOld = lpCurrMode;
  2140.     lpDevOld  = lpCurrDevice;
  2141.  
  2142.     if (! lpDrvOld)
  2143.     {
  2144.         REPORTERR (DDERR_GENERIC);
  2145.         return DDERR_GENERIC;
  2146.     }
  2147.  
  2148.  
  2149.     //
  2150.     // Step 1. Get New Mode (and new device)
  2151.     //
  2152.  
  2153.     // Get D3D Guid
  2154.     if (lpDevOld)
  2155.         lpGuidD3D = &(lpDevOld->guid);
  2156.     else
  2157.         lpGuidD3D = NULL;
  2158.  
  2159.     // Get New Mode and Device corresponding to current desktop
  2160.     if (! GetDesktopMode (lpDrvOld, lpGuidD3D, &lpModeNew, &lpDevNew))
  2161.     {
  2162.         REPORTERR (DDERR_GENERIC);
  2163.         return DDERR_GENERIC;
  2164.     }
  2165.  
  2166.     // Do they match
  2167.     if (lpModeOld == lpModeNew)
  2168.     {
  2169.         // Nothing to do
  2170.         return DD_OK;
  2171.     }
  2172.  
  2173.     // 
  2174.     // Step 2.    Destroy current Mode
  2175.     //
  2176.     FiniRender ();
  2177.     FiniPrimary ();
  2178. //  FiniMode ();        // Don't do this => unnecessary mode switch
  2179.  
  2180.     //
  2181.     // Step 3.  Create new mode
  2182.     //
  2183.     lpCurrMode = lpModeNew;
  2184.     if (lpDevNew)
  2185.         lpCurrDevice = lpDevNew;
  2186.  
  2187.     // Create Primary Surface
  2188.     hResult = InitPrimary ();
  2189.     if (FAILED (hResult))
  2190.     {
  2191.         // Error, no point in trying to restore old defaults
  2192.         // they are out of sync with the current desktop
  2193.         return hResult;
  2194.     }
  2195.  
  2196.  
  2197.     // Create Render surface
  2198.     hResult = InitRender ();
  2199.     if (FAILED (hResult))
  2200.     {
  2201.         // Error, no point in trying to restore old defaults
  2202.         // they are out of sync with the current desktop
  2203.         return hResult;
  2204.     }
  2205.  
  2206.     // Notify the window of a successful change in Mode
  2207.     SendMessage (hWindow, D3DWIN_CHANGED_MODE, 0, 0);
  2208.  
  2209.     // Success
  2210.     return DD_OK;
  2211. } // D3DInfo::ChangeDesktop
  2212.   
  2213.  
  2214.  
  2215.   
  2216. /*
  2217. **-----------------------------------------------------------------------------
  2218. ** Name:    D3DWindow::ChangeDriver
  2219. ** Purpose: 
  2220. **-----------------------------------------------------------------------------
  2221. */
  2222.  
  2223. HRESULT D3DWindow::ChangeDriver (LPGUID lpGuidDD, LPD3DDevInfo lpDevHint)
  2224. {
  2225.     HRESULT         hResult;
  2226.     LPGUID       lpGuidD3D;
  2227.     LPDDDrvInfo  lpDrvNew,  lpDrvOld;
  2228.     LPDDModeInfo lpModeNew, lpModeOld;
  2229.     LPD3DDevInfo lpDevNew, lpDevOld;
  2230.  
  2231.     // Get New Driver
  2232.     lpDrvNew = ValidateDriver (lpGuidDD);
  2233.     if (! lpDrvNew)
  2234.     {
  2235.         return DDERR_GENERIC;
  2236.     }
  2237.  
  2238.     // Are we already using the requested driver
  2239.     if ((isValid ()) && (lpDrvNew == lpCurrDriver))
  2240.         return DD_OK;
  2241.  
  2242.     // Get reasonable defaults for Mode and D3D device
  2243.     if (lpDevHint)
  2244.         lpGuidD3D = &(lpDevHint->guid);
  2245.     else if (lpCurrDevice)
  2246.         lpGuidD3D = &(lpCurrDevice->guid);
  2247.     else
  2248.         lpGuidD3D = NULL;
  2249.  
  2250.     if (! GetDesktopMode (lpDrvNew, lpGuidD3D, &lpModeNew, &lpDevNew))
  2251.     {
  2252.         return DDERR_GENERIC;
  2253.     }
  2254.     
  2255.     // Save old defaults
  2256.     lpDrvOld    = lpCurrDriver;
  2257.     lpModeOld    = lpCurrMode;
  2258.     lpDevOld    = lpCurrDevice;
  2259.  
  2260.     // Destroy almost everything
  2261.     Fini ();
  2262.  
  2263.     // Set new defaults
  2264.     lpCurrDriver = lpDrvNew;
  2265.     lpCurrMode   = lpModeNew;
  2266.     lpCurrDevice = lpDevNew;
  2267.  
  2268.     // Re-create almost everything based on new driver
  2269.     hResult = Init ();
  2270.     if (FAILED (hResult))
  2271.     {
  2272.         // Try to restore old defaults
  2273.         Fini ();
  2274.  
  2275.         lpCurrDriver = lpDrvOld;
  2276.         lpCurrMode   = lpModeOld;
  2277.         lpCurrDevice = lpDevOld;
  2278.  
  2279.         Init ();
  2280.         return hResult;
  2281.     }
  2282.  
  2283.     // Notify the window of a successful change in Driver
  2284.     SendMessage (hWindow, D3DWIN_CHANGED_DRIVER, 0, 0);
  2285.  
  2286.     // Success
  2287.     return DD_OK;
  2288. } // End D3DWindow::ChangeDriver
  2289.  
  2290.  
  2291.   
  2292. /*
  2293. **-----------------------------------------------------------------------------
  2294. ** Name:    D3DWindow::ChangeDevice
  2295. ** Purpose: Change to a new D3D device (RAMP, RGB, Hardware, etc.)
  2296. ** Notes:
  2297. **
  2298. **  Algorithm:
  2299. **        - Destroy the current D3D Device (and associated surfaces)
  2300. **        - Recreate a new D3D device from the new GUID
  2301. **
  2302. **  1.    The new D3D Device may not be supported by the current DD Device.
  2303. **
  2304. **  2.  The new D3D Device may not be compatible with the current Mode
  2305. **        - If we are windowed, then punt (we shouldn't change the desktop)
  2306. **        - If we are full-screen then pick a new mode that is compatible
  2307. **            - This means destroy the current mode and recreate it.
  2308. **
  2309. **-----------------------------------------------------------------------------
  2310. */
  2311.  
  2312. HRESULT D3DWindow::ChangeDevice (LPGUID lpD3DGuid)
  2313. {
  2314.     HRESULT         hResult;
  2315.     LPDDDrvInfo        lpDrvOld;
  2316.     LPDDModeInfo    lpModeOld;
  2317.     LPD3DDevInfo    lpDevNew, lpDevOld;
  2318.  
  2319.     // Check Parameters
  2320.     if (! lpD3DGuid)
  2321.     {
  2322.         REPORTERR (DDERR_INVALIDPARAMS);
  2323.         return DDERR_INVALIDPARAMS;
  2324.     }
  2325.     
  2326.     // Check Initialization
  2327.     if (! isValid () || (! lpddsRender))
  2328.     {
  2329.         REPORTERR (DDERR_GENERIC);
  2330.         return DDERR_GENERIC;
  2331.     }
  2332.  
  2333.     // Save Original State
  2334.     lpDrvOld    = lpCurrDriver;
  2335.     lpModeOld   = lpCurrMode;
  2336.     lpDevOld    = lpCurrDevice;
  2337.  
  2338.     // Verify new D3D device belongs to current DD driver
  2339.     lpDevNew = lpDrvOld->FindDevice (lpD3DGuid, NULL);
  2340.     if (! lpDevNew)
  2341.     {
  2342.         REPORTERR (DDERR_INVALIDPARAMS);
  2343.         return DDERR_INVALIDPARAMS;
  2344.     }
  2345.  
  2346.     //
  2347.     //    Step 1. Verify new D3D device is supported with current mode
  2348.     //
  2349.     if (! lpModeOld->ModeSupported (lpDevNew))
  2350.     {
  2351.         // We can't change the mode
  2352.         // as we shouldn't be changing the desktop
  2353.         REPORTERR (DDERR_INVALIDPARAMS);
  2354.         return DDERR_INVALIDPARAMS;
  2355.     }
  2356.  
  2357.  
  2358.     //
  2359.     //    Step 2.  Destroy Old D3D Device
  2360.     //
  2361.     FiniRender ();
  2362.  
  2363.     //
  2364.     //    Step 3. Create new D3D Device
  2365.     //
  2366.  
  2367.     // Set new D3D device (and mode)
  2368.     lpCurrDevice = lpDevNew;
  2369.  
  2370.     // Create new D3D Device
  2371.     hResult = InitRender ();
  2372.     if (FAILED (hResult))
  2373.     {
  2374.         // Try to restore original device
  2375.         lpCurrDevice = lpDevOld;        
  2376.         InitRender ();
  2377.  
  2378.         // Return Error
  2379.         REPORTERR (hResult);
  2380.         return hResult;
  2381.     }
  2382.  
  2383.     // Notify the window of a successful change in device
  2384.     SendMessage (hWindow, D3DWIN_CHANGED_DEVICE, 0, 0);
  2385.  
  2386.     // Success
  2387.     return DD_OK;
  2388. } // End D3DWindow::ChangeDevice
  2389.  
  2390.  
  2391.  
  2392. /*
  2393. **-----------------------------------------------------------------------------
  2394. ** End of File
  2395. **-----------------------------------------------------------------------------
  2396. */
  2397.