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 / boids / d3dwin.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-15  |  57.3 KB  |  2,453 lines

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