home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Utilities / MView / d3dxapp.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  43.6 KB  |  1,672 lines

  1. //
  2. // D3DX Application Framework
  3. // Copyright (c) 1999 Microsoft Corporation. All rights reserved.
  4. //
  5. #include "mviewpch.h"
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <malloc.h>
  10. #include <windows.h>
  11. #include <mmsystem.h>
  12. #include <multimon.h>
  13. #include "d3dxapp.h"
  14. #include "dxerr8.h"
  15.  
  16. #define RELEASE(x) if(x) { x->Release(); x = NULL; } else 0
  17. typedef BOOL (WINAPI* LPGETMONITORINFO)(HMONITOR, LPMONITORINFO);   
  18.  
  19.  
  20. // ---------------------------------------------------------------------------
  21. //
  22. // Structures
  23. //
  24. // ---------------------------------------------------------------------------
  25.  
  26. struct D3DX_DEVICE
  27. {
  28.     UINT       m_uAdapter;
  29.     D3DDEVTYPE m_DevType;
  30.     DWORD      m_dwBehavior;
  31. };
  32.  
  33.  
  34. struct D3DX_TIMER
  35. {
  36.     float m_fTicksPerSec;
  37.     float m_fFramesPerSec;
  38.     float m_fSecsPerFrame;
  39.  
  40.     UINT64 m_qwTicks;
  41.     UINT64 m_qwTicksPerSec;
  42.     UINT64 m_qwTicksPerFrame;
  43. };
  44.  
  45.  
  46. struct D3DX_APPLICATION_DATA
  47. {
  48.     BOOL m_bActive        ;
  49.     BOOL m_bRunning       ;
  50.     BOOL m_bStopping      ;
  51.     BOOL m_bDrawing       ;
  52.     BOOL m_bFullscreen    ;
  53.     BOOL m_bInSizeMove    ;
  54.     BOOL m_bInReset       ;
  55.     BOOL m_bCoverWindow   ;
  56.     BOOL m_bNeedReset     ;
  57.     BOOL m_bNeedDraw      ;
  58.     BOOL m_bDeviceCreated ;
  59.     BOOL m_bDeviceReset   ;
  60.  
  61.     D3DX_TIMER            m_Timer;
  62.     D3DX_DEVICE           m_Device;
  63.     D3DPRESENT_PARAMETERS m_Params;
  64.     D3DPRESENT_PARAMETERS m_UserParams;
  65.  
  66.     float m_fWindowAspect;
  67.     float m_fScreenAspect;
  68.  
  69.     HACCEL           m_hAccel;
  70.     RECT             m_WindowRect;
  71.     WINDOWPLACEMENT  m_WindowPlacement;
  72.     LPGETMONITORINFO m_pfnGetMonitorInfo;
  73.  
  74.     UINT  m_cAdapter;
  75.     UINT* m_pAdapter;
  76. };
  77.  
  78.  
  79.  
  80. // ---------------------------------------------------------------------------
  81. //
  82. // Debug printf functions
  83. //
  84. // ---------------------------------------------------------------------------
  85.  
  86. #if DBG
  87. /*
  88. static void
  89. DPF(const char *szFmt, ...)
  90. {
  91.     char sz[256], szMsg[256];
  92.  
  93.     va_list va;
  94.     va_start(va, szFmt);
  95.     _vsnprintf(szMsg, sizeof(szMsg), szFmt, va);
  96.     va_end(va);
  97.  
  98.     _snprintf(sz, sizeof(sz), "d3dxapp: %s\r\n", szMsg);
  99.  
  100.     sz[sizeof(sz)-1] = '\0';
  101.     OutputDebugString(sz);
  102. }
  103. */
  104.  
  105.  
  106. static void
  107. DPF_HR(HRESULT hr, const char *szFmt, ...)
  108. {
  109.     char sz[256], szMsg[256];
  110.     const char *szHr;
  111.  
  112.  
  113.     va_list va;
  114.     va_start(va, szFmt);
  115.     _vsnprintf(szMsg, sizeof(szMsg), szFmt, va);
  116.     va_end(va);
  117.  
  118.     szHr = DXGetErrorString8(hr);
  119.  
  120.     _snprintf(sz, sizeof(sz), "d3dxapp: %s (%s)\r\n", szMsg, szHr);
  121.     sz[sizeof(sz)-1] = '\0';
  122.     OutputDebugString(sz);
  123. }
  124. #else
  125.  
  126. #pragma warning(disable:4002)
  127. #define DPF_HR() 0
  128.  
  129. #endif
  130.  
  131. // ---------------------------------------------------------------------------
  132. //
  133. // Timer functions
  134. //
  135. // ---------------------------------------------------------------------------
  136.  
  137.  
  138. static UINT64
  139. D3DXTimer_GetTicks()
  140. {
  141.     UINT64 qw;
  142.  
  143.     do
  144.     {
  145.         // Use QueryPerformanceCounter to get high-res timer. Fall back on 
  146.         // timeGetTime if QPC is not supported.
  147.  
  148.         if(!QueryPerformanceCounter((LARGE_INTEGER *) &qw))
  149.             return (UINT64) timeGetTime();
  150.     }
  151.     while(!qw);
  152.  
  153.     return qw;
  154. }
  155.  
  156.  
  157. static void
  158. D3DXTimer_Initialize(D3DX_TIMER *pTimer)
  159. {
  160.     // Use QueryPerformanceFrequency to get frequency of timer.  If QPF is not 
  161.     // supported, use 1000, since timeGetTime returns milliseconds.
  162.  
  163.     if(!QueryPerformanceFrequency((LARGE_INTEGER *) &pTimer->m_qwTicksPerSec))
  164.         pTimer->m_qwTicksPerSec = 1000;
  165.  
  166.     pTimer->m_fTicksPerSec  = (float) (__int64) pTimer->m_qwTicksPerSec;
  167. }
  168.  
  169.  
  170. static void 
  171. D3DXTimer_Start(D3DX_TIMER *pTimer, float fFramesPerSec)
  172. {
  173.     if(fFramesPerSec < 1.0f)
  174.         fFramesPerSec = 1.0f;
  175.     
  176.     pTimer->m_fFramesPerSec = fFramesPerSec;
  177.     pTimer->m_fSecsPerFrame = 1.0f / fFramesPerSec;
  178.     pTimer->m_qwTicksPerFrame = pTimer->m_qwTicksPerSec / (__int64) fFramesPerSec;
  179.     pTimer->m_qwTicks = D3DXTimer_GetTicks();
  180. }
  181.  
  182.  
  183. static void 
  184. D3DXTimer_OnFrame(D3DX_TIMER *pTimer)
  185. {
  186.     UINT64 qw;
  187.     qw = D3DXTimer_GetTicks();
  188.  
  189.  
  190.     if(qw != pTimer->m_qwTicks)
  191.     {
  192.         pTimer->m_qwTicksPerFrame = qw - pTimer->m_qwTicks;
  193.         pTimer->m_qwTicks = qw;
  194.  
  195.         pTimer->m_fFramesPerSec = 
  196.             pTimer->m_fTicksPerSec / (float) (__int64) pTimer->m_qwTicksPerFrame;
  197.  
  198.         if(pTimer->m_fFramesPerSec < 1.0f)
  199.             pTimer->m_fFramesPerSec = 1.0f;
  200.  
  201.         pTimer->m_fSecsPerFrame = 1.0f / pTimer->m_fFramesPerSec;
  202.     }
  203. }
  204.  
  205.  
  206.  
  207.  
  208. // ---------------------------------------------------------------------------
  209. //
  210. // EnumFirstResource
  211. //
  212. // ---------------------------------------------------------------------------
  213.  
  214.  
  215. static BOOL CALLBACK 
  216. EnumFirstResource(HMODULE hInstance, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam)
  217. {
  218.     *((LPSTR *) lParam) = lpszName;
  219.     return FALSE;
  220. }
  221.  
  222.  
  223. // ---------------------------------------------------------------------------
  224. //
  225. // GetClientScreenRect - Get non-minimized client rect on screen
  226. //
  227. // ---------------------------------------------------------------------------
  228.  
  229. static BOOL
  230. GetClientScreenRect(HWND hwnd, LPRECT pRect)
  231. {
  232.     if(!pRect)
  233.         return FALSE;
  234.  
  235.     WINDOWPLACEMENT wp;
  236.     GetWindowPlacement(hwnd, &wp);
  237.  
  238.     if(SW_SHOWMINIMIZED == wp.showCmd)
  239.     {
  240.         RECT rectBorder;
  241.         memset(&rectBorder, 0x00, sizeof(RECT));
  242.  
  243.         AdjustWindowRectEx(
  244.             &rectBorder, 
  245.             GetWindowLong(hwnd, GWL_STYLE),
  246.             NULL != GetMenu(hwnd),
  247.             GetWindowLong(hwnd, GWL_EXSTYLE));
  248.  
  249.         pRect->left   = wp.rcNormalPosition.left   - rectBorder.left;
  250.         pRect->top    = wp.rcNormalPosition.top    - rectBorder.top;
  251.         pRect->right  = wp.rcNormalPosition.right  - rectBorder.right;
  252.         pRect->bottom = wp.rcNormalPosition.bottom - rectBorder.bottom;
  253.     }
  254.     else
  255.     {
  256.         GetClientRect(hwnd, pRect);
  257.         ClientToScreen(hwnd, (LPPOINT) pRect);
  258.  
  259.         pRect->right += pRect->left;
  260.         pRect->bottom += pRect->top;
  261.  
  262.         pRect->top += 28;
  263.         pRect->bottom -= 20;
  264.     }
  265.  
  266.     return TRUE;
  267. }
  268.  
  269.  
  270. // ---------------------------------------------------------------------------
  271. //
  272. // CD3DXApplication
  273. //
  274. // ---------------------------------------------------------------------------
  275.  
  276. CD3DXApplication::CD3DXApplication()
  277. {
  278.     m_hInstance  = NULL;
  279.     m_hwnd       = NULL;
  280.     m_pD3D       = NULL;
  281.     m_pDevice = NULL;
  282.     m_pData      = NULL;
  283. }
  284.  
  285.  
  286. CD3DXApplication::~CD3DXApplication()
  287. {
  288.     RELEASE(m_pDevice);
  289.     RELEASE(m_pD3D);
  290.  
  291.     if(m_hwnd)
  292.         DestroyWindow(m_hwnd);
  293.  
  294.     if(m_pData)
  295.     {
  296.         if(m_pData->m_pAdapter)
  297.             delete [] m_pData->m_pAdapter;
  298.  
  299.         delete m_pData;
  300.     }
  301. }
  302.  
  303.  
  304. HRESULT 
  305. CD3DXApplication::Initialize(HINSTANCE hInstance, LPCSTR szWindowName, 
  306.      LPCSTR szClassName, UINT uWidth, UINT uHeight)
  307. {
  308.     HRESULT hr;
  309.     RECT rect;
  310.  
  311.     if(m_pData)
  312.     {
  313.         DPF_HR(0, "Application already initialized");
  314.         return S_OK;
  315.     }
  316.  
  317.     if (!D3DXCheckVersion(D3D_SDK_VERSION, D3DX_SDK_VERSION))
  318.         return E_FAIL;
  319.  
  320.     // Create D3D
  321.     if(!(m_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
  322.     {
  323.         DPF_HR(0, "Direct3DCreate9 failed");
  324.         goto LFail;
  325.     }
  326.  
  327.  
  328.     // Initialize private data
  329.     if(!(m_pData = new D3DX_APPLICATION_DATA))
  330.     {
  331.         DPF_HR(0, "Could not allocate private data");
  332.         hr = E_OUTOFMEMORY;
  333.         goto LError;
  334.     }
  335.  
  336.     memset(m_pData, 0x00, sizeof(D3DX_APPLICATION_DATA));
  337.  
  338.     D3DXTimer_Initialize(&m_pData->m_Timer);
  339.     D3DXTimer_Start(&m_pData->m_Timer, 30.0f);
  340.  
  341.     m_hInstance = hInstance;
  342.  
  343.  
  344.  
  345.     // Create window class
  346.     if(!szWindowName)
  347.         szWindowName = "D3DX Application";
  348.  
  349.     if(!szClassName)
  350.     {
  351.         WNDCLASS wc;
  352.  
  353.         // Use first icon resource as window icon.
  354.         LPSTR szIcon;
  355.         szIcon = NULL;
  356.         EnumResourceNames(m_hInstance, RT_GROUP_ICON, EnumFirstResource, (LONG_PTR)&szIcon);
  357.  
  358.         wc.style         = 0;
  359.         wc.lpfnWndProc   = (WNDPROC) WndProc;
  360.         wc.cbClsExtra    = 0;
  361.         wc.cbWndExtra    = 0;
  362.         wc.hInstance     = m_hInstance;
  363.         wc.hIcon         = szIcon ? LoadIcon(m_hInstance, szIcon) : NULL;
  364.         wc.hCursor       = CopyCursor(LoadCursor(NULL, IDC_ARROW));
  365.         wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
  366.         wc.lpszMenuName  = NULL;
  367.         wc.lpszClassName = szClassName = szWindowName;
  368.  
  369.         RegisterClass(&wc);
  370.     }
  371.  
  372.  
  373.  
  374.     // Create window (exact size and style will be overridden later)
  375.     if(0 == uWidth || 0 == uHeight)
  376.     {
  377.         uWidth  = 640;
  378.         uHeight = 480;
  379.     }
  380.  
  381.     rect.left   = 0;
  382.     rect.top    = 0;
  383.     rect.right  = uWidth;
  384.     rect.bottom = uHeight;
  385.  
  386.     AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
  387.  
  388.     m_hwnd = CreateWindow(szClassName, szWindowName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 
  389.         CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, (HWND) NULL, 
  390.         (HMENU) NULL, m_hInstance, (LPVOID) NULL);
  391.  
  392.     if(!m_hwnd)
  393.     {
  394.         DPF_HR(0, "Failed to create window");
  395.         goto LFail;
  396.     }
  397.  
  398.     DragAcceptFiles( m_hwnd, TRUE );
  399.  
  400.     // Save 'this' in the window's USERDATA for WndProc.
  401.     SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this);
  402.  
  403.  
  404.     // Find first accelerator resource
  405.     LPSTR szAccel;
  406.     szAccel = NULL;
  407.     EnumResourceNames(m_hInstance, RT_ACCELERATOR, EnumFirstResource, (LONG_PTR) &szAccel);
  408.  
  409.     if(szAccel)
  410.         m_pData->m_hAccel = LoadAccelerators(m_hInstance, szAccel);
  411.  
  412.  
  413.     // Default presentation parameters
  414.     m_pData->m_Params.BackBufferWidth        = 0;
  415.     m_pData->m_Params.BackBufferHeight       = 0;
  416.     m_pData->m_Params.BackBufferFormat       = D3DFMT_UNKNOWN;
  417.     m_pData->m_Params.BackBufferCount        = 0;
  418.     m_pData->m_Params.MultiSampleType        = D3DMULTISAMPLE_NONE;
  419.     m_pData->m_Params.SwapEffect             = D3DSWAPEFFECT_COPY;
  420.     m_pData->m_Params.hDeviceWindow          = m_hwnd;
  421.     m_pData->m_Params.Windowed               = TRUE;
  422.     m_pData->m_Params.EnableAutoDepthStencil = TRUE;
  423.     m_pData->m_Params.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
  424.     m_pData->m_Params.Flags                  = 0;
  425.  
  426.     m_pData->m_UserParams = m_pData->m_Params;
  427.     m_PresentParameters   = m_pData->m_Params;
  428.  
  429.  
  430.     // Get GetMonitorInfo entrypoint
  431.     HINSTANCE hUser32;
  432.  
  433.     if((hUser32 = (HINSTANCE) GetModuleHandle("user32.dll")) ||
  434.        (hUser32 = (HINSTANCE) LoadLibrary("user32.dll")))
  435.     {
  436.         m_pData->m_pfnGetMonitorInfo = 
  437.            (LPGETMONITORINFO) GetProcAddress(hUser32, "GetMonitorInfoA");
  438.     }
  439.  
  440.  
  441.     // Default adapter ordering
  442.     UINT uAdapter;
  443.  
  444.     m_pData->m_cAdapter = m_pD3D->GetAdapterCount();
  445.     
  446.     if(!(m_pData->m_pAdapter = new UINT[m_pData->m_cAdapter]))
  447.     {
  448.         hr = E_OUTOFMEMORY;
  449.         goto LError;
  450.     }
  451.  
  452.     for(uAdapter = 0; uAdapter < m_pData->m_cAdapter; uAdapter++)
  453.     {
  454.         m_pData->m_pAdapter[uAdapter] = uAdapter;
  455.     }
  456.  
  457.  
  458.  
  459.     return S_OK;
  460.  
  461.  
  462. LFail:
  463.     hr = E_FAIL;
  464.     goto LError;
  465.  
  466. LError:
  467.     RELEASE(m_pD3D);
  468.  
  469.     if(m_hwnd)
  470.         DestroyWindow(m_hwnd);
  471.  
  472.     if(m_pData)
  473.     {
  474.         if(m_pData->m_pAdapter)
  475.             delete m_pData->m_pAdapter;
  476.  
  477.         delete m_pData;
  478.     }
  479.  
  480.     m_hwnd = NULL;
  481.     m_pData = NULL;
  482.  
  483.     return hr;
  484. }
  485.  
  486.  
  487.  
  488. HRESULT 
  489. CD3DXApplication::Reset(D3DPRESENT_PARAMETERS *pPresentParameters)
  490. {
  491.     HRESULT hr;
  492.  
  493.     if(!m_pData)
  494.     {
  495.         DPF_HR(0, "Application not initialized");
  496.         return E_FAIL;
  497.     }
  498.  
  499.     if(m_pData->m_bDrawing)
  500.     {
  501.         DPF_HR(0, "Reset cannot be called from within OnDraw");
  502.         return E_FAIL;
  503.     }
  504.  
  505.     if(m_pData->m_bInReset)
  506.     {
  507.         // Reset called from within reset
  508.         return S_OK;
  509.     }
  510.  
  511.  
  512.  
  513.     // If we are not running, we just save off the parameters and return.
  514.     // (The device will be created when we begin running.)
  515.     if(pPresentParameters)
  516.         m_pData->m_UserParams = *pPresentParameters;
  517.  
  518.     if(!m_pData->m_bRunning)
  519.         return S_OK;
  520.  
  521.  
  522.  
  523.  
  524.     // Ok.. so we are actually going to actually do work..
  525.     m_pData->m_bInReset = TRUE;
  526.  
  527.     D3DX_DEVICE Device = m_pData->m_Device;
  528.     D3DPRESENT_PARAMETERS Params = m_pData->m_UserParams;
  529.  
  530.  
  531.     // If we are switching from fullscreen to windowed, we need to destroy
  532.     // the device, so that video mode gets restored before we try to figure
  533.     // out which monitor the window is primarily on.
  534.     if(Params.Windowed && m_pData->m_bFullscreen)
  535.     {
  536.         if(m_pData->m_bDeviceReset)
  537.         {
  538.             m_pData->m_bDeviceReset = FALSE;
  539.  
  540.             if(FAILED(hr = OnLostDevice()))
  541.                 DPF_HR(hr, "OnLostDevice failed");
  542.         }
  543.  
  544.         if(m_pData->m_bDeviceCreated)
  545.         {
  546.             m_pData->m_bDeviceCreated = FALSE;
  547.  
  548.             if(FAILED(hr = OnDestroyDevice()))
  549.                 DPF_HR(hr, "OnDestroyDevice failed");
  550.         }
  551.  
  552.         RELEASE(m_pDevice);
  553.     }
  554.  
  555.  
  556.     // Compute window client rect (in screen coordinates)
  557.     if(!m_pData->m_bCoverWindow)
  558.     {
  559.         m_pData->m_WindowPlacement.length = sizeof(WINDOWPLACEMENT);
  560.         GetWindowPlacement(m_hwnd, &m_pData->m_WindowPlacement);
  561.         GetClientScreenRect(m_hwnd, &m_pData->m_WindowRect);
  562.     }
  563.  
  564.     RECT WindowRect = m_pData->m_WindowRect;
  565.  
  566.  
  567.     // Default values for width and height
  568.     if(D3DX_DEFAULT == Params.BackBufferWidth)
  569.         Params.BackBufferWidth = 0;
  570.  
  571.     if(D3DX_DEFAULT == Params.BackBufferHeight)
  572.         Params.BackBufferHeight = 0;
  573.  
  574.     if(!Params.BackBufferWidth || !Params.BackBufferHeight)
  575.     {
  576.         if(Params.Windowed)
  577.         {
  578.             Params.BackBufferWidth  = (WindowRect.right > WindowRect.left) ? (WindowRect.right - WindowRect.left) : 1;
  579.             Params.BackBufferHeight = (WindowRect.bottom > WindowRect.top) ? (WindowRect.bottom - WindowRect.top) : 1;
  580.         }
  581.         else
  582.         {
  583.             Params.BackBufferWidth  = 640;
  584.             Params.BackBufferHeight = 480;
  585.         }
  586.     }
  587.  
  588.     if(Params.Windowed)
  589.     {
  590.         Params.BackBufferCount = 1;
  591.         Params.FullScreen_RefreshRateInHz      = 0;
  592.         Params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  593.     }
  594.  
  595.     Params.hDeviceWindow = m_hwnd;
  596.  
  597.  
  598.     // Default values for backbuffer count
  599.     UINT uBBCMax;
  600.     UINT uBBCMin;
  601.  
  602.     if(0 != Params.BackBufferCount && D3DX_DEFAULT != Params.BackBufferCount)
  603.     {
  604.         uBBCMax = Params.BackBufferCount;
  605.         uBBCMin = Params.BackBufferCount;
  606.     }
  607.     else if(!Params.Windowed && D3DSWAPEFFECT_DISCARD == Params.SwapEffect)
  608.     {
  609.         uBBCMax = 2;
  610.         uBBCMin = 1;
  611.     }
  612.     else
  613.     {
  614.         uBBCMax = 1;
  615.         uBBCMin = 1;
  616.     }
  617.  
  618.  
  619.  
  620.  
  621.     // Device type list
  622.     static D3DDEVTYPE DevTypeList[] = 
  623.     {
  624.         D3DDEVTYPE_HAL,
  625.         D3DDEVTYPE_REF,
  626.     };
  627.  
  628.     D3DDEVTYPE *pDevType;
  629.     D3DDEVTYPE *pDevTypeMin = DevTypeList;
  630.     D3DDEVTYPE *pDevTypeLim = DevTypeList + (sizeof(DevTypeList) / sizeof(DevTypeList[0]));
  631.  
  632.  
  633.  
  634.  
  635.     // Adapter list. This list is sorted by area covered by window.  This 
  636.     // is done so that as the window gets dragged from monitor to monitor, 
  637.     // the adapter which the window is mostly on will be considered first.
  638.  
  639.     UINT  cAdapter    = m_pData->m_cAdapter;
  640.     UINT *pAdapter;
  641.     UINT *pAdapterMin = m_pData->m_pAdapter;
  642.     UINT *pAdapterLim = pAdapterMin + cAdapter;
  643.  
  644.     if(!m_pData->m_bFullscreen && m_pData->m_pfnGetMonitorInfo && cAdapter > 1)
  645.     {
  646.         HMONITOR    hMonitor;
  647.         MONITORINFO minfo;
  648.  
  649.         UINT *pAreaMin = (UINT *) _alloca(cAdapter * sizeof(UINT));
  650.         UINT iAdapter;
  651.  
  652.         // Clip client area to adapter rect
  653.         for(iAdapter = 0; iAdapter < cAdapter; iAdapter++)
  654.         {
  655.             minfo.cbSize = sizeof(MONITORINFO);
  656.  
  657.             hMonitor = m_pD3D->GetAdapterMonitor(pAdapterMin[iAdapter]);
  658.  
  659.             m_pData->m_pfnGetMonitorInfo(hMonitor, &minfo);
  660.  
  661.  
  662.             if(minfo.rcWork.left < WindowRect.left)
  663.                 minfo.rcWork.left = WindowRect.left;
  664.  
  665.             if(minfo.rcWork.right > WindowRect.right)
  666.                 minfo.rcWork.right = WindowRect.right;
  667.  
  668.             if(minfo.rcWork.right < minfo.rcWork.left)
  669.                 minfo.rcWork.right = minfo.rcWork.left;
  670.  
  671.  
  672.             if(minfo.rcWork.top < WindowRect.top)
  673.                 minfo.rcWork.top = WindowRect.top;
  674.  
  675.             if(minfo.rcWork.bottom > WindowRect.bottom)
  676.                 minfo.rcWork.bottom = WindowRect.bottom;
  677.  
  678.             if(minfo.rcWork.bottom < minfo.rcWork.top)
  679.                 minfo.rcWork.bottom = minfo.rcWork.top;
  680.  
  681.  
  682.             pAreaMin[iAdapter] = (UINT) ((minfo.rcWork.right - minfo.rcWork.left) * (minfo.rcWork.bottom - minfo.rcWork.top));
  683.         }
  684.  
  685.  
  686.         // Sort adapters by area
  687.         for(;;)
  688.         {
  689.             for(iAdapter = 1; iAdapter < cAdapter; iAdapter++)
  690.             {
  691.                 if(pAreaMin[iAdapter] > pAreaMin[iAdapter - 1])
  692.                 {
  693.                     UINT u;
  694.  
  695.                     u = pAreaMin[iAdapter]; 
  696.                     pAreaMin[iAdapter] = pAreaMin[iAdapter - 1]; 
  697.                     pAreaMin[iAdapter - 1] = u;
  698.  
  699.                     u = pAdapterMin[iAdapter]; 
  700.                     pAdapterMin[iAdapter] = pAdapterMin[iAdapter - 1]; 
  701.                     pAdapterMin[iAdapter - 1] = u;
  702.  
  703.                     break;
  704.                 }
  705.             }
  706.  
  707.             if(iAdapter == cAdapter)
  708.                 break;
  709.         }
  710.     }
  711.  
  712.  
  713.  
  714.  
  715.     // Search for suitable device
  716.     enum { NONE, EXISTING, RESET, CREATE } Action = NONE;
  717.  
  718.     for(pDevType = pDevTypeMin; pDevType < pDevTypeLim; pDevType++)
  719.     {
  720.         Device.m_DevType = *pDevType;
  721.  
  722.         for(pAdapter = pAdapterMin; pAdapter < pAdapterLim; pAdapter++)
  723.         {
  724.             Device.m_uAdapter = *pAdapter;
  725.             D3DFORMAT PrimaryFormat;
  726.  
  727.  
  728.             // Resolve unknown backbuffer formats
  729.             if(D3DFMT_UNKNOWN == m_pData->m_UserParams.BackBufferFormat)
  730.             {
  731.                 if(Params.Windowed)
  732.                 {
  733.                     // Use current display mode
  734.                     D3DDISPLAYMODE mode;
  735.  
  736.                     if(FAILED(m_pD3D->GetAdapterDisplayMode(Device.m_uAdapter , &mode)))
  737.                         continue;
  738.  
  739.                     PrimaryFormat = mode.Format;
  740.                     Params.BackBufferFormat = mode.Format;
  741.  
  742.                     if(FAILED(m_pD3D->CheckDeviceType(Device.m_uAdapter, Device.m_DevType, 
  743.                         PrimaryFormat, Params.BackBufferFormat, FALSE)))
  744.                     {
  745.                         continue;
  746.                     }
  747.  
  748.                 }
  749.                 else
  750.                 {
  751.                     // Fallbacks
  752.                     for(UINT i = 0; i < 3; i++)
  753.                     {
  754.                         switch(i)
  755.                         {
  756.                         case 0: Params.BackBufferFormat = D3DFMT_R5G6B5;   break;
  757.                         case 1: Params.BackBufferFormat = D3DFMT_X1R5G5B5; break;
  758.                         case 2: Params.BackBufferFormat = D3DFMT_X8R8G8B8; break;
  759.                         }
  760.  
  761.                         PrimaryFormat = Params.BackBufferFormat;
  762.         
  763.                         if(FAILED(m_pD3D->CheckDeviceType(Device.m_uAdapter, Device.m_DevType, 
  764.                             PrimaryFormat, Params.BackBufferFormat, FALSE)))
  765.                         {
  766.                             continue;
  767.                         }
  768.  
  769.                         break;
  770.                     }
  771.  
  772.                     if(i == 3)
  773.                         continue;
  774.                 }
  775.             }
  776.             else
  777.             {
  778.                 // Try to pick primary format without alpha
  779.                 switch(Params.BackBufferFormat)
  780.                 {
  781.                 case D3DFMT_A8R8G8B8: PrimaryFormat = D3DFMT_X8R8G8B8;         break;
  782.                 case D3DFMT_A1R5G5B5: PrimaryFormat = D3DFMT_X1R5G5B5;         break;
  783.                 case D3DFMT_A4R4G4B4: PrimaryFormat = D3DFMT_X4R4G4B4;         break;  
  784.                 default:              PrimaryFormat = Params.BackBufferFormat; break;
  785.                 }
  786.  
  787.                 if(FAILED(m_pD3D->CheckDeviceType(Device.m_uAdapter, Device.m_DevType, 
  788.                     PrimaryFormat, Params.BackBufferFormat, FALSE)))
  789.                 {
  790.                     continue;
  791.                 }
  792.             }
  793.  
  794.  
  795.             // Resolve unknown depth/stencil formats
  796.             if(D3DFMT_UNKNOWN == m_pData->m_UserParams.AutoDepthStencilFormat)
  797.             {
  798.                 static D3DFORMAT s_ZS16[] = 
  799.                 { 
  800.                     D3DFMT_D16_LOCKABLE,
  801.                     D3DFMT_D16,
  802.                     D3DFMT_D15S1,
  803.                     D3DFMT_D32,
  804.                     D3DFMT_D24S8,
  805.                     D3DFMT_D24X4S4,
  806.                     D3DFMT_D24X8
  807.                 };
  808.  
  809.                 static D3DFORMAT s_ZS32[] = 
  810.                 { 
  811.                     D3DFMT_D32,
  812.                     D3DFMT_D24S8,
  813.                     D3DFMT_D24X4S4,
  814.                     D3DFMT_D24X8,
  815.                     D3DFMT_D16_LOCKABLE,
  816.                     D3DFMT_D16,
  817.                     D3DFMT_D15S1
  818.                 };
  819.  
  820.                 D3DFORMAT *pZS;
  821.  
  822.                 switch(Params.BackBufferFormat)
  823.                 {
  824.                 case D3DFMT_R5G6B5:
  825.                 case D3DFMT_X1R5G5B5:
  826.                 case D3DFMT_A1R5G5B5:
  827.                 case D3DFMT_A4R4G4B4:
  828.                 case D3DFMT_A8R3G3B2:
  829.                 case D3DFMT_X4R4G4B4:
  830.                     pZS = s_ZS16;
  831.                     break;
  832.  
  833.                 case D3DFMT_R8G8B8:
  834.                 case D3DFMT_A8R8G8B8:
  835.                 case D3DFMT_X8R8G8B8:
  836.                 default:
  837.                     pZS = s_ZS32;
  838.                     break;
  839.                 }
  840.  
  841.                 for(UINT i = 0; i < 7; i++)
  842.                 {
  843.                     Params.AutoDepthStencilFormat = pZS[i];
  844.  
  845.                     if(FAILED(m_pD3D->CheckDeviceFormat(Device.m_uAdapter, Device.m_DevType, 
  846.                         PrimaryFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, Params.AutoDepthStencilFormat)))
  847.                     {
  848.                         continue;
  849.                     }
  850.  
  851.                     if(FAILED(m_pD3D->CheckDepthStencilMatch(Device.m_uAdapter, Device.m_DevType, 
  852.                         PrimaryFormat, Params.BackBufferFormat, Params.AutoDepthStencilFormat)))
  853.                     {
  854.                         continue;
  855.                     }
  856.  
  857.                     break;
  858.                 }
  859.  
  860.                 if(i == 7)
  861.                     continue;
  862.             }
  863.  
  864.  
  865.  
  866.             // Check device caps
  867.             BOOL bCapsSufficient;
  868.  
  869.             bCapsSufficient = FALSE;
  870.  
  871.             if(FAILED(m_pD3D->GetDeviceCaps(Device.m_uAdapter, Device.m_DevType, &m_Caps)))
  872.                 continue;
  873.  
  874.             if(m_Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
  875.             {
  876.                 if(m_Caps.DevCaps & D3DDEVCAPS_PUREDEVICE)
  877.                 {
  878.                     // Try Pure HW
  879.                     Device.m_dwBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE;
  880.                     bCapsSufficient = AreCapsSufficient(&m_Caps, Device.m_dwBehavior);
  881.                 }
  882.  
  883.                 if(!bCapsSufficient)
  884.                 {
  885.                     // Try HW
  886.                     Device.m_dwBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  887.                     bCapsSufficient = AreCapsSufficient(&m_Caps, Device.m_dwBehavior);
  888.                 }
  889.  
  890.                 if(!bCapsSufficient)
  891.                 {
  892.                     // Try Mixed
  893.                     Device.m_dwBehavior = D3DCREATE_MIXED_VERTEXPROCESSING;
  894.                     bCapsSufficient = AreCapsSufficient(&m_Caps, Device.m_dwBehavior);
  895.                 }
  896.             }
  897.  
  898.             if(!bCapsSufficient)
  899.             {
  900.                 // Try SW
  901.                 Device.m_dwBehavior = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  902.  
  903.                 m_Caps.VertexProcessingCaps = D3DVTXPCAPS_TEXGEN | D3DVTXPCAPS_MATERIALSOURCE7 |
  904.                     D3DVTXPCAPS_DIRECTIONALLIGHTS | D3DVTXPCAPS_POSITIONALLIGHTS | D3DVTXPCAPS_LOCALVIEWER;
  905.  
  906.                 m_Caps.MaxActiveLights           = 0xffffffff;
  907.                 m_Caps.MaxUserClipPlanes         = 6;
  908.                 m_Caps.MaxVertexBlendMatrices    = 4;
  909.                 m_Caps.MaxVertexBlendMatrixIndex = 255;
  910.  
  911.                 if(0.0f == m_Caps.MaxPointSize)
  912.                     m_Caps.MaxPointSize = 64.0f;
  913.  
  914.                 m_Caps.MaxPrimitiveCount         = 0xffffffff;
  915.                 m_Caps.MaxVertexIndex            = 0xffffffff;
  916.                 m_Caps.MaxStreams                = 16;
  917.                 m_Caps.MaxStreamStride           = 0xffffffff;
  918.                 m_Caps.VertexShaderVersion       = D3DVS_VERSION(1, 1);
  919.                 m_Caps.MaxVertexShaderConst      = 96;
  920.  
  921.                 bCapsSufficient = AreCapsSufficient(&m_Caps, Device.m_dwBehavior);
  922.             }
  923.  
  924.             if(!bCapsSufficient)
  925.                 continue;
  926.  
  927.  
  928.             // Iterate thru backbuffer counts
  929.             for(Params.BackBufferCount = uBBCMax; Params.BackBufferCount >= uBBCMin; Params.BackBufferCount--)
  930.             {
  931.  
  932.                 // Try to reuse current device
  933.                 if(m_pDevice)
  934.                 {
  935.                     if(!memcmp(&m_pData->m_Device, &Device, sizeof(D3DX_DEVICE)) &&
  936.                        !memcmp(&m_pData->m_Params, &Params, sizeof(D3DPRESENT_PARAMETERS)))
  937.                     {
  938.                         // Use existing device
  939.                         Action = EXISTING;
  940.                         break;
  941.                     }
  942.  
  943.                     if(m_pData->m_bDeviceReset)
  944.                     {
  945.                         m_pData->m_bDeviceReset = FALSE;
  946.  
  947.                         if(FAILED(hr = OnLostDevice()))
  948.                             DPF_HR(hr, "OnLostDevice failed");
  949.                     }
  950.  
  951.                     if(!memcmp(&m_pData->m_Device, &Device, sizeof(D3DX_DEVICE)))
  952.                     {
  953.                         // Reset existing device
  954.                         if(FAILED(hr = m_pDevice->Reset(&Params)))
  955.                         {
  956.                             DPF_HR(hr, "IDirect3DDevice9::Reset failed");
  957.                             continue;
  958.                         }
  959.  
  960.                         Action = RESET;
  961.                         break;
  962.                     }
  963.  
  964.                     if(m_pData->m_bDeviceCreated)
  965.                     {
  966.                         m_pData->m_bDeviceCreated = FALSE;
  967.  
  968.                         if(FAILED(hr = OnDestroyDevice()))
  969.                             DPF_HR(hr, "OnDestroyDevice failed");
  970.                     }
  971.  
  972.                     RELEASE(m_pDevice);
  973.                 }
  974.  
  975.                 // Try to create device
  976.                 if(FAILED(m_pD3D->CreateDevice(Device.m_uAdapter, Device.m_DevType, m_hwnd, 
  977.                     Device.m_dwBehavior, &Params, &m_pDevice)))
  978.                 {
  979.                     continue;
  980.                 }
  981.  
  982.                 Action = CREATE;
  983.                 break;
  984.             }
  985.  
  986.             if(Params.BackBufferCount < uBBCMin)
  987.                 continue;
  988.  
  989.             break;
  990.         }
  991.  
  992.         if(pAdapter == pAdapterLim)
  993.             continue;
  994.  
  995.         break;
  996.     }
  997.  
  998.  
  999.     // No suitable device found
  1000.     if(NONE == Action)
  1001.     {
  1002.         if(m_pDevice)
  1003.         {
  1004.             if(m_pData->m_bDeviceReset)
  1005.             {
  1006.                 m_pData->m_bDeviceReset = FALSE;
  1007.  
  1008.                 if(FAILED(hr = OnLostDevice()))
  1009.                     DPF_HR(hr, "OnLostDevice failed");
  1010.             }
  1011.  
  1012.             if(m_pData->m_bDeviceCreated)
  1013.             {
  1014.                 m_pData->m_bDeviceCreated = FALSE;
  1015.  
  1016.                 if(FAILED(hr = OnDestroyDevice()))
  1017.                     DPF_HR(hr, "OnDestroyDevice failed");
  1018.             }
  1019.  
  1020.             RELEASE(m_pDevice);
  1021.         }
  1022.  
  1023.         DPF_HR(0, "No suitable device found");
  1024.         m_pData->m_bInReset = FALSE;
  1025.         return E_FAIL;
  1026.     }
  1027.  
  1028.  
  1029.     // Device found!
  1030.     if(EXISTING != Action)
  1031.     {
  1032.         m_pData->m_Device   = Device;
  1033.         m_pData->m_Params   = Params;
  1034.         m_PresentParameters = Params;
  1035.  
  1036.  
  1037. #if DBG
  1038.         char szDbg[256];
  1039.         char sz[256];
  1040.  
  1041.         switch(Action)
  1042.         {
  1043.         case RESET:  strcpy(szDbg, "reset "); break;
  1044.         case CREATE: strcpy(szDbg, "create "); break;
  1045.         default:     strcpy(szDbg, "??? "); break;
  1046.         }
  1047.  
  1048.         sprintf(sz, "(card%d ", Device.m_uAdapter);
  1049.         strcat(szDbg, sz);
  1050.  
  1051.         if(Device.m_dwBehavior & D3DCREATE_PUREDEVICE)
  1052.             strcat(szDbg, "pure ");
  1053.  
  1054.         if(Device.m_dwBehavior & D3DCREATE_SOFTWARE_VERTEXPROCESSING)
  1055.             strcat(szDbg, "sw ");
  1056.         else if(Device.m_dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING)
  1057.             strcat(szDbg, "hw ");
  1058.         else if(Device.m_dwBehavior & D3DCREATE_MIXED_VERTEXPROCESSING)
  1059.             strcat(szDbg, "mixed ");
  1060.  
  1061.         if(D3DDEVTYPE_HAL == Device.m_DevType)
  1062.             strcat(szDbg, "hal ");
  1063.         else if(D3DDEVTYPE_SW == Device.m_DevType)
  1064.             strcat(szDbg, "emulation ");
  1065.         else if(D3DDEVTYPE_REF == Device.m_DevType)
  1066.             strcat(szDbg, "ref ");
  1067.  
  1068.         sprintf(sz, "%dx%d) ", Params.BackBufferWidth, Params.BackBufferHeight);
  1069.         strcat(szDbg, sz);
  1070.  
  1071.         DPF_HR(0, szDbg);
  1072. #endif
  1073.  
  1074.  
  1075.         BOOL bWasFullscreen = m_pData->m_bFullscreen;
  1076.         m_pData->m_bFullscreen = !Params.Windowed;
  1077.  
  1078.  
  1079.    
  1080.         // Set initial framerate estimate to half the monitor refresh rate.  This
  1081.         // is completely arbitrary, but it seems reasonable.
  1082.         D3DDISPLAYMODE AdapterMode;
  1083.  
  1084.         if(FAILED(m_pD3D->GetAdapterDisplayMode(Device.m_uAdapter, &AdapterMode)))
  1085.             AdapterMode.RefreshRate = 0;
  1086.  
  1087.         if(AdapterMode.RefreshRate)
  1088.             D3DXTimer_Start(&m_pData->m_Timer, (float) AdapterMode.RefreshRate * 0.5f);
  1089.         else
  1090.             D3DXTimer_Start(&m_pData->m_Timer, 30.0f);
  1091.  
  1092.  
  1093.  
  1094.         // Update window
  1095.         DWORD dwSWP = SWP_NOMOVE | SWP_NOSIZE;
  1096.  
  1097.         if(m_pData->m_bFullscreen)
  1098.         {
  1099.             dwSWP |= SWP_NOZORDER | SWP_SHOWWINDOW;
  1100.  
  1101.             // Remove border from window
  1102.             if(!m_pData->m_bCoverWindow)
  1103.             {
  1104.                 SetWindowLongPtr(m_hwnd, GWL_STYLE, WS_POPUP);
  1105.                 m_pData->m_bCoverWindow = TRUE;
  1106.                 dwSWP |= SWP_FRAMECHANGED;
  1107.             }
  1108.  
  1109.  
  1110.             // Calculate screen aspect
  1111.             m_pData->m_fScreenAspect = (4.0f * Params.BackBufferHeight) / (3.0f * Params.BackBufferWidth);
  1112.         }
  1113.         else
  1114.         {
  1115.             dwSWP |= SWP_SHOWWINDOW;
  1116.  
  1117.             // Add border to window, move back to orig position
  1118.             if(m_pData->m_bCoverWindow)
  1119.             {
  1120.                 SetWindowLongPtr(m_hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
  1121.                 SetWindowPlacement(m_hwnd, &m_pData->m_WindowPlacement);
  1122.                 InvalidateRect(NULL, NULL, TRUE);
  1123.                 m_pData->m_bCoverWindow = FALSE;
  1124.  
  1125.                 dwSWP |= SWP_FRAMECHANGED;
  1126.             }
  1127.  
  1128.  
  1129.             // Calculate screen aspect from current display mode
  1130.             D3DDISPLAYMODE mode;
  1131.  
  1132.             if(SUCCEEDED(m_pD3D->GetAdapterDisplayMode(Device.m_uAdapter, &mode)))
  1133.                 m_pData->m_fScreenAspect = (4.0f * mode.Height) / (3.0f * mode.Width);
  1134.             else
  1135.                 m_pData->m_fScreenAspect = 1.0f;
  1136.         }
  1137.  
  1138.         SetWindowPos(m_hwnd, HWND_TOP, 0, 0, 0, 0, dwSWP);
  1139.     }
  1140.  
  1141.  
  1142.  
  1143.     // Compute window aspect ratio
  1144.     if(!Params.Windowed)
  1145.         m_pData->m_fWindowAspect = (float) (Params.BackBufferWidth) / (float) (Params.BackBufferHeight);
  1146.     else if(WindowRect.right > WindowRect.left)
  1147.         m_pData->m_fWindowAspect = (float) (WindowRect.right - WindowRect.left) / (float) (WindowRect.bottom - WindowRect.top);
  1148.     else
  1149.         m_pData->m_fWindowAspect = 1.0f;
  1150.  
  1151.  
  1152.  
  1153.     // Create and Reset callbacks
  1154.     if(!m_pData->m_bDeviceCreated)
  1155.     {
  1156.         m_pData->m_bDeviceCreated = TRUE;
  1157.         m_pData->m_bDeviceReset = FALSE;
  1158.  
  1159.         if(FAILED(hr = OnCreateDevice()))
  1160.         {
  1161.             DPF_HR(hr, "OnCreateDevice failed");
  1162.             m_pData->m_bInReset = FALSE;
  1163.             return hr;
  1164.         }
  1165.     }
  1166.  
  1167.     if(!m_pData->m_bDeviceReset)
  1168.     {
  1169.         m_pData->m_bDeviceReset = TRUE;
  1170.  
  1171.         if(FAILED(hr = OnResetDevice()))
  1172.         {
  1173.             DPF_HR(hr, "OnResetDevice failed");
  1174.             m_pData->m_bInReset = FALSE;
  1175.             return hr;
  1176.         }
  1177.     }
  1178.  
  1179.     m_pData->m_bInReset = FALSE;
  1180.     return S_OK;
  1181. }
  1182.  
  1183.  
  1184. HRESULT
  1185. CD3DXApplication::Run()
  1186. {
  1187.     MSG msg;
  1188.     HRESULT hr;
  1189.  
  1190.     if(!m_pData)
  1191.     {
  1192.         DPF_HR(0, "Application not initialized");
  1193.         return E_FAIL;
  1194.     }
  1195.  
  1196.     if(m_pData->m_bRunning)
  1197.     {
  1198.         DPF_HR(0, "Application is already running");
  1199.         return E_FAIL;
  1200.     }
  1201.  
  1202.     m_pData->m_bRunning    = TRUE;
  1203.     m_pData->m_bStopping   = FALSE;
  1204.     m_pData->m_bNeedReset  = TRUE;
  1205.     m_pData->m_bNeedDraw   = FALSE;
  1206.  
  1207.  
  1208.  
  1209.     // Main applcation loop
  1210.     while(!m_pData->m_bStopping)
  1211.     {
  1212.         // Reset the device
  1213.         if(m_pData->m_bNeedReset)
  1214.         {
  1215.             if(FAILED(hr = Reset(NULL)))
  1216.             {
  1217.                 m_pData->m_bRunning = FALSE;
  1218.                 break;
  1219.             }
  1220.  
  1221.             D3DXTimer_Start(&m_pData->m_Timer, m_pData->m_Timer.m_fFramesPerSec);
  1222.             m_pData->m_bNeedReset = FALSE;
  1223.         }
  1224.  
  1225.         // Look for messages in queue.  Application will dutifully process all 
  1226.         // incoming messages before trying to process a frame.
  1227.  
  1228.         if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
  1229.         {
  1230.             if(WM_QUIT == msg.message)
  1231.                 break;
  1232.  
  1233.             if(!TranslateAccelerator(m_hwnd, m_pData->m_hAccel, &msg))
  1234.             {
  1235.                 TranslateMessage(&msg);
  1236.                 DispatchMessage(&msg);
  1237.             }
  1238.         } 
  1239.         else
  1240.         {
  1241.             hr = m_pDevice->TestCooperativeLevel();
  1242.  
  1243.             if(D3D_OK == hr)
  1244.             {
  1245.                 // Device is available!  If the application is currently active,
  1246.                 // we will update and draw the scene.  If not, we will just idle.
  1247.  
  1248.                 if(m_pData->m_bActive)
  1249.                 {
  1250.                     if(FAILED(hr = Update()))
  1251.                         break;
  1252.  
  1253.                     if(m_pData->m_bStopping)
  1254.                         break;
  1255.                 }
  1256.  
  1257.                 if(m_pData->m_bActive || m_pData->m_bNeedDraw)
  1258.                 {
  1259.                     if(FAILED(hr = Draw()))
  1260.                         break;
  1261.  
  1262.                     m_pData->m_bNeedDraw = FALSE;
  1263.  
  1264.                     if(m_pData->m_bStopping)
  1265.                         break;
  1266.                 }
  1267.  
  1268.                 if(!m_pData->m_bActive)
  1269.                 {
  1270.                     if(FAILED(hr = OnIdle()))
  1271.                     {
  1272.                         DPF_HR(hr, "OnIdle failed");
  1273.                         break;
  1274.                     }
  1275.                 }
  1276.             }
  1277.             else if(D3DERR_DEVICENOTRESET == hr)
  1278.             {   
  1279.                 // The device is available, but needs to be Reset.
  1280.                 m_pData->m_bDeviceReset = FALSE;
  1281.  
  1282.                 if(FAILED(hr = OnLostDevice()))
  1283.                 {
  1284.                     DPF_HR(hr, "OnLostDevice failed");
  1285.                     break;
  1286.                 }
  1287.  
  1288.                 if(m_pData->m_bStopping)
  1289.                     break;
  1290.  
  1291.                 if(SUCCEEDED(hr = m_pDevice->Reset(&m_pData->m_Params)))
  1292.                 {
  1293.                     m_pData->m_bDeviceReset = TRUE;
  1294.  
  1295.                     if(FAILED(hr = OnResetDevice()))
  1296.                     {
  1297.                         DPF_HR(hr, "OnResetDevice failed");
  1298.                         break;
  1299.                     }
  1300.                 }
  1301.                 else
  1302.                 {
  1303.                     // Reset failed for some reason.  As a last-ditch effort,
  1304.                     // we will destroy the device and attempt to recreate, since
  1305.                     // there might be another adapter/devtype which will still work.
  1306.                     m_pData->m_bDeviceCreated = FALSE;
  1307.  
  1308.                     hr = OnDestroyDevice();
  1309.                     RELEASE(m_pDevice);
  1310.  
  1311.                     if(FAILED(hr))
  1312.                     {
  1313.                         DPF_HR(hr, "OnDestroyDevice failed");
  1314.                         break;
  1315.                     }
  1316.  
  1317.                     m_pData->m_bNeedReset = TRUE;
  1318.                 }
  1319.             }
  1320.             else if(D3DERR_DEVICELOST == hr)
  1321.             {
  1322.                 // Device is not currently available.  We will just idle until
  1323.                 // the device becomes available again.
  1324.  
  1325.                 if(FAILED(hr = OnIdle()))
  1326.                 {
  1327.                     DPF_HR(hr, "OnIdle failed");
  1328.                     break;
  1329.                 }
  1330.             }
  1331.         }
  1332.     }
  1333.  
  1334.  
  1335.     // Destroy the device, if one exists.
  1336.     if(m_pDevice)
  1337.     {
  1338.         HRESULT hrT;
  1339.  
  1340.         if(m_pData->m_bDeviceReset)
  1341.         {
  1342.             m_pData->m_bDeviceReset = FALSE;
  1343.  
  1344.             if(FAILED(hrT = OnLostDevice()))
  1345.             {
  1346.                 DPF_HR(hrT, "OnLostDevice failed");
  1347.                 hr = FAILED(hr) ? hr : hrT;
  1348.             }
  1349.         }
  1350.  
  1351.         if(m_pData->m_bDeviceCreated)
  1352.         {
  1353.             m_pData->m_bDeviceCreated = FALSE;
  1354.  
  1355.             if(FAILED(hrT = OnDestroyDevice()))
  1356.             {
  1357.                 DPF_HR(hrT, "OnDestroyDevice failed");
  1358.                 hr = FAILED(hr) ? hr : hrT;
  1359.             }
  1360.         }
  1361.  
  1362.         RELEASE(m_pDevice);
  1363.     }
  1364.  
  1365.     m_pData->m_bRunning = FALSE;
  1366.     return hr;
  1367. }
  1368.  
  1369.  
  1370. HRESULT 
  1371. CD3DXApplication::Stop()
  1372. {
  1373.     if(!m_pData)
  1374.     {
  1375.         DPF_HR(0, "Application not initialized");
  1376.         return E_FAIL;
  1377.     }
  1378.  
  1379.     if(!m_pData->m_bRunning)
  1380.     {
  1381.         DPF_HR(0, "Application is not running");
  1382.         return E_FAIL;
  1383.     }
  1384.  
  1385.     m_pData->m_bStopping = TRUE;
  1386.     return S_OK;
  1387. }
  1388.  
  1389.  
  1390. BOOL 
  1391. CD3DXApplication::IsRunning()
  1392. {
  1393.     return m_pData && m_pData->m_bRunning;
  1394. }
  1395.  
  1396.  
  1397. BOOL 
  1398. CD3DXApplication::IsFullscreen()
  1399. {
  1400.     return m_pData && m_pData->m_bFullscreen;
  1401. }
  1402.  
  1403.  
  1404. HRESULT
  1405. CD3DXApplication::Update()
  1406. {
  1407.     HRESULT hr;
  1408.  
  1409.     if(!m_pData)
  1410.     {
  1411.         DPF_HR(0, "Application not initialized");
  1412.         return E_FAIL;
  1413.     }
  1414.  
  1415.     if(!m_pData->m_bRunning)
  1416.     {
  1417.         DPF_HR(0, "Application is not running");
  1418.         return E_FAIL;
  1419.     }
  1420.  
  1421.     if(FAILED(hr = OnUpdate(m_pData->m_Timer.m_fSecsPerFrame)))
  1422.     {
  1423.         DPF_HR(hr, "OnUpdate failed");
  1424.         return hr;
  1425.     }
  1426.  
  1427.     if(m_pData->m_bActive)
  1428.         D3DXTimer_OnFrame(&m_pData->m_Timer);
  1429.  
  1430.     return S_OK;
  1431. }
  1432.  
  1433.  
  1434. HRESULT
  1435. CD3DXApplication::Draw()
  1436. {
  1437.     HRESULT hr;
  1438.     BOOL bRecreate = FALSE;
  1439.  
  1440.     if(!m_pData)
  1441.     {
  1442.         DPF_HR(0, "Application not initialized");
  1443.         return E_FAIL;
  1444.     }
  1445.  
  1446.     if(!m_pData->m_bRunning)
  1447.     {
  1448.         DPF_HR(0, "Application is not running");
  1449.         return E_FAIL;
  1450.     }
  1451.  
  1452.     if(!m_pDevice || m_pData->m_bDrawing || !m_pData->m_bDeviceCreated || !m_pData->m_bDeviceReset)
  1453.         return S_OK;
  1454.  
  1455.  
  1456.     // Calculate aspect ratio
  1457.     float fAspect = m_pData->m_fWindowAspect * m_pData->m_fScreenAspect;
  1458.  
  1459.  
  1460.     // Draw scene
  1461.     m_pDevice->BeginScene();
  1462.  
  1463.     m_pData->m_bDrawing = TRUE;
  1464.     hr = OnDraw(fAspect);
  1465.     m_pData->m_bDrawing = FALSE;
  1466.  
  1467.     m_pDevice->EndScene();
  1468.  
  1469.     if(FAILED(hr))
  1470.     {
  1471.         DPF_HR(hr, "OnDraw failed");
  1472.         return hr;
  1473.     }
  1474.  
  1475.     RECT r;
  1476.     GetClientRect(m_hwnd, &r);
  1477.     r.top += 28;
  1478.     r.bottom -= 20;
  1479.     hr = m_pDevice->Present(NULL, &r, NULL, NULL);
  1480.     if (FAILED(hr))
  1481.         m_pData->m_bActive = FALSE;
  1482.     return S_OK;
  1483. }
  1484.  
  1485.  
  1486. BOOL 
  1487. CD3DXApplication::AreCapsSufficient(D3DCAPS9 *pCaps, DWORD dwBehavior)
  1488. {
  1489.     // (Default implementation - please override)
  1490.     return TRUE;
  1491. }
  1492.  
  1493.  
  1494. LRESULT 
  1495. CD3DXApplication::OnMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1496. {
  1497.     // (Default implementation - please override)
  1498.  
  1499.     switch(uMsg)
  1500.     {
  1501.     case WM_KEYDOWN:
  1502.         switch(wParam)
  1503.         {
  1504.         case VK_ESCAPE: // Exit app
  1505.             PostQuitMessage(0);
  1506.             break;
  1507.         }
  1508.  
  1509.         break;
  1510.  
  1511.     case WM_SETCURSOR:
  1512.         if(IsFullscreen())
  1513.         {
  1514.             SetCursor(NULL);
  1515.             return 0;
  1516.         }
  1517.         break;
  1518.     }
  1519.  
  1520.     return DefWindowProc(hwnd, uMsg, wParam, lParam);
  1521. }
  1522.  
  1523.  
  1524. HRESULT 
  1525. CD3DXApplication::OnUpdate(float fSecsPerFrame)
  1526. {
  1527.     // (Default implementation - please override)
  1528.     return S_OK;
  1529. }
  1530.  
  1531.  
  1532. HRESULT 
  1533. CD3DXApplication::OnDraw(float fAspectRatio)
  1534. {
  1535.     // (Default implementation - please override)
  1536.     m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0x00000000, 1.0f, 0x00);
  1537.  
  1538.     // Just to be nice
  1539.     Sleep(1);
  1540.  
  1541.     return S_OK;
  1542. }
  1543.  
  1544.  
  1545. HRESULT 
  1546. CD3DXApplication::OnIdle()
  1547. {
  1548.     // (Default implementation - please override)
  1549.     WaitMessage();
  1550.     return S_OK;
  1551. }
  1552.  
  1553.  
  1554. HRESULT 
  1555. CD3DXApplication::OnCreateDevice()
  1556. {
  1557.     // (Default implementation - please override)
  1558.     return S_OK;
  1559. }
  1560.  
  1561.  
  1562. HRESULT 
  1563. CD3DXApplication::OnResetDevice()
  1564. {
  1565.     // (Default implementation - please override)
  1566.     return S_OK;
  1567. }
  1568.  
  1569.  
  1570. HRESULT 
  1571. CD3DXApplication::OnLostDevice()
  1572. {
  1573.     // (Default implementation - please override)
  1574.     return S_OK;
  1575. }
  1576.  
  1577.  
  1578. HRESULT 
  1579. CD3DXApplication::OnDestroyDevice()
  1580. {
  1581.     // (Default implementation - please override)
  1582.     return S_OK;
  1583. }
  1584.  
  1585.  
  1586. LRESULT CALLBACK 
  1587. CD3DXApplication::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1588. {
  1589.     PAINTSTRUCT ps;
  1590.  
  1591.     CD3DXApplication *pApp = (CD3DXApplication *) (LPVOID) GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1592.  
  1593.     if(WM_CLOSE == uMsg)
  1594.         PostQuitMessage(0);
  1595.  
  1596.     if(!pApp)
  1597.         return DefWindowProc(hwnd, uMsg, wParam, lParam);
  1598.  
  1599.     if(pApp->m_pData)
  1600.     {
  1601.         switch(uMsg)
  1602.         {
  1603.         case WM_ACTIVATEAPP:
  1604.             if(!LOWORD(wParam) && pApp->m_pData->m_bActive)
  1605.             {
  1606.                 pApp->m_pData->m_bActive = FALSE;
  1607.             }
  1608.             else if(LOWORD(wParam) && !pApp->m_pData->m_bActive)
  1609.             {
  1610.                 pApp->m_pData->m_bActive = TRUE;
  1611.                 D3DXTimer_Start(&pApp->m_pData->m_Timer, pApp->m_pData->m_Timer.m_fFramesPerSec);
  1612.             }
  1613.             if (HIWORD(wParam))
  1614.             {
  1615.                 pApp->m_pData->m_bActive = FALSE;
  1616.             }
  1617.  
  1618.             if (IsIconic(pApp->m_hwnd))
  1619.                 pApp->m_pData->m_bActive = FALSE;
  1620.  
  1621.  
  1622.             break;
  1623.  
  1624.  
  1625.         case WM_ENTERSIZEMOVE:
  1626.             if(!pApp->m_pData->m_bFullscreen)
  1627.                 pApp->m_pData->m_bInSizeMove = TRUE;
  1628.  
  1629.             break;
  1630.  
  1631.         case WM_SIZE:
  1632.             if(!pApp->m_pData->m_bFullscreen && !pApp->m_pData->m_bInSizeMove && !pApp->m_pData->m_bInReset)
  1633.                 pApp->m_pData->m_bNeedReset = TRUE;
  1634.             
  1635.             if(!pApp->m_pData->m_bFullscreen && LOWORD(lParam))
  1636.                 pApp->m_pData->m_fWindowAspect = (float) LOWORD(lParam) / (float) HIWORD(lParam);
  1637.  
  1638.             break;
  1639.             
  1640.         case WM_EXITSIZEMOVE:
  1641.             if(!pApp->m_pData->m_bFullscreen)
  1642.             {
  1643.                 pApp->m_pData->m_bInSizeMove = FALSE;
  1644.                 pApp->m_pData->m_bNeedReset  = TRUE;
  1645.                 pApp->m_pData->m_bNeedDraw   = TRUE;
  1646.             }
  1647.             break;
  1648.             
  1649.         case WM_PAINT:
  1650.             BeginPaint(hwnd, &ps);
  1651.  
  1652.             RECT r;
  1653.             GetClientRect(pApp->m_hwnd, &r);
  1654.             r.top += 28;
  1655.             r.bottom -= 20;
  1656.             pApp->m_pDevice->Present(NULL, &r, NULL, NULL);
  1657.  
  1658.             //pApp->Draw();
  1659.             pApp->m_pData->m_bNeedDraw = TRUE;
  1660.  
  1661.             EndPaint(hwnd, &ps);
  1662.             return 0L;
  1663.  
  1664.         case WM_ERASEBKGND:
  1665.             return 0L;
  1666.         }
  1667.     }
  1668.  
  1669.     return pApp->OnMessage(hwnd, uMsg, wParam, lParam);
  1670. }
  1671.  
  1672.