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

Windows编程

开发平台:

Visual C++

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