DXUTmisc.cpp
上传用户:junlon
上传日期:2022-01-05
资源大小:39075k
文件大小:130k
源码类别:

DirextX编程

开发平台:

Visual C++

  1. //--------------------------------------------------------------------------------------
  2. // File: DXUTMisc.cpp
  3. //
  4. // Shortcut macros and functions for using DX objects
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved
  7. //--------------------------------------------------------------------------------------
  8. #include "dxstdafx.h"
  9. #define DXUT_GAMEPAD_TRIGGER_THRESHOLD      30
  10. #undef min // use __min instead
  11. #undef max // use __max instead
  12. //--------------------------------------------------------------------------------------
  13. // Global/Static Members
  14. //--------------------------------------------------------------------------------------
  15. CDXUTResourceCache& DXUTGetGlobalResourceCache()
  16. {
  17.     // Using an accessor function gives control of the construction order
  18.     static CDXUTResourceCache cache;
  19.     return cache;
  20. }
  21. CDXUTTimer* DXUTGetGlobalTimer()
  22. {
  23.     // Using an accessor function gives control of the construction order
  24.     static CDXUTTimer timer;
  25.     return &timer;
  26. }
  27. //--------------------------------------------------------------------------------------
  28. // Internal functions forward declarations
  29. //--------------------------------------------------------------------------------------
  30. bool DXUTFindMediaSearchTypicalDirs( WCHAR* strSearchPath, int cchSearch, LPCWSTR strLeaf, WCHAR* strExePath, WCHAR* strExeName );
  31. bool DXUTFindMediaSearchParentDirs( WCHAR* strSearchPath, int cchSearch, WCHAR* strStartAt, WCHAR* strLeafName );
  32. INT_PTR CALLBACK DisplaySwitchToREFWarningProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  33. //--------------------------------------------------------------------------------------
  34. // Shared code for samples to ask user if they want to use a REF device or quit
  35. //--------------------------------------------------------------------------------------
  36. void DXUTDisplaySwitchingToREFWarning()
  37. {
  38.     if( DXUTGetShowMsgBoxOnError() )
  39.     {
  40.         // Open the appropriate registry key
  41.         DWORD dwSkipWarning = 0;
  42.         HKEY hKey;
  43.         LONG lResult = RegOpenKeyEx( HKEY_CURRENT_USER, L"Software\Microsoft\DirectX 9.0 SDK", 0, KEY_READ, &hKey );
  44.         if( ERROR_SUCCESS == lResult ) 
  45.         {
  46.             DWORD dwType;
  47.             DWORD dwSize = sizeof(DWORD);
  48.             lResult = RegQueryValueEx( hKey, L"Skip Warning On REF", NULL, &dwType, (BYTE*)&dwSkipWarning, &dwSize );
  49.             RegCloseKey( hKey );
  50.         }
  51.         if( dwSkipWarning == 0 )
  52.         {
  53.             // Compact code to create a custom dialog box without using a template in a resource file.
  54.             // If this dialog were in a .rc file, this would be a lot simpler but every sample calling this function would
  55.             // need a copy of the dialog in its own .rc file. Also MessageBox API could be used here instead, but 
  56.             // the MessageBox API is simpler to call but it can't provide a "Don't show again" checkbox
  57.             typedef struct { DLGITEMTEMPLATE a; WORD b; WORD c; WORD d; WORD e; WORD f; } DXUT_DLG_ITEM; 
  58.             typedef struct { DLGTEMPLATE a; WORD b; WORD c; WCHAR d[2]; WORD e; WCHAR f[14]; DXUT_DLG_ITEM i1; DXUT_DLG_ITEM i2; DXUT_DLG_ITEM i3; DXUT_DLG_ITEM i4; DXUT_DLG_ITEM i5; } DXUT_DLG_DATA; 
  59.             DXUT_DLG_DATA dtp = 
  60.             {                                                                                                                                                  
  61.                 {WS_CAPTION|WS_POPUP|WS_VISIBLE|WS_SYSMENU|DS_ABSALIGN|DS_3DLOOK|DS_SETFONT|DS_MODALFRAME|DS_CENTER,0,5,0,0,269,82},0,0,L" ",8,L"MS Sans Serif", 
  62.                 {{WS_CHILD|WS_VISIBLE|SS_ICON|SS_CENTERIMAGE,0,7,7,24,24,0x100},0xFFFF,0x0082,0,0,0}, // icon
  63.                 {{WS_CHILD|WS_VISIBLE,0,40,7,230,25,0x101},0xFFFF,0x0082,0,0,0}, // static text
  64.                 {{WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON,0,80,39,50,14,IDYES},0xFFFF,0x0080,0,0,0}, // Yes button
  65.                 {{WS_CHILD|WS_VISIBLE,0,133,39,50,14,IDNO},0xFFFF,0x0080,0,0,0}, // No button
  66.                 {{WS_CHILD|WS_VISIBLE|BS_CHECKBOX,0,7,59,70,16,IDIGNORE},0xFFFF,0x0080,0,0,0}, // checkbox
  67.             }; 
  68.             int nResult = (int) DialogBoxIndirect( DXUTGetHINSTANCE(), (DLGTEMPLATE*)&dtp, DXUTGetHWND(), DisplaySwitchToREFWarningProc ); 
  69.             if( (nResult & 0x80) == 0x80 ) // "Don't show again" checkbox was checked
  70.             {
  71.                 lResult = RegOpenKeyEx( HKEY_CURRENT_USER, L"Software\Microsoft\DirectX 9.0 SDK", 0, KEY_WRITE, &hKey );
  72.                 if( ERROR_SUCCESS == lResult ) 
  73.                 {
  74.                     dwSkipWarning = 1;
  75.                     RegSetValueEx( hKey, L"Skip Warning On REF", 0, REG_DWORD, (BYTE*)&dwSkipWarning, sizeof(DWORD) );
  76.                     RegCloseKey( hKey );
  77.                 }
  78.             }
  79.             // User choose not to continue
  80.             if( (nResult & 0x0F) == IDNO )
  81.                 DXUTShutdown(1);
  82.         }
  83.     }
  84. }
  85. //--------------------------------------------------------------------------------------
  86. // MsgProc for DXUTDisplaySwitchingToREFWarning() dialog box
  87. //--------------------------------------------------------------------------------------
  88. INT_PTR CALLBACK DisplaySwitchToREFWarningProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 
  89.     switch (message) 
  90.     { 
  91.         case WM_INITDIALOG:
  92.             // Easier to set text here than in the DLGITEMTEMPLATE
  93.             SetWindowText( hDlg, DXUTGetWindowTitle() );
  94.             SendMessage( GetDlgItem(hDlg, 0x100), STM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIcon(0, IDI_QUESTION));
  95.             SetDlgItemText( hDlg, 0x101, L"Switching to the Direct3D reference rasterizer, a software devicenthat implements the entire Direct3D feature set, but runs very slowly.nDo you wish to continue?" ); 
  96.             SetDlgItemText( hDlg, IDYES, L"&Yes" );
  97.             SetDlgItemText( hDlg, IDNO, L"&No" );
  98.             SetDlgItemText( hDlg, IDIGNORE, L"&Don't show again" );
  99.             break;
  100.         case WM_COMMAND: 
  101.             switch (LOWORD(wParam)) 
  102.             { 
  103.                 case IDIGNORE: CheckDlgButton( hDlg, IDIGNORE, (IsDlgButtonChecked( hDlg, IDIGNORE ) == BST_CHECKED) ? BST_UNCHECKED : BST_CHECKED ); EnableWindow( GetDlgItem( hDlg, IDNO ), (IsDlgButtonChecked( hDlg, IDIGNORE ) != BST_CHECKED) ); break;
  104.                 case IDNO: EndDialog(hDlg, (IsDlgButtonChecked( hDlg, IDIGNORE ) == BST_CHECKED) ? IDNO|0x80 : IDNO|0x00 ); return TRUE; 
  105.                 case IDCANCEL:
  106.                 case IDYES: EndDialog(hDlg, (IsDlgButtonChecked( hDlg, IDIGNORE ) == BST_CHECKED) ? IDYES|0x80 : IDYES|0x00 ); return TRUE; 
  107.             } 
  108.             break;
  109.     } 
  110.     return FALSE; 
  111. //--------------------------------------------------------------------------------------
  112. CDXUTTimer::CDXUTTimer()
  113. {
  114.     m_bTimerStopped     = true;
  115.     m_llQPFTicksPerSec  = 0;
  116.     m_llStopTime        = 0;
  117.     m_llLastElapsedTime = 0;
  118.     m_llBaseTime        = 0;
  119.     // Use QueryPerformanceFrequency to get the frequency of the counter
  120.     LARGE_INTEGER qwTicksPerSec;
  121.     QueryPerformanceFrequency( &qwTicksPerSec );
  122.     m_llQPFTicksPerSec = qwTicksPerSec.QuadPart;
  123. }
  124. //--------------------------------------------------------------------------------------
  125. void CDXUTTimer::Reset()
  126. {
  127.     LARGE_INTEGER qwTime = GetAdjustedCurrentTime();
  128.     
  129.     m_llBaseTime        = qwTime.QuadPart;
  130.     m_llLastElapsedTime = qwTime.QuadPart;
  131.     m_llStopTime        = 0;
  132.     m_bTimerStopped     = FALSE;
  133. }
  134. //--------------------------------------------------------------------------------------
  135. void CDXUTTimer::Start()
  136. {
  137.     // Get the current time
  138.     LARGE_INTEGER qwTime;
  139.     QueryPerformanceCounter( &qwTime );
  140.     if( m_bTimerStopped )
  141.         m_llBaseTime += qwTime.QuadPart - m_llStopTime;
  142.     m_llStopTime = 0;
  143.     m_llLastElapsedTime = qwTime.QuadPart;
  144.     m_bTimerStopped = FALSE;
  145. }
  146. //--------------------------------------------------------------------------------------
  147. void CDXUTTimer::Stop()
  148. {
  149.     if( !m_bTimerStopped )
  150.     {
  151.         LARGE_INTEGER qwTime;
  152.         QueryPerformanceCounter( &qwTime );
  153.         m_llStopTime = qwTime.QuadPart;
  154.         m_llLastElapsedTime = qwTime.QuadPart;
  155.         m_bTimerStopped = TRUE;
  156.     }
  157. }
  158. //--------------------------------------------------------------------------------------
  159. void CDXUTTimer::Advance()
  160. {
  161.     m_llStopTime += m_llQPFTicksPerSec/10;
  162. }
  163. //--------------------------------------------------------------------------------------
  164. double CDXUTTimer::GetAbsoluteTime()
  165. {
  166.     LARGE_INTEGER qwTime;
  167.     QueryPerformanceCounter( &qwTime );
  168.     double fTime = qwTime.QuadPart / (double) m_llQPFTicksPerSec;
  169.     return fTime;
  170. }
  171. //--------------------------------------------------------------------------------------
  172. double CDXUTTimer::GetTime()
  173. {
  174.     LARGE_INTEGER qwTime = GetAdjustedCurrentTime();
  175.     double fAppTime = (double) ( qwTime.QuadPart - m_llBaseTime ) / (double) m_llQPFTicksPerSec;
  176.     return fAppTime;
  177. }
  178. //--------------------------------------------------------------------------------------
  179. void CDXUTTimer::GetTimeValues( double* pfTime, double* pfAbsoluteTime, float* pfElapsedTime )
  180. {
  181.     assert( pfTime && pfAbsoluteTime && pfElapsedTime );    
  182.     LARGE_INTEGER qwTime = GetAdjustedCurrentTime();
  183.     float fElapsedTime = (float) ((double) ( qwTime.QuadPart - m_llLastElapsedTime ) / (double) m_llQPFTicksPerSec);
  184.     m_llLastElapsedTime = qwTime.QuadPart;
  185.     // Clamp the timer to non-negative values to ensure the timer is accurate.
  186.     // fElapsedTime can be outside this range if processor goes into a 
  187.     // power save mode or we somehow get shuffled to another processor.  
  188.     // However, the main thread should call SetThreadAffinityMask to ensure that 
  189.     // we don't get shuffled to another processor.  Other worker threads should NOT call 
  190.     // SetThreadAffinityMask, but use a shared copy of the timer data gathered from 
  191.     // the main thread.
  192.     if( fElapsedTime < 0.0f )
  193.         fElapsedTime = 0.0f;
  194.     
  195.     *pfAbsoluteTime = qwTime.QuadPart / (double) m_llQPFTicksPerSec;
  196.     *pfTime = ( qwTime.QuadPart - m_llBaseTime ) / (double) m_llQPFTicksPerSec;   
  197.     *pfElapsedTime = fElapsedTime;
  198. }
  199. //--------------------------------------------------------------------------------------
  200. double CDXUTTimer::GetElapsedTime()
  201. {
  202.     LARGE_INTEGER qwTime = GetAdjustedCurrentTime();
  203.     double fElapsedTime = (double) ( qwTime.QuadPart - m_llLastElapsedTime ) / (double) m_llQPFTicksPerSec;
  204.     m_llLastElapsedTime = qwTime.QuadPart;
  205.     // See the explanation about clamping in CDXUTTimer::GetTimeValues()
  206.     if( fElapsedTime < 0.0f )
  207.         fElapsedTime = 0.0f;
  208.     return fElapsedTime;
  209. }
  210. //--------------------------------------------------------------------------------------
  211. // If stopped, returns time when stopped otherwise returns current time
  212. //--------------------------------------------------------------------------------------
  213. LARGE_INTEGER CDXUTTimer::GetAdjustedCurrentTime()
  214. {
  215.     LARGE_INTEGER qwTime;
  216.     if( m_llStopTime != 0 )
  217.         qwTime.QuadPart = m_llStopTime;
  218.     else
  219.         QueryPerformanceCounter( &qwTime );
  220.     return qwTime;
  221. }
  222. //--------------------------------------------------------------------------------------
  223. bool CDXUTTimer::IsStopped()
  224. {
  225.     return m_bTimerStopped;
  226. }
  227. //--------------------------------------------------------------------------------------
  228. // Limit the current thread to one processor (the current one). This ensures that timing code 
  229. // runs on only one processor, and will not suffer any ill effects from power management.
  230. // See "Game Timing and Multicore Processors" for more details
  231. //--------------------------------------------------------------------------------------
  232. void CDXUTTimer::LimitThreadAffinityToCurrentProc()
  233. {
  234.     HANDLE hCurrentProcess = GetCurrentProcess();
  235.     
  236.     // Get the processor affinity mask for this process
  237.     DWORD_PTR dwProcessAffinityMask = 0;
  238.     DWORD_PTR dwSystemAffinityMask = 0;
  239.     
  240.     if( GetProcessAffinityMask( hCurrentProcess, &dwProcessAffinityMask, &dwSystemAffinityMask ) != 0 && dwProcessAffinityMask )
  241.     {
  242.         // Find the lowest processor that our process is allows to run against
  243.         DWORD_PTR dwAffinityMask = ( dwProcessAffinityMask & ((~dwProcessAffinityMask) + 1 ) );
  244.         // Set this as the processor that our thread must always run against
  245.         // This must be a subset of the process affinity mask
  246.         HANDLE hCurrentThread = GetCurrentThread();
  247.         if( INVALID_HANDLE_VALUE != hCurrentThread )
  248.         {
  249.             SetThreadAffinityMask( hCurrentThread, dwAffinityMask );
  250.             CloseHandle( hCurrentThread );
  251.         }
  252.     }
  253.     CloseHandle( hCurrentProcess );
  254. }
  255. //--------------------------------------------------------------------------------------
  256. // Returns pointer to static media search buffer
  257. //--------------------------------------------------------------------------------------
  258. WCHAR* DXUTMediaSearchPath()
  259. {
  260.     static WCHAR s_strMediaSearchPath[MAX_PATH] = {0};
  261.     return s_strMediaSearchPath;
  262. }   
  263. //--------------------------------------------------------------------------------------
  264. LPCWSTR DXUTGetMediaSearchPath()
  265. {
  266.     return DXUTMediaSearchPath();
  267. }
  268. //--------------------------------------------------------------------------------------
  269. HRESULT DXUTSetMediaSearchPath( LPCWSTR strPath )
  270. {
  271.     HRESULT hr;
  272.     WCHAR* s_strSearchPath = DXUTMediaSearchPath();
  273.     hr = StringCchCopy( s_strSearchPath, MAX_PATH, strPath );   
  274.     if( SUCCEEDED(hr) )
  275.     {
  276.         // append slash if needed
  277.         size_t ch;
  278.         hr = StringCchLength( s_strSearchPath, MAX_PATH, &ch );
  279.         if( SUCCEEDED(hr) && s_strSearchPath[ch-1] != L'\')
  280.         {
  281.             hr = StringCchCat( s_strSearchPath, MAX_PATH, L"\" );
  282.         }
  283.     }
  284.     return hr;
  285. }
  286. //--------------------------------------------------------------------------------------
  287. // Tries to find the location of a SDK media file
  288. //       cchDest is the size in WCHARs of strDestPath.  Be careful not to 
  289. //       pass in sizeof(strDest) on UNICODE builds.
  290. //--------------------------------------------------------------------------------------
  291. HRESULT DXUTFindDXSDKMediaFileCch( WCHAR* strDestPath, int cchDest, LPCWSTR strFilename )
  292. {
  293.     bool bFound;
  294.     WCHAR strSearchFor[MAX_PATH];
  295.     
  296.     if( NULL==strFilename || strFilename[0] == 0 || NULL==strDestPath || cchDest < 10 )
  297.         return E_INVALIDARG;
  298.     // Get the exe name, and exe path
  299.     WCHAR strExePath[MAX_PATH] = {0};
  300.     WCHAR strExeName[MAX_PATH] = {0};
  301.     WCHAR* strLastSlash = NULL;
  302.     GetModuleFileName( NULL, strExePath, MAX_PATH );
  303.     strExePath[MAX_PATH-1]=0;
  304.     strLastSlash = wcsrchr( strExePath, TEXT('\') );
  305.     if( strLastSlash )
  306.     {
  307.         StringCchCopy( strExeName, MAX_PATH, &strLastSlash[1] );
  308.         // Chop the exe name from the exe path
  309.         *strLastSlash = 0;
  310.         // Chop the .exe from the exe name
  311.         strLastSlash = wcsrchr( strExeName, TEXT('.') );
  312.         if( strLastSlash )
  313.             *strLastSlash = 0;
  314.     }
  315.     // Typical directories:
  316.     //      .
  317.     //      ..
  318.     //      ....
  319.     //      %EXE_DIR%
  320.     //      %EXE_DIR%..
  321.     //      %EXE_DIR%....
  322.     //      %EXE_DIR%..%EXE_NAME%
  323.     //      %EXE_DIR%....%EXE_NAME%
  324.     // Typical directory search
  325.     bFound = DXUTFindMediaSearchTypicalDirs( strDestPath, cchDest, strFilename, strExePath, strExeName );
  326.     if( bFound )
  327.         return S_OK;
  328.     // Typical directory search again, but also look in a subdir called "media" 
  329.     StringCchPrintf( strSearchFor, MAX_PATH, L"media\%s", strFilename ); 
  330.     bFound = DXUTFindMediaSearchTypicalDirs( strDestPath, cchDest, strSearchFor, strExePath, strExeName );
  331.     if( bFound )
  332.         return S_OK;
  333.     WCHAR strLeafName[MAX_PATH] = {0};
  334.     // Search all parent directories starting at . and using strFilename as the leaf name
  335.     StringCchCopy( strLeafName, MAX_PATH, strFilename ); 
  336.     bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, L".", strLeafName );
  337.     if( bFound )
  338.         return S_OK;
  339.     // Search all parent directories starting at the exe's dir and using strFilename as the leaf name
  340.     bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, strExePath, strLeafName );
  341.     if( bFound )
  342.         return S_OK;
  343.     // Search all parent directories starting at . and using "mediastrFilename" as the leaf name
  344.     StringCchPrintf( strLeafName, MAX_PATH, L"media\%s", strFilename ); 
  345.     bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, L".", strLeafName );
  346.     if( bFound )
  347.         return S_OK;
  348.     // Search all parent directories starting at the exe's dir and using "mediastrFilename" as the leaf name
  349.     bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, strExePath, strLeafName );
  350.     if( bFound )
  351.         return S_OK;
  352.     // On failure, return the file as the path but also return an error code
  353.     StringCchCopy( strDestPath, cchDest, strFilename );
  354.     return DXUTERR_MEDIANOTFOUND;
  355. }
  356. //--------------------------------------------------------------------------------------
  357. // Search a set of typical directories
  358. //--------------------------------------------------------------------------------------
  359. bool DXUTFindMediaSearchTypicalDirs( WCHAR* strSearchPath, int cchSearch, LPCWSTR strLeaf, 
  360.                                      WCHAR* strExePath, WCHAR* strExeName )
  361. {
  362.     // Typical directories:
  363.     //      .
  364.     //      ..
  365.     //      ....
  366.     //      %EXE_DIR%
  367.     //      %EXE_DIR%..
  368.     //      %EXE_DIR%....
  369.     //      %EXE_DIR%..%EXE_NAME%
  370.     //      %EXE_DIR%....%EXE_NAME%
  371.     //      DXSDK media path
  372.     // Search in .  
  373.     StringCchCopy( strSearchPath, cchSearch, strLeaf ); 
  374.     if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
  375.         return true;
  376.     // Search in ..  
  377.     StringCchPrintf( strSearchPath, cchSearch, L"..\%s", strLeaf ); 
  378.     if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
  379.         return true;
  380.     // Search in .... 
  381.     StringCchPrintf( strSearchPath, cchSearch, L"..\..\%s", strLeaf ); 
  382.     if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
  383.         return true;
  384.     // Search in .... 
  385.     StringCchPrintf( strSearchPath, cchSearch, L"..\..\%s", strLeaf ); 
  386.     if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
  387.         return true;
  388.     // Search in the %EXE_DIR% 
  389.     StringCchPrintf( strSearchPath, cchSearch, L"%s\%s", strExePath, strLeaf ); 
  390.     if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
  391.         return true;
  392.     // Search in the %EXE_DIR%.. 
  393.     StringCchPrintf( strSearchPath, cchSearch, L"%s\..\%s", strExePath, strLeaf ); 
  394.     if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
  395.         return true;
  396.     // Search in the %EXE_DIR%.... 
  397.     StringCchPrintf( strSearchPath, cchSearch, L"%s\..\..\%s", strExePath, strLeaf ); 
  398.     if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
  399.         return true;
  400.     // Search in "%EXE_DIR%..%EXE_NAME%".  This matches the DirectX SDK layout
  401.     StringCchPrintf( strSearchPath, cchSearch, L"%s\..\%s\%s", strExePath, strExeName, strLeaf ); 
  402.     if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
  403.         return true;
  404.     // Search in "%EXE_DIR%....%EXE_NAME%".  This matches the DirectX SDK layout
  405.     StringCchPrintf( strSearchPath, cchSearch, L"%s\..\..\%s\%s", strExePath, strExeName, strLeaf ); 
  406.     if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
  407.         return true;
  408.     // Search in media search dir 
  409.     WCHAR* s_strSearchPath = DXUTMediaSearchPath();
  410.     if( s_strSearchPath[0] != 0 )
  411.     {
  412.         StringCchPrintf( strSearchPath, cchSearch, L"%s%s", s_strSearchPath, strLeaf ); 
  413.         if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
  414.             return true;
  415.     }
  416.     return false;
  417. }
  418. //--------------------------------------------------------------------------------------
  419. // Search parent directories starting at strStartAt, and appending strLeafName
  420. // at each parent directory.  It stops at the root directory.
  421. //--------------------------------------------------------------------------------------
  422. bool DXUTFindMediaSearchParentDirs( WCHAR* strSearchPath, int cchSearch, WCHAR* strStartAt, WCHAR* strLeafName )
  423. {
  424.     WCHAR strFullPath[MAX_PATH] = {0};
  425.     WCHAR strFullFileName[MAX_PATH] = {0};
  426.     WCHAR strSearch[MAX_PATH] = {0};
  427.     WCHAR* strFilePart = NULL;
  428.     GetFullPathName( strStartAt, MAX_PATH, strFullPath, &strFilePart );
  429.     if( strFilePart == NULL )
  430.         return false;
  431.    
  432.     while( strFilePart != NULL && *strFilePart != '' )
  433.     {
  434.         StringCchPrintf( strFullFileName, MAX_PATH, L"%s\%s", strFullPath, strLeafName ); 
  435.         if( GetFileAttributes( strFullFileName ) != 0xFFFFFFFF )
  436.         {
  437.             StringCchCopy( strSearchPath, cchSearch, strFullFileName ); 
  438.             return true;
  439.         }
  440.         StringCchPrintf( strSearch, MAX_PATH, L"%s\..", strFullPath ); 
  441.         GetFullPathName( strSearch, MAX_PATH, strFullPath, &strFilePart );
  442.     }
  443.     return false;
  444. }
  445. //--------------------------------------------------------------------------------------
  446. // CDXUTResourceCache
  447. //--------------------------------------------------------------------------------------
  448. CDXUTResourceCache::~CDXUTResourceCache()
  449. {
  450.     OnDestroyDevice();
  451.     m_TextureCache.RemoveAll();
  452.     m_EffectCache.RemoveAll();
  453.     m_FontCache.RemoveAll();
  454. }
  455. HRESULT CDXUTResourceCache::CreateTextureFromFile( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, LPDIRECT3DTEXTURE9 *ppTexture )
  456. {
  457.     return CreateTextureFromFileEx( pDevice, pSrcFile, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
  458.                                     0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT,
  459.                                     0, NULL, NULL, ppTexture );
  460. }
  461. //--------------------------------------------------------------------------------------
  462. HRESULT CDXUTResourceCache::CreateTextureFromFileEx( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, UINT Width, UINT Height, UINT MipLevels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, DWORD Filter, DWORD MipFilter, D3DCOLOR ColorKey, D3DXIMAGE_INFO *pSrcInfo, PALETTEENTRY *pPalette, LPDIRECT3DTEXTURE9 *ppTexture )
  463. {
  464.     // Search the cache for a matching entry.
  465.     for( int i = 0; i < m_TextureCache.GetSize(); ++i )
  466.     {
  467.         DXUTCache_Texture &Entry = m_TextureCache[i];
  468.         if( Entry.Location == DXUTCACHE_LOCATION_FILE &&
  469.             !lstrcmpW( Entry.wszSource, pSrcFile ) &&
  470.             Entry.Width == Width &&
  471.             Entry.Height == Height &&
  472.             Entry.MipLevels == MipLevels &&
  473.             Entry.Usage == Usage &&
  474.             Entry.Format == Format &&
  475.             Entry.Pool == Pool &&
  476.             Entry.Type == D3DRTYPE_TEXTURE )
  477.         {
  478.             // A match is found. Obtain the IDirect3DTexture9 interface and return that.
  479.             return Entry.pTexture->QueryInterface( IID_IDirect3DTexture9, (LPVOID*)ppTexture );
  480.         }
  481.     }
  482.     HRESULT hr;
  483.     // No matching entry.  Load the resource and create a new entry.
  484.     hr = D3DXCreateTextureFromFileEx( pDevice, pSrcFile, Width, Height, MipLevels, Usage, Format,
  485.                                       Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppTexture );
  486.     if( FAILED( hr ) )
  487.         return hr;
  488.     DXUTCache_Texture NewEntry;
  489.     NewEntry.Location = DXUTCACHE_LOCATION_FILE;
  490.     StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcFile );
  491.     NewEntry.Width = Width;
  492.     NewEntry.Height = Height;
  493.     NewEntry.MipLevels = MipLevels;
  494.     NewEntry.Usage = Usage;
  495.     NewEntry.Format = Format;
  496.     NewEntry.Pool = Pool;
  497.     NewEntry.Type = D3DRTYPE_TEXTURE;
  498.     (*ppTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
  499.     m_TextureCache.Add( NewEntry );
  500.     return S_OK;
  501. }
  502. //--------------------------------------------------------------------------------------
  503. HRESULT CDXUTResourceCache::CreateTextureFromResource( LPDIRECT3DDEVICE9 pDevice, HMODULE hSrcModule, LPCTSTR pSrcResource, LPDIRECT3DTEXTURE9 *ppTexture )
  504. {
  505.     return CreateTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, D3DX_DEFAULT, D3DX_DEFAULT,
  506.                                         D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT,
  507.                                         D3DX_DEFAULT, 0, NULL, NULL, ppTexture );
  508. }
  509. //--------------------------------------------------------------------------------------
  510. HRESULT CDXUTResourceCache::CreateTextureFromResourceEx( LPDIRECT3DDEVICE9 pDevice, HMODULE hSrcModule, LPCTSTR pSrcResource, UINT Width, UINT Height, UINT MipLevels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, DWORD Filter, DWORD MipFilter, D3DCOLOR ColorKey, D3DXIMAGE_INFO *pSrcInfo, PALETTEENTRY *pPalette, LPDIRECT3DTEXTURE9 *ppTexture )
  511. {
  512.     // Search the cache for a matching entry.
  513.     for( int i = 0; i < m_TextureCache.GetSize(); ++i )
  514.     {
  515.         DXUTCache_Texture &Entry = m_TextureCache[i];
  516.         if( Entry.Location == DXUTCACHE_LOCATION_RESOURCE &&
  517.             Entry.hSrcModule == hSrcModule &&
  518.             !lstrcmpW( Entry.wszSource, pSrcResource ) &&
  519.             Entry.Width == Width &&
  520.             Entry.Height == Height &&
  521.             Entry.MipLevels == MipLevels &&
  522.             Entry.Usage == Usage &&
  523.             Entry.Format == Format &&
  524.             Entry.Pool == Pool &&
  525.             Entry.Type == D3DRTYPE_TEXTURE )
  526.         {
  527.             // A match is found. Obtain the IDirect3DTexture9 interface and return that.
  528.             return Entry.pTexture->QueryInterface( IID_IDirect3DTexture9, (LPVOID*)ppTexture );
  529.         }
  530.     }
  531.     HRESULT hr;
  532.     // No matching entry.  Load the resource and create a new entry.
  533.     hr = D3DXCreateTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, Width, Height, MipLevels, Usage,
  534.                                           Format, Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppTexture );
  535.     if( FAILED( hr ) )
  536.         return hr;
  537.     DXUTCache_Texture NewEntry;
  538.     NewEntry.Location = DXUTCACHE_LOCATION_RESOURCE;
  539.     NewEntry.hSrcModule = hSrcModule;
  540.     StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcResource );
  541.     NewEntry.Width = Width;
  542.     NewEntry.Height = Height;
  543.     NewEntry.MipLevels = MipLevels;
  544.     NewEntry.Usage = Usage;
  545.     NewEntry.Format = Format;
  546.     NewEntry.Pool = Pool;
  547.     NewEntry.Type = D3DRTYPE_TEXTURE;
  548.     (*ppTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
  549.     m_TextureCache.Add( NewEntry );
  550.     return S_OK;
  551. }
  552. //--------------------------------------------------------------------------------------
  553. HRESULT CDXUTResourceCache::CreateCubeTextureFromFile( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, LPDIRECT3DCUBETEXTURE9 *ppCubeTexture )
  554. {
  555.     return CreateCubeTextureFromFileEx( pDevice, pSrcFile, D3DX_DEFAULT, D3DX_DEFAULT, 0,
  556.                                         D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT,
  557.                                         0, NULL, NULL, ppCubeTexture );
  558. }
  559. //--------------------------------------------------------------------------------------
  560. HRESULT CDXUTResourceCache::CreateCubeTextureFromFileEx( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, UINT Size, UINT MipLevels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, DWORD Filter, DWORD MipFilter, D3DCOLOR ColorKey, D3DXIMAGE_INFO *pSrcInfo, PALETTEENTRY *pPalette, LPDIRECT3DCUBETEXTURE9 *ppCubeTexture )
  561. {
  562.     // Search the cache for a matching entry.
  563.     for( int i = 0; i < m_TextureCache.GetSize(); ++i )
  564.     {
  565.         DXUTCache_Texture &Entry = m_TextureCache[i];
  566.         if( Entry.Location == DXUTCACHE_LOCATION_FILE &&
  567.             !lstrcmpW( Entry.wszSource, pSrcFile ) &&
  568.             Entry.Width == Size &&
  569.             Entry.MipLevels == MipLevels &&
  570.             Entry.Usage == Usage &&
  571.             Entry.Format == Format &&
  572.             Entry.Pool == Pool &&
  573.             Entry.Type == D3DRTYPE_CUBETEXTURE )
  574.         {
  575.             // A match is found. Obtain the IDirect3DCubeTexture9 interface and return that.
  576.             return Entry.pTexture->QueryInterface( IID_IDirect3DCubeTexture9, (LPVOID*)ppCubeTexture );
  577.         }
  578.     }
  579.     HRESULT hr;
  580.     // No matching entry.  Load the resource and create a new entry.
  581.     hr = D3DXCreateCubeTextureFromFileEx( pDevice, pSrcFile, Size, MipLevels, Usage, Format, Pool, Filter,
  582.                                           MipFilter, ColorKey, pSrcInfo, pPalette, ppCubeTexture );
  583.     if( FAILED( hr ) )
  584.         return hr;
  585.     DXUTCache_Texture NewEntry;
  586.     NewEntry.Location = DXUTCACHE_LOCATION_FILE;
  587.     StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcFile );
  588.     NewEntry.Width = Size;
  589.     NewEntry.MipLevels = MipLevels;
  590.     NewEntry.Usage = Usage;
  591.     NewEntry.Format = Format;
  592.     NewEntry.Pool = Pool;
  593.     NewEntry.Type = D3DRTYPE_CUBETEXTURE;
  594.     (*ppCubeTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
  595.     m_TextureCache.Add( NewEntry );
  596.     return S_OK;
  597. }
  598. //--------------------------------------------------------------------------------------
  599. HRESULT CDXUTResourceCache::CreateCubeTextureFromResource( LPDIRECT3DDEVICE9 pDevice, HMODULE hSrcModule, LPCTSTR pSrcResource, LPDIRECT3DCUBETEXTURE9 *ppCubeTexture )
  600. {
  601.     return CreateCubeTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, D3DX_DEFAULT, D3DX_DEFAULT,
  602.                                             0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT,
  603.                                             0, NULL, NULL, ppCubeTexture );
  604. }
  605. //--------------------------------------------------------------------------------------
  606. HRESULT CDXUTResourceCache::CreateCubeTextureFromResourceEx( LPDIRECT3DDEVICE9 pDevice, HMODULE hSrcModule, LPCTSTR pSrcResource, UINT Size, UINT MipLevels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, DWORD Filter, DWORD MipFilter, D3DCOLOR ColorKey, D3DXIMAGE_INFO *pSrcInfo, PALETTEENTRY *pPalette, LPDIRECT3DCUBETEXTURE9 *ppCubeTexture )
  607. {
  608.     // Search the cache for a matching entry.
  609.     for( int i = 0; i < m_TextureCache.GetSize(); ++i )
  610.     {
  611.         DXUTCache_Texture &Entry = m_TextureCache[i];
  612.         if( Entry.Location == DXUTCACHE_LOCATION_RESOURCE &&
  613.             Entry.hSrcModule == hSrcModule &&
  614.             !lstrcmpW( Entry.wszSource, pSrcResource ) &&
  615.             Entry.Width == Size &&
  616.             Entry.MipLevels == MipLevels &&
  617.             Entry.Usage == Usage &&
  618.             Entry.Format == Format &&
  619.             Entry.Pool == Pool &&
  620.             Entry.Type == D3DRTYPE_CUBETEXTURE )
  621.         {
  622.             // A match is found. Obtain the IDirect3DCubeTexture9 interface and return that.
  623.             return Entry.pTexture->QueryInterface( IID_IDirect3DCubeTexture9, (LPVOID*)ppCubeTexture );
  624.         }
  625.     }
  626.     HRESULT hr;
  627.     // No matching entry.  Load the resource and create a new entry.
  628.     hr = D3DXCreateCubeTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, Size, MipLevels, Usage, Format,
  629.                                               Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppCubeTexture );
  630.     if( FAILED( hr ) )
  631.         return hr;
  632.     DXUTCache_Texture NewEntry;
  633.     NewEntry.Location = DXUTCACHE_LOCATION_RESOURCE;
  634.     NewEntry.hSrcModule = hSrcModule;
  635.     StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcResource );
  636.     NewEntry.Width = Size;
  637.     NewEntry.MipLevels = MipLevels;
  638.     NewEntry.Usage = Usage;
  639.     NewEntry.Format = Format;
  640.     NewEntry.Pool = Pool;
  641.     NewEntry.Type = D3DRTYPE_CUBETEXTURE;
  642.     (*ppCubeTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
  643.     m_TextureCache.Add( NewEntry );
  644.     return S_OK;
  645. }
  646. //--------------------------------------------------------------------------------------
  647. HRESULT CDXUTResourceCache::CreateVolumeTextureFromFile( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, LPDIRECT3DVOLUMETEXTURE9 *ppVolumeTexture )
  648. {
  649.     return CreateVolumeTextureFromFileEx( pDevice, pSrcFile, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
  650.                                           0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT,
  651.                                           0, NULL, NULL, ppVolumeTexture );
  652. }
  653. //--------------------------------------------------------------------------------------
  654. HRESULT CDXUTResourceCache::CreateVolumeTextureFromFileEx( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, UINT Width, UINT Height, UINT Depth, UINT MipLevels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, DWORD Filter, DWORD MipFilter, D3DCOLOR ColorKey, D3DXIMAGE_INFO *pSrcInfo, PALETTEENTRY *pPalette, LPDIRECT3DVOLUMETEXTURE9 *ppTexture )
  655. {
  656.     // Search the cache for a matching entry.
  657.     for( int i = 0; i < m_TextureCache.GetSize(); ++i )
  658.     {
  659.         DXUTCache_Texture &Entry = m_TextureCache[i];
  660.         if( Entry.Location == DXUTCACHE_LOCATION_FILE &&
  661.             !lstrcmpW( Entry.wszSource, pSrcFile ) &&
  662.             Entry.Width == Width &&
  663.             Entry.Height == Height &&
  664.             Entry.Depth == Depth &&
  665.             Entry.MipLevels == MipLevels &&
  666.             Entry.Usage == Usage &&
  667.             Entry.Format == Format &&
  668.             Entry.Pool == Pool &&
  669.             Entry.Type == D3DRTYPE_VOLUMETEXTURE )
  670.         {
  671.             // A match is found. Obtain the IDirect3DVolumeTexture9 interface and return that.
  672.             return Entry.pTexture->QueryInterface( IID_IDirect3DVolumeTexture9, (LPVOID*)ppTexture );
  673.         }
  674.     }
  675.     HRESULT hr;
  676.     // No matching entry.  Load the resource and create a new entry.
  677.     hr = D3DXCreateVolumeTextureFromFileEx( pDevice, pSrcFile, Width, Height, Depth, MipLevels, Usage, Format,
  678.                                             Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppTexture );
  679.     if( FAILED( hr ) )
  680.         return hr;
  681.     DXUTCache_Texture NewEntry;
  682.     NewEntry.Location = DXUTCACHE_LOCATION_FILE;
  683.     StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcFile );
  684.     NewEntry.Width = Width;
  685.     NewEntry.Height = Height;
  686.     NewEntry.Depth = Depth;
  687.     NewEntry.MipLevels = MipLevels;
  688.     NewEntry.Usage = Usage;
  689.     NewEntry.Format = Format;
  690.     NewEntry.Pool = Pool;
  691.     NewEntry.Type = D3DRTYPE_VOLUMETEXTURE;
  692.     (*ppTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
  693.     m_TextureCache.Add( NewEntry );
  694.     return S_OK;
  695. }
  696. //--------------------------------------------------------------------------------------
  697. HRESULT CDXUTResourceCache::CreateVolumeTextureFromResource( LPDIRECT3DDEVICE9 pDevice, HMODULE hSrcModule, LPCTSTR pSrcResource, LPDIRECT3DVOLUMETEXTURE9 *ppVolumeTexture )
  698. {
  699.     return CreateVolumeTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, D3DX_DEFAULT, D3DX_DEFAULT,
  700.                                               D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
  701.                                               D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, ppVolumeTexture );
  702. }
  703. //--------------------------------------------------------------------------------------
  704. HRESULT CDXUTResourceCache::CreateVolumeTextureFromResourceEx( LPDIRECT3DDEVICE9 pDevice, HMODULE hSrcModule, LPCTSTR pSrcResource, UINT Width, UINT Height, UINT Depth, UINT MipLevels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, DWORD Filter, DWORD MipFilter, D3DCOLOR ColorKey, D3DXIMAGE_INFO *pSrcInfo, PALETTEENTRY *pPalette, LPDIRECT3DVOLUMETEXTURE9 *ppVolumeTexture )
  705. {
  706.     // Search the cache for a matching entry.
  707.     for( int i = 0; i < m_TextureCache.GetSize(); ++i )
  708.     {
  709.         DXUTCache_Texture &Entry = m_TextureCache[i];
  710.         if( Entry.Location == DXUTCACHE_LOCATION_RESOURCE &&
  711.             Entry.hSrcModule == hSrcModule &&
  712.             !lstrcmpW( Entry.wszSource, pSrcResource ) &&
  713.             Entry.Width == Width &&
  714.             Entry.Height == Height &&
  715.             Entry.Depth == Depth &&
  716.             Entry.MipLevels == MipLevels &&
  717.             Entry.Usage == Usage &&
  718.             Entry.Format == Format &&
  719.             Entry.Pool == Pool &&
  720.             Entry.Type == D3DRTYPE_VOLUMETEXTURE )
  721.         {
  722.             // A match is found. Obtain the IDirect3DVolumeTexture9 interface and return that.
  723.             return Entry.pTexture->QueryInterface( IID_IDirect3DVolumeTexture9, (LPVOID*)ppVolumeTexture );
  724.         }
  725.     }
  726.     HRESULT hr;
  727.     // No matching entry.  Load the resource and create a new entry.
  728.     hr = D3DXCreateVolumeTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, Width, Height, Depth, MipLevels, Usage,
  729.                                                 Format, Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppVolumeTexture );
  730.     if( FAILED( hr ) )
  731.         return hr;
  732.     DXUTCache_Texture NewEntry;
  733.     NewEntry.Location = DXUTCACHE_LOCATION_RESOURCE;
  734.     NewEntry.hSrcModule = hSrcModule;
  735.     StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcResource );
  736.     NewEntry.Width = Width;
  737.     NewEntry.Height = Height;
  738.     NewEntry.Depth = Depth;
  739.     NewEntry.MipLevels = MipLevels;
  740.     NewEntry.Usage = Usage;
  741.     NewEntry.Format = Format;
  742.     NewEntry.Pool = Pool;
  743.     NewEntry.Type = D3DRTYPE_VOLUMETEXTURE;
  744.     (*ppVolumeTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
  745.     m_TextureCache.Add( NewEntry );
  746.     return S_OK;
  747. }
  748. //--------------------------------------------------------------------------------------
  749. HRESULT CDXUTResourceCache::CreateFont( LPDIRECT3DDEVICE9 pDevice, UINT Height, UINT Width, UINT Weight, UINT MipLevels, BOOL Italic, DWORD CharSet, DWORD OutputPrecision, DWORD Quality, DWORD PitchAndFamily, LPCTSTR pFacename, LPD3DXFONT *ppFont )
  750. {
  751.     D3DXFONT_DESCW Desc;
  752.     
  753.     Desc.Height = Height;
  754.     Desc.Width = Width;
  755.     Desc.Weight = Weight;
  756.     Desc.MipLevels = MipLevels;
  757.     Desc.Italic = Italic;
  758.     Desc.CharSet = (BYTE)CharSet;
  759.     Desc.OutputPrecision = (BYTE)OutputPrecision;
  760.     Desc.Quality = (BYTE)Quality;
  761.     Desc.PitchAndFamily = (BYTE)PitchAndFamily;
  762.     StringCchCopy( Desc.FaceName, LF_FACESIZE, pFacename );
  763.     return CreateFontIndirect( pDevice, &Desc, ppFont );
  764. }
  765. //--------------------------------------------------------------------------------------
  766. HRESULT CDXUTResourceCache::CreateFontIndirect( LPDIRECT3DDEVICE9 pDevice, CONST D3DXFONT_DESC *pDesc, LPD3DXFONT *ppFont )
  767. {
  768.     // Search the cache for a matching entry.
  769.     for( int i = 0; i < m_FontCache.GetSize(); ++i )
  770.     {
  771.         DXUTCache_Font &Entry = m_FontCache[i];
  772.         if( Entry.Width == pDesc->Width &&
  773.             Entry.Height == pDesc->Height &&
  774.             Entry.Weight == pDesc->Weight &&
  775.             Entry.MipLevels == pDesc->MipLevels &&
  776.             Entry.Italic == pDesc->Italic &&
  777.             Entry.CharSet == pDesc->CharSet &&
  778.             Entry.OutputPrecision == pDesc->OutputPrecision &&
  779.             Entry.Quality == pDesc->Quality &&
  780.             Entry.PitchAndFamily == pDesc->PitchAndFamily &&
  781.             CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  782.                            Entry.FaceName, -1,
  783.                            pDesc->FaceName, -1 ) == CSTR_EQUAL )
  784.         {
  785.             // A match is found.  Increment the reference and return the ID3DXFont object.
  786.             Entry.pFont->AddRef();
  787.             *ppFont = Entry.pFont;
  788.             return S_OK;
  789.         }
  790.     }
  791.     HRESULT hr;
  792.     // No matching entry.  Load the resource and create a new entry.
  793.     hr = D3DXCreateFontIndirect( pDevice, pDesc, ppFont );
  794.     if( FAILED( hr ) )
  795.         return hr;
  796.     DXUTCache_Font NewEntry;
  797.     (D3DXFONT_DESC &)NewEntry = *pDesc;
  798.     NewEntry.pFont = *ppFont;
  799.     NewEntry.pFont->AddRef();
  800.     m_FontCache.Add( NewEntry );
  801.     return S_OK;
  802. }
  803. //--------------------------------------------------------------------------------------
  804. HRESULT CDXUTResourceCache::CreateEffectFromFile( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, const D3DXMACRO *pDefines, LPD3DXINCLUDE pInclude, DWORD Flags, LPD3DXEFFECTPOOL pPool, LPD3DXEFFECT *ppEffect, LPD3DXBUFFER *ppCompilationErrors )
  805. {
  806.     // Search the cache for a matching entry.
  807.     for( int i = 0; i < m_EffectCache.GetSize(); ++i )
  808.     {
  809.         DXUTCache_Effect &Entry = m_EffectCache[i];
  810.         if( Entry.Location == DXUTCACHE_LOCATION_FILE &&
  811.             !lstrcmpW( Entry.wszSource, pSrcFile ) &&
  812.             Entry.dwFlags == Flags )
  813.         {
  814.             // A match is found.  Increment the ref coutn and return the ID3DXEffect object.
  815.             *ppEffect = Entry.pEffect;
  816.             (*ppEffect)->AddRef();
  817.             return S_OK;
  818.         }
  819.     }
  820.     HRESULT hr;
  821.     // No matching entry.  Load the resource and create a new entry.
  822.     hr = D3DXCreateEffectFromFile( pDevice, pSrcFile, pDefines, pInclude, Flags, pPool, ppEffect, ppCompilationErrors );
  823.     if( FAILED( hr ) )
  824.         return hr;
  825.     DXUTCache_Effect NewEntry;
  826.     NewEntry.Location = DXUTCACHE_LOCATION_FILE;
  827.     StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcFile );
  828.     NewEntry.dwFlags = Flags;
  829.     NewEntry.pEffect = *ppEffect;
  830.     NewEntry.pEffect->AddRef();
  831.     m_EffectCache.Add( NewEntry );
  832.     return S_OK;
  833. }
  834. //--------------------------------------------------------------------------------------
  835. HRESULT CDXUTResourceCache::CreateEffectFromResource( LPDIRECT3DDEVICE9 pDevice, HMODULE hSrcModule, LPCTSTR pSrcResource, const D3DXMACRO *pDefines, LPD3DXINCLUDE pInclude, DWORD Flags, LPD3DXEFFECTPOOL pPool, LPD3DXEFFECT *ppEffect, LPD3DXBUFFER *ppCompilationErrors )
  836. {
  837.     // Search the cache for a matching entry.
  838.     for( int i = 0; i < m_EffectCache.GetSize(); ++i )
  839.     {
  840.         DXUTCache_Effect &Entry = m_EffectCache[i];
  841.         if( Entry.Location == DXUTCACHE_LOCATION_RESOURCE &&
  842.             Entry.hSrcModule == hSrcModule &&
  843.             !lstrcmpW( Entry.wszSource, pSrcResource ) &&
  844.             Entry.dwFlags == Flags )
  845.         {
  846.             // A match is found.  Increment the ref coutn and return the ID3DXEffect object.
  847.             *ppEffect = Entry.pEffect;
  848.             (*ppEffect)->AddRef();
  849.             return S_OK;
  850.         }
  851.     }
  852.     HRESULT hr;
  853.     // No matching entry.  Load the resource and create a new entry.
  854.     hr = D3DXCreateEffectFromResource( pDevice, hSrcModule, pSrcResource, pDefines, pInclude, Flags,
  855.                                        pPool, ppEffect, ppCompilationErrors );
  856.     if( FAILED( hr ) )
  857.         return hr;
  858.     DXUTCache_Effect NewEntry;
  859.     NewEntry.Location = DXUTCACHE_LOCATION_RESOURCE;
  860.     NewEntry.hSrcModule = hSrcModule;
  861.     StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcResource );
  862.     NewEntry.dwFlags = Flags;
  863.     NewEntry.pEffect = *ppEffect;
  864.     NewEntry.pEffect->AddRef();
  865.     m_EffectCache.Add( NewEntry );
  866.     return S_OK;
  867. }
  868. //--------------------------------------------------------------------------------------
  869. // Device event callbacks
  870. //--------------------------------------------------------------------------------------
  871. //--------------------------------------------------------------------------------------
  872. HRESULT CDXUTResourceCache::OnCreateDevice( IDirect3DDevice9 *pd3dDevice )
  873. {
  874.     return S_OK;
  875. }
  876. //--------------------------------------------------------------------------------------
  877. HRESULT CDXUTResourceCache::OnResetDevice( IDirect3DDevice9 *pd3dDevice )
  878. {
  879.     // Call OnResetDevice on all effect and font objects
  880.     for( int i = 0; i < m_EffectCache.GetSize(); ++i )
  881.         m_EffectCache[i].pEffect->OnResetDevice();
  882.     for( int i = 0; i < m_FontCache.GetSize(); ++i )
  883.         m_FontCache[i].pFont->OnResetDevice();
  884.     return S_OK;
  885. }
  886. //--------------------------------------------------------------------------------------
  887. HRESULT CDXUTResourceCache::OnLostDevice()
  888. {
  889.     // Call OnLostDevice on all effect and font objects
  890.     for( int i = 0; i < m_EffectCache.GetSize(); ++i )
  891.         m_EffectCache[i].pEffect->OnLostDevice();
  892.     for( int i = 0; i < m_FontCache.GetSize(); ++i )
  893.         m_FontCache[i].pFont->OnLostDevice();
  894.     // Release all the default pool textures
  895.     for( int i = m_TextureCache.GetSize() - 1; i >= 0; --i )
  896.         if( m_TextureCache[i].Pool == D3DPOOL_DEFAULT )
  897.         {
  898.             SAFE_RELEASE( m_TextureCache[i].pTexture );
  899.             m_TextureCache.Remove( i );  // Remove the entry
  900.         }
  901.     return S_OK;
  902. }
  903. //--------------------------------------------------------------------------------------
  904. HRESULT CDXUTResourceCache::OnDestroyDevice()
  905. {
  906.     // Release all resources
  907.     for( int i = m_EffectCache.GetSize() - 1; i >= 0; --i )
  908.     {
  909.         SAFE_RELEASE( m_EffectCache[i].pEffect );
  910.         m_EffectCache.Remove( i );
  911.     }
  912.     for( int i = m_FontCache.GetSize() - 1; i >= 0; --i )
  913.     {
  914.         SAFE_RELEASE( m_FontCache[i].pFont );
  915.         m_FontCache.Remove( i );
  916.     }
  917.     for( int i = m_TextureCache.GetSize() - 1; i >= 0; --i )
  918.     {
  919.         SAFE_RELEASE( m_TextureCache[i].pTexture );
  920.         m_TextureCache.Remove( i );
  921.     }
  922.     return S_OK;
  923. }
  924. //--------------------------------------------------------------------------------------
  925. CD3DArcBall::CD3DArcBall()
  926. {
  927.     Reset();
  928.     m_vDownPt = D3DXVECTOR3(0,0,0);
  929.     m_vCurrentPt = D3DXVECTOR3(0,0,0);
  930.     m_Offset.x = m_Offset.y = 0;
  931.     RECT rc;
  932.     GetClientRect( GetForegroundWindow(), &rc );
  933.     SetWindow( rc.right, rc.bottom );
  934. }
  935. //--------------------------------------------------------------------------------------
  936. void CD3DArcBall::Reset()
  937. {
  938.     D3DXQuaternionIdentity( &m_qDown );
  939.     D3DXQuaternionIdentity( &m_qNow );
  940.     D3DXMatrixIdentity( &m_mRotation );
  941.     D3DXMatrixIdentity( &m_mTranslation );
  942.     D3DXMatrixIdentity( &m_mTranslationDelta );
  943.     m_bDrag = FALSE;
  944.     m_fRadiusTranslation = 1.0f;
  945.     m_fRadius = 1.0f;
  946. }
  947. //--------------------------------------------------------------------------------------
  948. D3DXVECTOR3 CD3DArcBall::ScreenToVector( float fScreenPtX, float fScreenPtY )
  949. {
  950.     // Scale to screen
  951.     FLOAT x   = -(fScreenPtX - m_Offset.x - m_nWidth/2)  / (m_fRadius*m_nWidth/2);
  952.     FLOAT y   =  (fScreenPtY - m_Offset.y - m_nHeight/2) / (m_fRadius*m_nHeight/2);
  953.     FLOAT z   = 0.0f;
  954.     FLOAT mag = x*x + y*y;
  955.     if( mag > 1.0f )
  956.     {
  957.         FLOAT scale = 1.0f/sqrtf(mag);
  958.         x *= scale;
  959.         y *= scale;
  960.     }
  961.     else
  962.         z = sqrtf( 1.0f - mag );
  963.     // Return vector
  964.     return D3DXVECTOR3( x, y, z );
  965. }
  966. //--------------------------------------------------------------------------------------
  967. D3DXQUATERNION CD3DArcBall::QuatFromBallPoints(const D3DXVECTOR3 &vFrom, const D3DXVECTOR3 &vTo)
  968. {
  969.     D3DXVECTOR3 vPart;
  970.     float fDot = D3DXVec3Dot(&vFrom, &vTo);
  971.     D3DXVec3Cross(&vPart, &vFrom, &vTo);
  972.     return D3DXQUATERNION(vPart.x, vPart.y, vPart.z, fDot);
  973. }
  974. //--------------------------------------------------------------------------------------
  975. void CD3DArcBall::OnBegin( int nX, int nY )
  976. {
  977.     // Only enter the drag state if the click falls
  978.     // inside the click rectangle.
  979.     if( nX >= m_Offset.x &&
  980.         nX < m_Offset.x + m_nWidth &&
  981.         nY >= m_Offset.y &&
  982.         nY < m_Offset.y + m_nHeight )
  983.     {
  984.         m_bDrag = true;
  985.         m_qDown = m_qNow;
  986.         m_vDownPt = ScreenToVector( (float)nX, (float)nY );
  987.     }
  988. }
  989. //--------------------------------------------------------------------------------------
  990. void CD3DArcBall::OnMove( int nX, int nY )
  991. {
  992.     if (m_bDrag) 
  993.     { 
  994.         m_vCurrentPt = ScreenToVector( (float)nX, (float)nY );
  995.         m_qNow = m_qDown * QuatFromBallPoints( m_vDownPt, m_vCurrentPt );
  996.     }
  997. }
  998. //--------------------------------------------------------------------------------------
  999. void CD3DArcBall::OnEnd()
  1000. {
  1001.     m_bDrag = false;
  1002. }
  1003. //--------------------------------------------------------------------------------------
  1004. // Desc:
  1005. //--------------------------------------------------------------------------------------
  1006. LRESULT CD3DArcBall::HandleMessages( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  1007. {
  1008.     // Current mouse position
  1009.     int iMouseX = (short)LOWORD(lParam);
  1010.     int iMouseY = (short)HIWORD(lParam);
  1011.     switch( uMsg )
  1012.     {
  1013.         case WM_LBUTTONDOWN:
  1014.         case WM_LBUTTONDBLCLK:
  1015.             SetCapture( hWnd );
  1016.             OnBegin( iMouseX, iMouseY );
  1017.             return TRUE;
  1018.         case WM_LBUTTONUP:
  1019.             ReleaseCapture();
  1020.             OnEnd();
  1021.             return TRUE;
  1022.         case WM_CAPTURECHANGED:
  1023.             if( (HWND)lParam != hWnd )
  1024.             {
  1025.                 ReleaseCapture();
  1026.                 OnEnd();
  1027.             }
  1028.             return TRUE;
  1029.         case WM_RBUTTONDOWN:
  1030.         case WM_RBUTTONDBLCLK:
  1031.         case WM_MBUTTONDOWN:
  1032.         case WM_MBUTTONDBLCLK:
  1033.             SetCapture( hWnd );
  1034.             // Store off the position of the cursor when the button is pressed
  1035.             m_ptLastMouse.x = iMouseX;
  1036.             m_ptLastMouse.y = iMouseY;
  1037.             return TRUE;
  1038.         case WM_RBUTTONUP:
  1039.         case WM_MBUTTONUP:
  1040.             ReleaseCapture();
  1041.             return TRUE;
  1042.         case WM_MOUSEMOVE:
  1043.             if( MK_LBUTTON&wParam )
  1044.             {
  1045.                 OnMove( iMouseX, iMouseY );
  1046.             }
  1047.             else if( (MK_RBUTTON&wParam) || (MK_MBUTTON&wParam) )
  1048.             {
  1049.                 // Normalize based on size of window and bounding sphere radius
  1050.                 FLOAT fDeltaX = ( m_ptLastMouse.x-iMouseX ) * m_fRadiusTranslation / m_nWidth;
  1051.                 FLOAT fDeltaY = ( m_ptLastMouse.y-iMouseY ) * m_fRadiusTranslation / m_nHeight;
  1052.                 if( wParam & MK_RBUTTON )
  1053.                 {
  1054.                     D3DXMatrixTranslation( &m_mTranslationDelta, -2*fDeltaX, 2*fDeltaY, 0.0f );
  1055.                     D3DXMatrixMultiply( &m_mTranslation, &m_mTranslation, &m_mTranslationDelta );
  1056.                 }
  1057.                 else  // wParam & MK_MBUTTON
  1058.                 {
  1059.                     D3DXMatrixTranslation( &m_mTranslationDelta, 0.0f, 0.0f, 5*fDeltaY );
  1060.                     D3DXMatrixMultiply( &m_mTranslation, &m_mTranslation, &m_mTranslationDelta );
  1061.                 }
  1062.                 // Store mouse coordinate
  1063.                 m_ptLastMouse.x = iMouseX;
  1064.                 m_ptLastMouse.y = iMouseY;
  1065.             }
  1066.             return TRUE;
  1067.     }
  1068.     return FALSE;
  1069. }
  1070. //--------------------------------------------------------------------------------------
  1071. // Constructor
  1072. //--------------------------------------------------------------------------------------
  1073. CBaseCamera::CBaseCamera()
  1074. {
  1075.     m_cKeysDown = 0;
  1076.     ZeroMemory( m_aKeys, sizeof(BYTE)*CAM_MAX_KEYS );
  1077.     ZeroMemory( m_GamePad, sizeof(DXUT_GAMEPAD)*DXUT_MAX_CONTROLLERS );
  1078.     // Set attributes for the view matrix
  1079.     D3DXVECTOR3 vEyePt    = D3DXVECTOR3(0.0f,0.0f,0.0f);
  1080.     D3DXVECTOR3 vLookatPt = D3DXVECTOR3(0.0f,0.0f,1.0f);
  1081.     // Setup the view matrix
  1082.     SetViewParams( &vEyePt, &vLookatPt );
  1083.     // Setup the projection matrix
  1084.     SetProjParams( D3DX_PI/4, 1.0f, 1.0f, 1000.0f );
  1085.     GetCursorPos( &m_ptLastMousePosition );
  1086.     m_bMouseLButtonDown = false;
  1087.     m_bMouseMButtonDown = false;
  1088.     m_bMouseRButtonDown = false;
  1089.     m_nCurrentButtonMask = 0;
  1090.     m_nMouseWheelDelta = 0;
  1091.     m_fCameraYawAngle = 0.0f;
  1092.     m_fCameraPitchAngle = 0.0f;
  1093.     SetRect( &m_rcDrag, LONG_MIN, LONG_MIN, LONG_MAX, LONG_MAX );
  1094.     m_vVelocity     = D3DXVECTOR3(0,0,0);
  1095.     m_bMovementDrag = false;
  1096.     m_vVelocityDrag = D3DXVECTOR3(0,0,0);
  1097.     m_fDragTimer    = 0.0f;
  1098.     m_fTotalDragTimeToZero = 0.25;
  1099.     m_vRotVelocity = D3DXVECTOR2(0,0);
  1100.     m_fRotationScaler = 0.01f;           
  1101.     m_fMoveScaler = 5.0f;           
  1102.     m_bInvertPitch = false;
  1103.     m_bEnableYAxisMovement = true;
  1104.     m_bEnablePositionMovement = true;
  1105.     m_vMouseDelta   = D3DXVECTOR2(0,0);
  1106.     m_fFramesToSmoothMouseData = 2.0f;
  1107.     m_bClipToBoundary = false;
  1108.     m_vMinBoundary = D3DXVECTOR3(-1,-1,-1);
  1109.     m_vMaxBoundary = D3DXVECTOR3(1,1,1);
  1110. }
  1111. //--------------------------------------------------------------------------------------
  1112. // Client can call this to change the position and direction of camera
  1113. //--------------------------------------------------------------------------------------
  1114. VOID CBaseCamera::SetViewParams( D3DXVECTOR3* pvEyePt, D3DXVECTOR3* pvLookatPt )
  1115. {
  1116.     if( NULL == pvEyePt || NULL == pvLookatPt )
  1117.         return;
  1118.     m_vDefaultEye = m_vEye = *pvEyePt;
  1119.     m_vDefaultLookAt = m_vLookAt = *pvLookatPt;
  1120.     // Calc the view matrix
  1121.     D3DXVECTOR3 vUp(0,1,0);
  1122.     D3DXMatrixLookAtLH( &m_mView, pvEyePt, pvLookatPt, &vUp );
  1123.     D3DXMATRIX mInvView;
  1124.     D3DXMatrixInverse( &mInvView, NULL, &m_mView );
  1125.     // The axis basis vectors and camera position are stored inside the 
  1126.     // position matrix in the 4 rows of the camera's world matrix.
  1127.     // To figure out the yaw/pitch of the camera, we just need the Z basis vector
  1128.     D3DXVECTOR3* pZBasis = (D3DXVECTOR3*) &mInvView._31;
  1129.     m_fCameraYawAngle   = atan2f( pZBasis->x, pZBasis->z );
  1130.     float fLen = sqrtf(pZBasis->z*pZBasis->z + pZBasis->x*pZBasis->x);
  1131.     m_fCameraPitchAngle = -atan2f( pZBasis->y, fLen );
  1132. }
  1133. VOID CBaseCamera::SetViewParams( D3DXVECTOR3* pvEyePt, D3DXVECTOR3* pvLookatPt, D3DXVECTOR3* pvUpVec )
  1134. {
  1135. if( NULL == pvEyePt || NULL == pvLookatPt )
  1136.         return;
  1137. if( D3DXVec3Length( pvUpVec ) == 0.0f )
  1138. return;
  1139.     m_vDefaultEye = m_vEye = *pvEyePt;
  1140.     m_vDefaultLookAt = m_vLookAt = *pvLookatPt;
  1141.     // Calc the view matrix
  1142.     D3DXMatrixLookAtLH( &m_mView, pvEyePt, pvLookatPt, pvUpVec );
  1143.     D3DXMATRIX mInvView;
  1144.     D3DXMatrixInverse( &mInvView, NULL, &m_mView );
  1145.     // The axis basis vectors and camera position are stored inside the 
  1146.     // position matrix in the 4 rows of the camera's world matrix.
  1147.     // To figure out the yaw/pitch of the camera, we just need the Z basis vector
  1148.     D3DXVECTOR3* pZBasis = (D3DXVECTOR3*) &mInvView._31;
  1149.     m_fCameraYawAngle   = atan2f( pZBasis->x, pZBasis->z );
  1150.     float fLen = sqrtf(pZBasis->z*pZBasis->z + pZBasis->x*pZBasis->x);
  1151.     m_fCameraPitchAngle = -atan2f( pZBasis->y, fLen );
  1152. }
  1153. //--------------------------------------------------------------------------------------
  1154. // Calculates the projection matrix based on input params
  1155. //--------------------------------------------------------------------------------------
  1156. VOID CBaseCamera::SetProjParams( FLOAT fFOV, FLOAT fAspect, FLOAT fNearPlane,
  1157.                                    FLOAT fFarPlane )
  1158. {
  1159.     // Set attributes for the projection matrix
  1160.     m_fFOV        = fFOV;
  1161.     m_fAspect     = fAspect;
  1162.     m_fNearPlane  = fNearPlane;
  1163.     m_fFarPlane   = fFarPlane;
  1164.     D3DXMatrixPerspectiveFovLH( &m_mProj, fFOV, fAspect, fNearPlane, fFarPlane );
  1165. }
  1166. //--------------------------------------------------------------------------------------
  1167. // Call this from your message proc so this class can handle window messages
  1168. //--------------------------------------------------------------------------------------
  1169. LRESULT CBaseCamera::HandleMessages( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  1170. {
  1171.     UNREFERENCED_PARAMETER( hWnd );
  1172.     UNREFERENCED_PARAMETER( lParam );
  1173.     switch( uMsg )
  1174.     {
  1175.         case WM_KEYDOWN:
  1176.         {
  1177.             // Map this key to a D3DUtil_CameraKeys enum and update the
  1178.             // state of m_aKeys[] by adding the KEY_WAS_DOWN_MASK|KEY_IS_DOWN_MASK mask
  1179.             // only if the key is not down
  1180.             D3DUtil_CameraKeys mappedKey = MapKey( (UINT)wParam );
  1181.             if( mappedKey != CAM_UNKNOWN )
  1182.             {
  1183.                 if( FALSE == IsKeyDown(m_aKeys[mappedKey]) )
  1184.                 {
  1185.                     m_aKeys[ mappedKey ] = KEY_WAS_DOWN_MASK | KEY_IS_DOWN_MASK;
  1186.                     ++m_cKeysDown;
  1187.                 }
  1188.             }
  1189.             break;
  1190.         }
  1191.         case WM_KEYUP:
  1192.         {
  1193.             // Map this key to a D3DUtil_CameraKeys enum and update the
  1194.             // state of m_aKeys[] by removing the KEY_IS_DOWN_MASK mask.
  1195.             D3DUtil_CameraKeys mappedKey = MapKey( (UINT)wParam );
  1196.             if( mappedKey != CAM_UNKNOWN && (DWORD)mappedKey < 8 )
  1197.             {
  1198.                 m_aKeys[ mappedKey ] &= ~KEY_IS_DOWN_MASK;
  1199.                 --m_cKeysDown;
  1200.             }
  1201.             break;
  1202.         }
  1203.         case WM_RBUTTONDOWN:
  1204.         case WM_MBUTTONDOWN:
  1205.         case WM_LBUTTONDOWN:
  1206.         case WM_RBUTTONDBLCLK:
  1207.         case WM_MBUTTONDBLCLK:
  1208.         case WM_LBUTTONDBLCLK:
  1209.         {
  1210.             // Compute the drag rectangle in screen coord.
  1211.             POINT ptCursor = { (short)LOWORD(lParam), (short)HIWORD(lParam) };
  1212.             // Update member var state
  1213.             if( ( uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK ) && PtInRect( &m_rcDrag, ptCursor ) )
  1214.                 { m_bMouseLButtonDown = true; m_nCurrentButtonMask |= MOUSE_LEFT_BUTTON; }
  1215.             if( ( uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONDBLCLK ) && PtInRect( &m_rcDrag, ptCursor ) )
  1216.                 { m_bMouseMButtonDown = true; m_nCurrentButtonMask |= MOUSE_MIDDLE_BUTTON; }
  1217.             if( ( uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONDBLCLK ) && PtInRect( &m_rcDrag, ptCursor ) )
  1218.                 { m_bMouseRButtonDown = true; m_nCurrentButtonMask |= MOUSE_RIGHT_BUTTON; }
  1219.             // Capture the mouse, so if the mouse button is 
  1220.             // released outside the window, we'll get the WM_LBUTTONUP message
  1221.             SetCapture(hWnd);
  1222.             GetCursorPos( &m_ptLastMousePosition );
  1223.             return TRUE;
  1224.         }
  1225.         case WM_RBUTTONUP: 
  1226.         case WM_MBUTTONUP: 
  1227.         case WM_LBUTTONUP:   
  1228.         {
  1229.             // Update member var state
  1230.             if( uMsg == WM_LBUTTONUP ) { m_bMouseLButtonDown = false; m_nCurrentButtonMask &= ~MOUSE_LEFT_BUTTON; }
  1231.             if( uMsg == WM_MBUTTONUP ) { m_bMouseMButtonDown = false; m_nCurrentButtonMask &= ~MOUSE_MIDDLE_BUTTON; }
  1232.             if( uMsg == WM_RBUTTONUP ) { m_bMouseRButtonDown = false; m_nCurrentButtonMask &= ~MOUSE_RIGHT_BUTTON; }
  1233.             // Release the capture if no mouse buttons down
  1234.             if( !m_bMouseLButtonDown  && 
  1235.                 !m_bMouseRButtonDown &&
  1236.                 !m_bMouseMButtonDown )
  1237.             {
  1238.                 ReleaseCapture();
  1239.             }
  1240.             break;
  1241.         }
  1242.         case WM_CAPTURECHANGED:
  1243.         {
  1244.             if( (HWND)lParam != hWnd )
  1245.             {
  1246.                 if( (m_nCurrentButtonMask & MOUSE_LEFT_BUTTON) ||
  1247.                     (m_nCurrentButtonMask & MOUSE_MIDDLE_BUTTON) ||
  1248.                     (m_nCurrentButtonMask & MOUSE_RIGHT_BUTTON) )
  1249.                 {
  1250.                     m_bMouseLButtonDown = false;
  1251.                     m_bMouseMButtonDown = false;
  1252.                     m_bMouseRButtonDown = false;
  1253.                     m_nCurrentButtonMask &= ~MOUSE_LEFT_BUTTON;
  1254.                     m_nCurrentButtonMask &= ~MOUSE_MIDDLE_BUTTON;
  1255.                     m_nCurrentButtonMask &= ~MOUSE_RIGHT_BUTTON;
  1256.                     ReleaseCapture();
  1257.                 }
  1258.             }
  1259.             break;
  1260.         }
  1261.         case WM_MOUSEWHEEL: 
  1262.             // Update member var state
  1263.             m_nMouseWheelDelta = (short)HIWORD(wParam) / 120;
  1264.             break;
  1265.     }
  1266.     return FALSE;
  1267. }
  1268. //--------------------------------------------------------------------------------------
  1269. // Figure out the velocity based on keyboard input & drag if any
  1270. //--------------------------------------------------------------------------------------
  1271. void CBaseCamera::GetInput( bool bGetKeyboardInput, bool bGetMouseInput, bool bGetGamepadInput, bool bResetCursorAfterMove )
  1272. {
  1273.     m_vKeyboardDirection = D3DXVECTOR3(0,0,0);
  1274.     if( bGetKeyboardInput )
  1275.     {
  1276.         // Update acceleration vector based on keyboard state
  1277.         if( IsKeyDown(m_aKeys[CAM_MOVE_FORWARD]) )
  1278.             m_vKeyboardDirection.z += 1.0f;
  1279.         if( IsKeyDown(m_aKeys[CAM_MOVE_BACKWARD]) )
  1280.             m_vKeyboardDirection.z -= 1.0f;
  1281.         if( m_bEnableYAxisMovement )
  1282.         {
  1283.             if( IsKeyDown(m_aKeys[CAM_MOVE_UP]) )
  1284.                 m_vKeyboardDirection.y += 1.0f;
  1285.             if( IsKeyDown(m_aKeys[CAM_MOVE_DOWN]) )
  1286.                 m_vKeyboardDirection.y -= 1.0f;
  1287.         }
  1288.         if( IsKeyDown(m_aKeys[CAM_STRAFE_RIGHT]) )
  1289.             m_vKeyboardDirection.x += 1.0f;
  1290.         if( IsKeyDown(m_aKeys[CAM_STRAFE_LEFT]) )
  1291.             m_vKeyboardDirection.x -= 1.0f;
  1292.     }
  1293.     if( bGetMouseInput )
  1294.     {
  1295.         // Get current position of mouse
  1296.         POINT ptCurMouseDelta;
  1297.         POINT ptCurMousePos;
  1298.         
  1299.         if( GetCursorPos( &ptCurMousePos ) )
  1300.         {
  1301.             // Calc how far it's moved since last frame
  1302.             ptCurMouseDelta.x = ptCurMousePos.x - m_ptLastMousePosition.x;
  1303.             ptCurMouseDelta.y = ptCurMousePos.y - m_ptLastMousePosition.y;
  1304.             
  1305.             // Record current position for next time
  1306.             m_ptLastMousePosition = ptCurMousePos;
  1307.         }
  1308.         else
  1309.         {
  1310.             // If GetCursorPos() returns false, just set delta to zero
  1311.             ptCurMouseDelta.x = 0;
  1312.             ptCurMouseDelta.y = 0;
  1313.         }
  1314.         if( bResetCursorAfterMove && DXUTIsActive() )
  1315.         {
  1316.             // Set position of camera to center of desktop, 
  1317.             // so it always has room to move.  This is very useful
  1318.             // if the cursor is hidden.  If this isn't done and cursor is hidden, 
  1319.             // then invisible cursor will hit the edge of the screen 
  1320.             // and the user can't tell what happened
  1321.             POINT ptCenter;
  1322.             // Get the center of the current monitor
  1323.             MONITORINFO mi;
  1324.             mi.cbSize = sizeof(MONITORINFO);
  1325.             DXUTGetMonitorInfo( DXUTMonitorFromWindow(DXUTGetHWND(),MONITOR_DEFAULTTONEAREST), &mi );
  1326.             ptCenter.x = (mi.rcMonitor.left + mi.rcMonitor.right) / 2;
  1327.             ptCenter.y = (mi.rcMonitor.top + mi.rcMonitor.bottom) / 2;   
  1328.             SetCursorPos( ptCenter.x, ptCenter.y );
  1329.             m_ptLastMousePosition = ptCenter;
  1330.         }
  1331.         // Smooth the relative mouse data over a few frames so it isn't 
  1332.         // jerky when moving slowly at low frame rates.
  1333.         float fPercentOfNew =  1.0f / m_fFramesToSmoothMouseData;
  1334.         float fPercentOfOld =  1.0f - fPercentOfNew;
  1335.         m_vMouseDelta.x = m_vMouseDelta.x*fPercentOfOld + ptCurMouseDelta.x*fPercentOfNew;
  1336.         m_vMouseDelta.y = m_vMouseDelta.y*fPercentOfOld + ptCurMouseDelta.y*fPercentOfNew;
  1337.     }
  1338.     if( bGetGamepadInput )
  1339.     {
  1340.         m_vGamePadLeftThumb = D3DXVECTOR3(0,0,0);
  1341.         m_vGamePadRightThumb = D3DXVECTOR3(0,0,0);
  1342.         // Get controller state
  1343.         for( DWORD iUserIndex=0; iUserIndex<DXUT_MAX_CONTROLLERS; iUserIndex++ )
  1344.         {
  1345.             DXUTGetGamepadState( iUserIndex, &m_GamePad[iUserIndex], true, true );
  1346.             // Mark time if the controller is in a non-zero state
  1347.             if( m_GamePad[iUserIndex].wButtons || 
  1348.                 m_GamePad[iUserIndex].sThumbLX || m_GamePad[iUserIndex].sThumbLX || 
  1349.                 m_GamePad[iUserIndex].sThumbRX || m_GamePad[iUserIndex].sThumbRY || 
  1350.                 m_GamePad[iUserIndex].bLeftTrigger || m_GamePad[iUserIndex].bRightTrigger )
  1351.             {
  1352.                 m_GamePadLastActive[iUserIndex] = DXUTGetTime();
  1353.             }
  1354.         }
  1355.         // Find out which controller was non-zero last
  1356.         int iMostRecentlyActive = -1;
  1357.         double fMostRecentlyActiveTime = 0.0f;
  1358.         for( DWORD iUserIndex=0; iUserIndex<DXUT_MAX_CONTROLLERS; iUserIndex++ )
  1359.         {
  1360.             if( m_GamePadLastActive[iUserIndex] > fMostRecentlyActiveTime )
  1361.             {
  1362.                 fMostRecentlyActiveTime = m_GamePadLastActive[iUserIndex];
  1363.                 iMostRecentlyActive = iUserIndex;
  1364.             }
  1365.         }
  1366.         // Use the most recent non-zero controller if its connected
  1367.         if( iMostRecentlyActive >= 0 && m_GamePad[iMostRecentlyActive].bConnected )
  1368.         {
  1369.             m_vGamePadLeftThumb.x = m_GamePad[iMostRecentlyActive].fThumbLX;
  1370.             m_vGamePadLeftThumb.y = 0.0f;
  1371.             m_vGamePadLeftThumb.z = m_GamePad[iMostRecentlyActive].fThumbLY;
  1372.             m_vGamePadRightThumb.x = m_GamePad[iMostRecentlyActive].fThumbRX;
  1373.             m_vGamePadRightThumb.y = 0.0f;
  1374.             m_vGamePadRightThumb.z = m_GamePad[iMostRecentlyActive].fThumbRY;
  1375.         }
  1376.     }
  1377. }
  1378. //--------------------------------------------------------------------------------------
  1379. // Figure out the velocity based on keyboard input & drag if any
  1380. //--------------------------------------------------------------------------------------
  1381. void CBaseCamera::UpdateVelocity( float fElapsedTime )
  1382. {
  1383.     D3DXMATRIX mRotDelta;
  1384.     D3DXVECTOR2 vGamePadRightThumb = D3DXVECTOR2(m_vGamePadRightThumb.x, -m_vGamePadRightThumb.z);
  1385.     m_vRotVelocity = m_vMouseDelta * m_fRotationScaler + vGamePadRightThumb * 0.02f;
  1386.     D3DXVECTOR3 vAccel = m_vKeyboardDirection + m_vGamePadLeftThumb;
  1387.     // Normalize vector so if moving 2 dirs (left & forward), 
  1388.     // the camera doesn't move faster than if moving in 1 dir
  1389.     D3DXVec3Normalize( &vAccel, &vAccel );
  1390.     // Scale the acceleration vector
  1391.     vAccel *= m_fMoveScaler;
  1392.     if( m_bMovementDrag )
  1393.     {
  1394.         // Is there any acceleration this frame?
  1395.         if( D3DXVec3LengthSq( &vAccel ) > 0 )
  1396.         {
  1397.             // If so, then this means the user has pressed a movement key
  1398.             // so change the velocity immediately to acceleration 
  1399.             // upon keyboard input.  This isn't normal physics
  1400.             // but it will give a quick response to keyboard input
  1401.             m_vVelocity = vAccel;
  1402.             m_fDragTimer = m_fTotalDragTimeToZero;
  1403.             m_vVelocityDrag = vAccel / m_fDragTimer;
  1404.         }
  1405.         else 
  1406.         {
  1407.             // If no key being pressed, then slowly decrease velocity to 0
  1408.             if( m_fDragTimer > 0 )
  1409.             {
  1410.                 // Drag until timer is <= 0
  1411.                 m_vVelocity -= m_vVelocityDrag * fElapsedTime;
  1412.                 m_fDragTimer -= fElapsedTime;
  1413.             }
  1414.             else
  1415.             {
  1416.                 // Zero velocity
  1417.                 m_vVelocity = D3DXVECTOR3(0,0,0);
  1418.             }
  1419.         }
  1420.     }
  1421.     else
  1422.     {
  1423.         // No drag, so immediately change the velocity
  1424.         m_vVelocity = vAccel;
  1425.     }
  1426. }