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 //--------------------------------------------------------------------------------------
14 // Global/Static Members
15 //--------------------------------------------------------------------------------------
DXUTGetGlobalResourceCache()16 CDXUTResourceCache& DXUTGetGlobalResourceCache()
17 {
18     // Using an accessor function gives control of the construction order
19     static CDXUTResourceCache cache;
20     return cache;
21 }
DXUTGetGlobalTimer()22 CDXUTTimer* DXUTGetGlobalTimer()
23 {
24     // Using an accessor function gives control of the construction order
25     static CDXUTTimer timer;
26     return &timer;
27 }
28 
29 
30 //--------------------------------------------------------------------------------------
31 // Internal functions forward declarations
32 //--------------------------------------------------------------------------------------
33 bool DXUTFindMediaSearchTypicalDirs( WCHAR* strSearchPath, int cchSearch, LPCWSTR strLeaf, WCHAR* strExePath, WCHAR* strExeName );
34 bool DXUTFindMediaSearchParentDirs( WCHAR* strSearchPath, int cchSearch, WCHAR* strStartAt, WCHAR* strLeafName );
35 INT_PTR CALLBACK DisplaySwitchToREFWarningProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
36 
37 
38 //--------------------------------------------------------------------------------------
39 // Shared code for samples to ask user if they want to use a REF device or quit
40 //--------------------------------------------------------------------------------------
DXUTDisplaySwitchingToREFWarning()41 void DXUTDisplaySwitchingToREFWarning()
42 {
43     if( DXUTGetShowMsgBoxOnError() )
44     {
45         // Open the appropriate registry key
46         DWORD dwSkipWarning = 0;
47         HKEY hKey;
48         LONG lResult = RegOpenKeyEx( HKEY_CURRENT_USER, L"Software\\Microsoft\\DirectX 9.0 SDK", 0, KEY_READ, &hKey );
49         if( ERROR_SUCCESS == lResult )
50         {
51             DWORD dwType;
52             DWORD dwSize = sizeof(DWORD);
53             lResult = RegQueryValueEx( hKey, L"Skip Warning On REF", NULL, &dwType, (BYTE*)&dwSkipWarning, &dwSize );
54             RegCloseKey( hKey );
55         }
56 
57         if( dwSkipWarning == 0 )
58         {
59             // Compact code to create a custom dialog box without using a template in a resource file.
60             // If this dialog were in a .rc file, this would be a lot simpler but every sample calling this function would
61             // need a copy of the dialog in its own .rc file. Also MessageBox API could be used here instead, but
62             // the MessageBox API is simpler to call but it can't provide a "Don't show again" checkbox
63             typedef struct { DLGITEMTEMPLATE a; WORD b; WORD c; WORD d; WORD e; WORD f; } DXUT_DLG_ITEM;
64             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;
65 
66             DXUT_DLG_DATA dtp =
67             {
68                 {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",
69                 {{WS_CHILD|WS_VISIBLE|SS_ICON|SS_CENTERIMAGE,0,7,7,24,24,0x100},0xFFFF,0x0082,0,0,0}, // icon
70                 {{WS_CHILD|WS_VISIBLE,0,40,7,230,25,0x101},0xFFFF,0x0082,0,0,0}, // static text
71                 {{WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON,0,80,39,50,14,IDYES},0xFFFF,0x0080,0,0,0}, // Yes button
72                 {{WS_CHILD|WS_VISIBLE,0,133,39,50,14,IDNO},0xFFFF,0x0080,0,0,0}, // No button
73                 {{WS_CHILD|WS_VISIBLE|BS_CHECKBOX,0,7,59,70,16,IDIGNORE},0xFFFF,0x0080,0,0,0}, // checkbox
74             };
75 
76             int nResult = (int) DialogBoxIndirect( DXUTGetHINSTANCE(), (DLGTEMPLATE*)&dtp, DXUTGetHWND(), DisplaySwitchToREFWarningProc );
77 
78             if( (nResult & 0x80) == 0x80 ) // "Don't show again" checkbox was checked
79             {
80                 lResult = RegOpenKeyEx( HKEY_CURRENT_USER, L"Software\\Microsoft\\DirectX 9.0 SDK", 0, KEY_WRITE, &hKey );
81                 if( ERROR_SUCCESS == lResult )
82                 {
83                     dwSkipWarning = 1;
84                     RegSetValueEx( hKey, L"Skip Warning On REF", 0, REG_DWORD, (BYTE*)&dwSkipWarning, sizeof(DWORD) );
85                     RegCloseKey( hKey );
86                 }
87             }
88 
89             // User choose not to continue
90             if( (nResult & 0x0F) == IDNO )
91                 DXUTShutdown(1);
92         }
93     }
94 }
95 
96 
97 //--------------------------------------------------------------------------------------
98 // MsgProc for DXUTDisplaySwitchingToREFWarning() dialog box
99 //--------------------------------------------------------------------------------------
DisplaySwitchToREFWarningProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)100 INT_PTR CALLBACK DisplaySwitchToREFWarningProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
101 {
102     switch (message)
103     {
104         case WM_INITDIALOG:
105             // Easier to set text here than in the DLGITEMTEMPLATE
106             SetWindowText( hDlg, DXUTGetWindowTitle() );
107             SendMessage( GetDlgItem(hDlg, 0x100), STM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIcon(0, IDI_QUESTION));
108             SetDlgItemText( hDlg, 0x101, L"Switching to the Direct3D reference rasterizer, a software device\nthat implements the entire Direct3D feature set, but runs very slowly.\nDo you wish to continue?" );
109             SetDlgItemText( hDlg, IDYES, L"&Yes" );
110             SetDlgItemText( hDlg, IDNO, L"&No" );
111             SetDlgItemText( hDlg, IDIGNORE, L"&Don't show again" );
112             break;
113 
114         case WM_COMMAND:
115             switch (LOWORD(wParam))
116             {
117                 case IDIGNORE: CheckDlgButton( hDlg, IDIGNORE, (IsDlgButtonChecked( hDlg, IDIGNORE ) == BST_CHECKED) ? BST_UNCHECKED : BST_CHECKED ); EnableWindow( GetDlgItem( hDlg, IDNO ), (IsDlgButtonChecked( hDlg, IDIGNORE ) != BST_CHECKED) ); break;
118                 case IDNO: EndDialog(hDlg, (IsDlgButtonChecked( hDlg, IDIGNORE ) == BST_CHECKED) ? IDNO|0x80 : IDNO|0x00 ); return TRUE;
119                 case IDCANCEL:
120                 case IDYES: EndDialog(hDlg, (IsDlgButtonChecked( hDlg, IDIGNORE ) == BST_CHECKED) ? IDYES|0x80 : IDYES|0x00 ); return TRUE;
121             }
122             break;
123     }
124     return FALSE;
125 }
126 
127 
128 //--------------------------------------------------------------------------------------
CDXUTTimer()129 CDXUTTimer::CDXUTTimer()
130 {
131     m_bTimerStopped     = true;
132     m_llQPFTicksPerSec  = 0;
133 
134     m_llStopTime        = 0;
135     m_llLastElapsedTime = 0;
136     m_llBaseTime        = 0;
137 
138     // Use QueryPerformanceFrequency to get the frequency of the counter
139     LARGE_INTEGER qwTicksPerSec;
140     QueryPerformanceFrequency( &qwTicksPerSec );
141     m_llQPFTicksPerSec = qwTicksPerSec.QuadPart;
142 }
143 
144 
145 //--------------------------------------------------------------------------------------
Reset()146 void CDXUTTimer::Reset()
147 {
148     LARGE_INTEGER qwTime = GetAdjustedCurrentTime();
149 
150     m_llBaseTime        = qwTime.QuadPart;
151     m_llLastElapsedTime = qwTime.QuadPart;
152     m_llStopTime        = 0;
153     m_bTimerStopped     = FALSE;
154 }
155 
156 
157 //--------------------------------------------------------------------------------------
Start()158 void CDXUTTimer::Start()
159 {
160     // Get the current time
161     LARGE_INTEGER qwTime;
162     QueryPerformanceCounter( &qwTime );
163 
164     if( m_bTimerStopped )
165         m_llBaseTime += qwTime.QuadPart - m_llStopTime;
166     m_llStopTime = 0;
167     m_llLastElapsedTime = qwTime.QuadPart;
168     m_bTimerStopped = FALSE;
169 }
170 
171 
172 //--------------------------------------------------------------------------------------
Stop()173 void CDXUTTimer::Stop()
174 {
175     if( !m_bTimerStopped )
176     {
177         LARGE_INTEGER qwTime;
178         QueryPerformanceCounter( &qwTime );
179         m_llStopTime = qwTime.QuadPart;
180         m_llLastElapsedTime = qwTime.QuadPart;
181         m_bTimerStopped = TRUE;
182     }
183 }
184 
185 
186 //--------------------------------------------------------------------------------------
Advance()187 void CDXUTTimer::Advance()
188 {
189     m_llStopTime += m_llQPFTicksPerSec/10;
190 }
191 
192 
193 //--------------------------------------------------------------------------------------
GetAbsoluteTime()194 double CDXUTTimer::GetAbsoluteTime()
195 {
196     LARGE_INTEGER qwTime;
197     QueryPerformanceCounter( &qwTime );
198 
199     double fTime = qwTime.QuadPart / (double) m_llQPFTicksPerSec;
200 
201     return fTime;
202 }
203 
204 
205 //--------------------------------------------------------------------------------------
GetTime()206 double CDXUTTimer::GetTime()
207 {
208     LARGE_INTEGER qwTime = GetAdjustedCurrentTime();
209 
210     double fAppTime = (double) ( qwTime.QuadPart - m_llBaseTime ) / (double) m_llQPFTicksPerSec;
211 
212     return fAppTime;
213 }
214 
215 
216 //--------------------------------------------------------------------------------------
GetTimeValues(double * pfTime,double * pfAbsoluteTime,float * pfElapsedTime)217 void CDXUTTimer::GetTimeValues( double* pfTime, double* pfAbsoluteTime, float* pfElapsedTime )
218 {
219     assert( pfTime && pfAbsoluteTime && pfElapsedTime );
220 
221     LARGE_INTEGER qwTime = GetAdjustedCurrentTime();
222 
223     float fElapsedTime = (float) ((double) ( qwTime.QuadPart - m_llLastElapsedTime ) / (double) m_llQPFTicksPerSec);
224     m_llLastElapsedTime = qwTime.QuadPart;
225 
226     // Clamp the timer to non-negative values to ensure the timer is accurate.
227     // fElapsedTime can be outside this range if processor goes into a
228     // power save mode or we somehow get shuffled to another processor.
229     // However, the main thread should call SetThreadAffinityMask to ensure that
230     // we don't get shuffled to another processor.  Other worker threads should NOT call
231     // SetThreadAffinityMask, but use a shared copy of the timer data gathered from
232     // the main thread.
233     if( fElapsedTime < 0.0f )
234         fElapsedTime = 0.0f;
235 
236     *pfAbsoluteTime = qwTime.QuadPart / (double) m_llQPFTicksPerSec;
237     *pfTime = ( qwTime.QuadPart - m_llBaseTime ) / (double) m_llQPFTicksPerSec;
238     *pfElapsedTime = fElapsedTime;
239 }
240 
241 
242 //--------------------------------------------------------------------------------------
GetElapsedTime()243 double CDXUTTimer::GetElapsedTime()
244 {
245     LARGE_INTEGER qwTime = GetAdjustedCurrentTime();
246 
247     double fElapsedTime = (double) ( qwTime.QuadPart - m_llLastElapsedTime ) / (double) m_llQPFTicksPerSec;
248     m_llLastElapsedTime = qwTime.QuadPart;
249 
250     // See the explanation about clamping in CDXUTTimer::GetTimeValues()
251     if( fElapsedTime < 0.0f )
252         fElapsedTime = 0.0f;
253 
254     return fElapsedTime;
255 }
256 
257 
258 //--------------------------------------------------------------------------------------
259 // If stopped, returns time when stopped otherwise returns current time
260 //--------------------------------------------------------------------------------------
GetAdjustedCurrentTime()261 LARGE_INTEGER CDXUTTimer::GetAdjustedCurrentTime()
262 {
263     LARGE_INTEGER qwTime;
264     if( m_llStopTime != 0 )
265         qwTime.QuadPart = m_llStopTime;
266     else
267         QueryPerformanceCounter( &qwTime );
268     return qwTime;
269 }
270 
271 
272 //--------------------------------------------------------------------------------------
IsStopped()273 bool CDXUTTimer::IsStopped()
274 {
275     return m_bTimerStopped;
276 }
277 
278 
279 //--------------------------------------------------------------------------------------
280 // Limit the current thread to one processor (the current one). This ensures that timing code
281 // runs on only one processor, and will not suffer any ill effects from power management.
282 // See "Game Timing and Multicore Processors" for more details
283 //--------------------------------------------------------------------------------------
LimitThreadAffinityToCurrentProc()284 void CDXUTTimer::LimitThreadAffinityToCurrentProc()
285 {
286     HANDLE hCurrentProcess = GetCurrentProcess();
287 
288     // Get the processor affinity mask for this process
289     DWORD_PTR dwProcessAffinityMask = 0;
290     DWORD_PTR dwSystemAffinityMask = 0;
291 
292     if( GetProcessAffinityMask( hCurrentProcess, &dwProcessAffinityMask, &dwSystemAffinityMask ) != 0 && dwProcessAffinityMask )
293     {
294         // Find the lowest processor that our process is allows to run against
295         DWORD_PTR dwAffinityMask = ( dwProcessAffinityMask & ((~dwProcessAffinityMask) + 1 ) );
296 
297         // Set this as the processor that our thread must always run against
298         // This must be a subset of the process affinity mask
299         HANDLE hCurrentThread = GetCurrentThread();
300         if( INVALID_HANDLE_VALUE != hCurrentThread )
301         {
302             SetThreadAffinityMask( hCurrentThread, dwAffinityMask );
303             CloseHandle( hCurrentThread );
304         }
305     }
306 
307     CloseHandle( hCurrentProcess );
308 }
309 
310 
311 //--------------------------------------------------------------------------------------
312 // Returns pointer to static media search buffer
313 //--------------------------------------------------------------------------------------
DXUTMediaSearchPath()314 WCHAR* DXUTMediaSearchPath()
315 {
316     static WCHAR s_strMediaSearchPath[MAX_PATH] = {0};
317     return s_strMediaSearchPath;
318 
319 }
320 
321 //--------------------------------------------------------------------------------------
DXUTGetMediaSearchPath()322 LPCWSTR DXUTGetMediaSearchPath()
323 {
324     return DXUTMediaSearchPath();
325 }
326 
327 
328 //--------------------------------------------------------------------------------------
DXUTSetMediaSearchPath(LPCWSTR strPath)329 HRESULT DXUTSetMediaSearchPath( LPCWSTR strPath )
330 {
331     HRESULT hr;
332 
333     WCHAR* s_strSearchPath = DXUTMediaSearchPath();
334 
335     hr = StringCchCopy( s_strSearchPath, MAX_PATH, strPath );
336     if( SUCCEEDED(hr) )
337     {
338         // append slash if needed
339         size_t ch;
340         hr = StringCchLength( s_strSearchPath, MAX_PATH, &ch );
341         if( SUCCEEDED(hr) && s_strSearchPath[ch-1] != L'\\')
342         {
343             hr = StringCchCat( s_strSearchPath, MAX_PATH, L"\\" );
344         }
345     }
346 
347     return hr;
348 }
349 
350 
351 //--------------------------------------------------------------------------------------
352 // Tries to find the location of a SDK media file
353 //       cchDest is the size in WCHARs of strDestPath.  Be careful not to
354 //       pass in sizeof(strDest) on UNICODE builds.
355 //--------------------------------------------------------------------------------------
DXUTFindDXSDKMediaFileCch(WCHAR * strDestPath,int cchDest,LPCWSTR strFilename)356 HRESULT DXUTFindDXSDKMediaFileCch( WCHAR* strDestPath, int cchDest, LPCWSTR strFilename )
357 {
358     bool bFound;
359     WCHAR strSearchFor[MAX_PATH];
360 
361     if( NULL==strFilename || strFilename[0] == 0 || NULL==strDestPath || cchDest < 10 )
362         return E_INVALIDARG;
363 
364     // Get the exe name, and exe path
365     WCHAR strExePath[MAX_PATH] = {0};
366     WCHAR strExeName[MAX_PATH] = {0};
367     WCHAR* strLastSlash = NULL;
368     GetModuleFileName( NULL, strExePath, MAX_PATH );
369     strExePath[MAX_PATH-1]=0;
370     strLastSlash = wcsrchr( strExePath, TEXT('\\') );
371     if( strLastSlash )
372     {
373         StringCchCopy( strExeName, MAX_PATH, &strLastSlash[1] );
374 
375         // Chop the exe name from the exe path
376         *strLastSlash = 0;
377 
378         // Chop the .exe from the exe name
379         strLastSlash = wcsrchr( strExeName, TEXT('.') );
380         if( strLastSlash )
381             *strLastSlash = 0;
382     }
383 
384     // Typical directories:
385     //      .\
386     //      ..\
387     //      ..\..\
388     //      %EXE_DIR%\
389     //      %EXE_DIR%\..\
390     //      %EXE_DIR%\..\..\
391     //      %EXE_DIR%\..\%EXE_NAME%
392     //      %EXE_DIR%\..\..\%EXE_NAME%
393 
394     // Typical directory search
395     bFound = DXUTFindMediaSearchTypicalDirs( strDestPath, cchDest, strFilename, strExePath, strExeName );
396     if( bFound )
397         return S_OK;
398 
399     // Typical directory search again, but also look in a subdir called "\media\"
400     StringCchPrintf( strSearchFor, MAX_PATH, L"media\\%s", strFilename );
401     bFound = DXUTFindMediaSearchTypicalDirs( strDestPath, cchDest, strSearchFor, strExePath, strExeName );
402     if( bFound )
403         return S_OK;
404 
405     WCHAR strLeafName[MAX_PATH] = {0};
406 
407     // Search all parent directories starting at .\ and using strFilename as the leaf name
408     StringCchCopy( strLeafName, MAX_PATH, strFilename );
409     bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, L".", strLeafName );
410     if( bFound )
411         return S_OK;
412 
413     // Search all parent directories starting at the exe's dir and using strFilename as the leaf name
414     bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, strExePath, strLeafName );
415     if( bFound )
416         return S_OK;
417 
418     // Search all parent directories starting at .\ and using "media\strFilename" as the leaf name
419     StringCchPrintf( strLeafName, MAX_PATH, L"media\\%s", strFilename );
420     bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, L".", strLeafName );
421     if( bFound )
422         return S_OK;
423 
424     // Search all parent directories starting at the exe's dir and using "media\strFilename" as the leaf name
425     bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, strExePath, strLeafName );
426     if( bFound )
427         return S_OK;
428 
429     // On failure, return the file as the path but also return an error code
430     StringCchCopy( strDestPath, cchDest, strFilename );
431 
432     return DXUTERR_MEDIANOTFOUND;
433 }
434 
435 
436 //--------------------------------------------------------------------------------------
437 // Search a set of typical directories
438 //--------------------------------------------------------------------------------------
DXUTFindMediaSearchTypicalDirs(WCHAR * strSearchPath,int cchSearch,LPCWSTR strLeaf,WCHAR * strExePath,WCHAR * strExeName)439 bool DXUTFindMediaSearchTypicalDirs( WCHAR* strSearchPath, int cchSearch, LPCWSTR strLeaf,
440                                      WCHAR* strExePath, WCHAR* strExeName )
441 {
442     // Typical directories:
443     //      .\
444     //      ..\
445     //      ..\..\
446     //      %EXE_DIR%\
447     //      %EXE_DIR%\..\
448     //      %EXE_DIR%\..\..\
449     //      %EXE_DIR%\..\%EXE_NAME%
450     //      %EXE_DIR%\..\..\%EXE_NAME%
451     //      DXSDK media path
452 
453     // Search in .\
454     StringCchCopy( strSearchPath, cchSearch, strLeaf );
455     if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
456         return true;
457 
458     // Search in ..\
459     StringCchPrintf( strSearchPath, cchSearch, L"..\\%s", strLeaf );
460     if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
461         return true;
462 
463     // Search in ..\..\
464     StringCchPrintf( strSearchPath, cchSearch, L"..\\..\\%s", strLeaf );
465     if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
466         return true;
467 
468     // Search in ..\..\
469     StringCchPrintf( strSearchPath, cchSearch, L"..\\..\\%s", strLeaf );
470     if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
471         return true;
472 
473     // Search in the %EXE_DIR%\
474     StringCchPrintf( strSearchPath, cchSearch, L"%s\\%s", strExePath, strLeaf );
475     if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
476         return true;
477 
478     // Search in the %EXE_DIR%\..\
479     StringCchPrintf( strSearchPath, cchSearch, L"%s\\..\\%s", strExePath, strLeaf );
480     if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
481         return true;
482 
483     // Search in the %EXE_DIR%\..\..\
484     StringCchPrintf( strSearchPath, cchSearch, L"%s\\..\\..\\%s", strExePath, strLeaf );
485     if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
486         return true;
487 
488     // Search in "%EXE_DIR%\..\%EXE_NAME%\".  This matches the DirectX SDK layout
489     StringCchPrintf( strSearchPath, cchSearch, L"%s\\..\\%s\\%s", strExePath, strExeName, strLeaf );
490     if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
491         return true;
492 
493     // Search in "%EXE_DIR%\..\..\%EXE_NAME%\".  This matches the DirectX SDK layout
494     StringCchPrintf( strSearchPath, cchSearch, L"%s\\..\\..\\%s\\%s", strExePath, strExeName, strLeaf );
495     if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
496         return true;
497 
498     // Search in media search dir
499     WCHAR* s_strSearchPath = DXUTMediaSearchPath();
500     if( s_strSearchPath[0] != 0 )
501     {
502         StringCchPrintf( strSearchPath, cchSearch, L"%s%s", s_strSearchPath, strLeaf );
503         if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
504             return true;
505     }
506 
507     return false;
508 }
509 
510 
511 
512 //--------------------------------------------------------------------------------------
513 // Search parent directories starting at strStartAt, and appending strLeafName
514 // at each parent directory.  It stops at the root directory.
515 //--------------------------------------------------------------------------------------
DXUTFindMediaSearchParentDirs(WCHAR * strSearchPath,int cchSearch,WCHAR * strStartAt,WCHAR * strLeafName)516 bool DXUTFindMediaSearchParentDirs( WCHAR* strSearchPath, int cchSearch, WCHAR* strStartAt, WCHAR* strLeafName )
517 {
518     WCHAR strFullPath[MAX_PATH] = {0};
519     WCHAR strFullFileName[MAX_PATH] = {0};
520     WCHAR strSearch[MAX_PATH] = {0};
521     WCHAR* strFilePart = NULL;
522 
523     GetFullPathName( strStartAt, MAX_PATH, strFullPath, &strFilePart );
524     if( strFilePart == NULL )
525         return false;
526 
527     while( strFilePart != NULL && *strFilePart != '\0' )
528     {
529         StringCchPrintf( strFullFileName, MAX_PATH, L"%s\\%s", strFullPath, strLeafName );
530         if( GetFileAttributes( strFullFileName ) != 0xFFFFFFFF )
531         {
532             StringCchCopy( strSearchPath, cchSearch, strFullFileName );
533             return true;
534         }
535 
536         StringCchPrintf( strSearch, MAX_PATH, L"%s\\..", strFullPath );
537         GetFullPathName( strSearch, MAX_PATH, strFullPath, &strFilePart );
538     }
539 
540     return false;
541 }
542 
543 
544 //--------------------------------------------------------------------------------------
545 // CDXUTResourceCache
546 //--------------------------------------------------------------------------------------
547 
548 
~CDXUTResourceCache()549 CDXUTResourceCache::~CDXUTResourceCache()
550 {
551     OnDestroyDevice();
552 
553     m_TextureCache.RemoveAll();
554     m_EffectCache.RemoveAll();
555     m_FontCache.RemoveAll();
556 }
557 
558 
CreateTextureFromFile(LPDIRECT3DDEVICE9 pDevice,LPCTSTR pSrcFile,LPDIRECT3DTEXTURE9 * ppTexture)559 HRESULT CDXUTResourceCache::CreateTextureFromFile( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, LPDIRECT3DTEXTURE9 *ppTexture )
560 {
561     return CreateTextureFromFileEx( pDevice, pSrcFile, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
562                                     0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT,
563                                     0, NULL, NULL, ppTexture );
564 }
565 
566 
567 //--------------------------------------------------------------------------------------
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)568 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 )
569 {
570     // Search the cache for a matching entry.
571     for( int i = 0; i < m_TextureCache.GetSize(); ++i )
572     {
573         DXUTCache_Texture &Entry = m_TextureCache[i];
574         if( Entry.Location == DXUTCACHE_LOCATION_FILE &&
575             !lstrcmpW( Entry.wszSource, pSrcFile ) &&
576             Entry.Width == Width &&
577             Entry.Height == Height &&
578             Entry.MipLevels == MipLevels &&
579             Entry.Usage == Usage &&
580             Entry.Format == Format &&
581             Entry.Pool == Pool &&
582             Entry.Type == D3DRTYPE_TEXTURE )
583         {
584             // A match is found. Obtain the IDirect3DTexture9 interface and return that.
585             return Entry.pTexture->QueryInterface( IID_IDirect3DTexture9, (LPVOID*)ppTexture );
586         }
587     }
588 
589     HRESULT hr;
590 
591     // No matching entry.  Load the resource and create a new entry.
592     hr = D3DXCreateTextureFromFileEx( pDevice, pSrcFile, Width, Height, MipLevels, Usage, Format,
593                                       Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppTexture );
594     if( FAILED( hr ) )
595         return hr;
596 
597     DXUTCache_Texture NewEntry;
598     NewEntry.Location = DXUTCACHE_LOCATION_FILE;
599     StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcFile );
600     NewEntry.Width = Width;
601     NewEntry.Height = Height;
602     NewEntry.MipLevels = MipLevels;
603     NewEntry.Usage = Usage;
604     NewEntry.Format = Format;
605     NewEntry.Pool = Pool;
606     NewEntry.Type = D3DRTYPE_TEXTURE;
607     (*ppTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
608 
609     m_TextureCache.Add( NewEntry );
610     return S_OK;
611 }
612 
613 
614 //--------------------------------------------------------------------------------------
CreateTextureFromResource(LPDIRECT3DDEVICE9 pDevice,HMODULE hSrcModule,LPCTSTR pSrcResource,LPDIRECT3DTEXTURE9 * ppTexture)615 HRESULT CDXUTResourceCache::CreateTextureFromResource( LPDIRECT3DDEVICE9 pDevice, HMODULE hSrcModule, LPCTSTR pSrcResource, LPDIRECT3DTEXTURE9 *ppTexture )
616 {
617     return CreateTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, D3DX_DEFAULT, D3DX_DEFAULT,
618                                         D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT,
619                                         D3DX_DEFAULT, 0, NULL, NULL, ppTexture );
620 }
621 
622 
623 //--------------------------------------------------------------------------------------
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)624 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 )
625 {
626     // Search the cache for a matching entry.
627     for( int i = 0; i < m_TextureCache.GetSize(); ++i )
628     {
629         DXUTCache_Texture &Entry = m_TextureCache[i];
630         if( Entry.Location == DXUTCACHE_LOCATION_RESOURCE &&
631             Entry.hSrcModule == hSrcModule &&
632             !lstrcmpW( Entry.wszSource, pSrcResource ) &&
633             Entry.Width == Width &&
634             Entry.Height == Height &&
635             Entry.MipLevels == MipLevels &&
636             Entry.Usage == Usage &&
637             Entry.Format == Format &&
638             Entry.Pool == Pool &&
639             Entry.Type == D3DRTYPE_TEXTURE )
640         {
641             // A match is found. Obtain the IDirect3DTexture9 interface and return that.
642             return Entry.pTexture->QueryInterface( IID_IDirect3DTexture9, (LPVOID*)ppTexture );
643         }
644     }
645 
646     HRESULT hr;
647 
648     // No matching entry.  Load the resource and create a new entry.
649     hr = D3DXCreateTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, Width, Height, MipLevels, Usage,
650                                           Format, Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppTexture );
651     if( FAILED( hr ) )
652         return hr;
653 
654     DXUTCache_Texture NewEntry;
655     NewEntry.Location = DXUTCACHE_LOCATION_RESOURCE;
656     NewEntry.hSrcModule = hSrcModule;
657     StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcResource );
658     NewEntry.Width = Width;
659     NewEntry.Height = Height;
660     NewEntry.MipLevels = MipLevels;
661     NewEntry.Usage = Usage;
662     NewEntry.Format = Format;
663     NewEntry.Pool = Pool;
664     NewEntry.Type = D3DRTYPE_TEXTURE;
665     (*ppTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
666 
667     m_TextureCache.Add( NewEntry );
668     return S_OK;
669 }
670 
671 
672 //--------------------------------------------------------------------------------------
CreateCubeTextureFromFile(LPDIRECT3DDEVICE9 pDevice,LPCTSTR pSrcFile,LPDIRECT3DCUBETEXTURE9 * ppCubeTexture)673 HRESULT CDXUTResourceCache::CreateCubeTextureFromFile( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, LPDIRECT3DCUBETEXTURE9 *ppCubeTexture )
674 {
675     return CreateCubeTextureFromFileEx( pDevice, pSrcFile, D3DX_DEFAULT, D3DX_DEFAULT, 0,
676                                         D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT,
677                                         0, NULL, NULL, ppCubeTexture );
678 }
679 
680 
681 //--------------------------------------------------------------------------------------
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)682 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 )
683 {
684     // Search the cache for a matching entry.
685     for( int i = 0; i < m_TextureCache.GetSize(); ++i )
686     {
687         DXUTCache_Texture &Entry = m_TextureCache[i];
688         if( Entry.Location == DXUTCACHE_LOCATION_FILE &&
689             !lstrcmpW( Entry.wszSource, pSrcFile ) &&
690             Entry.Width == Size &&
691             Entry.MipLevels == MipLevels &&
692             Entry.Usage == Usage &&
693             Entry.Format == Format &&
694             Entry.Pool == Pool &&
695             Entry.Type == D3DRTYPE_CUBETEXTURE )
696         {
697             // A match is found. Obtain the IDirect3DCubeTexture9 interface and return that.
698             return Entry.pTexture->QueryInterface( IID_IDirect3DCubeTexture9, (LPVOID*)ppCubeTexture );
699         }
700     }
701 
702     HRESULT hr;
703 
704     // No matching entry.  Load the resource and create a new entry.
705     hr = D3DXCreateCubeTextureFromFileEx( pDevice, pSrcFile, Size, MipLevels, Usage, Format, Pool, Filter,
706                                           MipFilter, ColorKey, pSrcInfo, pPalette, ppCubeTexture );
707     if( FAILED( hr ) )
708         return hr;
709 
710     DXUTCache_Texture NewEntry;
711     NewEntry.Location = DXUTCACHE_LOCATION_FILE;
712     StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcFile );
713     NewEntry.Width = Size;
714     NewEntry.MipLevels = MipLevels;
715     NewEntry.Usage = Usage;
716     NewEntry.Format = Format;
717     NewEntry.Pool = Pool;
718     NewEntry.Type = D3DRTYPE_CUBETEXTURE;
719     (*ppCubeTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
720 
721     m_TextureCache.Add( NewEntry );
722     return S_OK;
723 }
724 
725 
726 //--------------------------------------------------------------------------------------
CreateCubeTextureFromResource(LPDIRECT3DDEVICE9 pDevice,HMODULE hSrcModule,LPCTSTR pSrcResource,LPDIRECT3DCUBETEXTURE9 * ppCubeTexture)727 HRESULT CDXUTResourceCache::CreateCubeTextureFromResource( LPDIRECT3DDEVICE9 pDevice, HMODULE hSrcModule, LPCTSTR pSrcResource, LPDIRECT3DCUBETEXTURE9 *ppCubeTexture )
728 {
729     return CreateCubeTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, D3DX_DEFAULT, D3DX_DEFAULT,
730                                             0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT,
731                                             0, NULL, NULL, ppCubeTexture );
732 }
733 
734 
735 //--------------------------------------------------------------------------------------
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)736 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 )
737 {
738     // Search the cache for a matching entry.
739     for( int i = 0; i < m_TextureCache.GetSize(); ++i )
740     {
741         DXUTCache_Texture &Entry = m_TextureCache[i];
742         if( Entry.Location == DXUTCACHE_LOCATION_RESOURCE &&
743             Entry.hSrcModule == hSrcModule &&
744             !lstrcmpW( Entry.wszSource, pSrcResource ) &&
745             Entry.Width == Size &&
746             Entry.MipLevels == MipLevels &&
747             Entry.Usage == Usage &&
748             Entry.Format == Format &&
749             Entry.Pool == Pool &&
750             Entry.Type == D3DRTYPE_CUBETEXTURE )
751         {
752             // A match is found. Obtain the IDirect3DCubeTexture9 interface and return that.
753             return Entry.pTexture->QueryInterface( IID_IDirect3DCubeTexture9, (LPVOID*)ppCubeTexture );
754         }
755     }
756 
757     HRESULT hr;
758 
759     // No matching entry.  Load the resource and create a new entry.
760     hr = D3DXCreateCubeTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, Size, MipLevels, Usage, Format,
761                                               Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppCubeTexture );
762     if( FAILED( hr ) )
763         return hr;
764 
765     DXUTCache_Texture NewEntry;
766     NewEntry.Location = DXUTCACHE_LOCATION_RESOURCE;
767     NewEntry.hSrcModule = hSrcModule;
768     StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcResource );
769     NewEntry.Width = Size;
770     NewEntry.MipLevels = MipLevels;
771     NewEntry.Usage = Usage;
772     NewEntry.Format = Format;
773     NewEntry.Pool = Pool;
774     NewEntry.Type = D3DRTYPE_CUBETEXTURE;
775     (*ppCubeTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
776 
777     m_TextureCache.Add( NewEntry );
778     return S_OK;
779 }
780 
781 
782 //--------------------------------------------------------------------------------------
CreateVolumeTextureFromFile(LPDIRECT3DDEVICE9 pDevice,LPCTSTR pSrcFile,LPDIRECT3DVOLUMETEXTURE9 * ppVolumeTexture)783 HRESULT CDXUTResourceCache::CreateVolumeTextureFromFile( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, LPDIRECT3DVOLUMETEXTURE9 *ppVolumeTexture )
784 {
785     return CreateVolumeTextureFromFileEx( pDevice, pSrcFile, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
786                                           0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT,
787                                           0, NULL, NULL, ppVolumeTexture );
788 }
789 
790 
791 //--------------------------------------------------------------------------------------
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)792 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 )
793 {
794     // Search the cache for a matching entry.
795     for( int i = 0; i < m_TextureCache.GetSize(); ++i )
796     {
797         DXUTCache_Texture &Entry = m_TextureCache[i];
798         if( Entry.Location == DXUTCACHE_LOCATION_FILE &&
799             !lstrcmpW( Entry.wszSource, pSrcFile ) &&
800             Entry.Width == Width &&
801             Entry.Height == Height &&
802             Entry.Depth == Depth &&
803             Entry.MipLevels == MipLevels &&
804             Entry.Usage == Usage &&
805             Entry.Format == Format &&
806             Entry.Pool == Pool &&
807             Entry.Type == D3DRTYPE_VOLUMETEXTURE )
808         {
809             // A match is found. Obtain the IDirect3DVolumeTexture9 interface and return that.
810             return Entry.pTexture->QueryInterface( IID_IDirect3DVolumeTexture9, (LPVOID*)ppTexture );
811         }
812     }
813 
814     HRESULT hr;
815 
816     // No matching entry.  Load the resource and create a new entry.
817     hr = D3DXCreateVolumeTextureFromFileEx( pDevice, pSrcFile, Width, Height, Depth, MipLevels, Usage, Format,
818                                             Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppTexture );
819     if( FAILED( hr ) )
820         return hr;
821 
822     DXUTCache_Texture NewEntry;
823     NewEntry.Location = DXUTCACHE_LOCATION_FILE;
824     StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcFile );
825     NewEntry.Width = Width;
826     NewEntry.Height = Height;
827     NewEntry.Depth = Depth;
828     NewEntry.MipLevels = MipLevels;
829     NewEntry.Usage = Usage;
830     NewEntry.Format = Format;
831     NewEntry.Pool = Pool;
832     NewEntry.Type = D3DRTYPE_VOLUMETEXTURE;
833     (*ppTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
834 
835     m_TextureCache.Add( NewEntry );
836     return S_OK;
837 }
838 
839 
840 //--------------------------------------------------------------------------------------
CreateVolumeTextureFromResource(LPDIRECT3DDEVICE9 pDevice,HMODULE hSrcModule,LPCTSTR pSrcResource,LPDIRECT3DVOLUMETEXTURE9 * ppVolumeTexture)841 HRESULT CDXUTResourceCache::CreateVolumeTextureFromResource( LPDIRECT3DDEVICE9 pDevice, HMODULE hSrcModule, LPCTSTR pSrcResource, LPDIRECT3DVOLUMETEXTURE9 *ppVolumeTexture )
842 {
843     return CreateVolumeTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, D3DX_DEFAULT, D3DX_DEFAULT,
844                                               D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
845                                               D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, ppVolumeTexture );
846 }
847 
848 
849 //--------------------------------------------------------------------------------------
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)850 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 )
851 {
852     // Search the cache for a matching entry.
853     for( int i = 0; i < m_TextureCache.GetSize(); ++i )
854     {
855         DXUTCache_Texture &Entry = m_TextureCache[i];
856         if( Entry.Location == DXUTCACHE_LOCATION_RESOURCE &&
857             Entry.hSrcModule == hSrcModule &&
858             !lstrcmpW( Entry.wszSource, pSrcResource ) &&
859             Entry.Width == Width &&
860             Entry.Height == Height &&
861             Entry.Depth == Depth &&
862             Entry.MipLevels == MipLevels &&
863             Entry.Usage == Usage &&
864             Entry.Format == Format &&
865             Entry.Pool == Pool &&
866             Entry.Type == D3DRTYPE_VOLUMETEXTURE )
867         {
868             // A match is found. Obtain the IDirect3DVolumeTexture9 interface and return that.
869             return Entry.pTexture->QueryInterface( IID_IDirect3DVolumeTexture9, (LPVOID*)ppVolumeTexture );
870         }
871     }
872 
873     HRESULT hr;
874 
875     // No matching entry.  Load the resource and create a new entry.
876     hr = D3DXCreateVolumeTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, Width, Height, Depth, MipLevels, Usage,
877                                                 Format, Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppVolumeTexture );
878     if( FAILED( hr ) )
879         return hr;
880 
881     DXUTCache_Texture NewEntry;
882     NewEntry.Location = DXUTCACHE_LOCATION_RESOURCE;
883     NewEntry.hSrcModule = hSrcModule;
884     StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcResource );
885     NewEntry.Width = Width;
886     NewEntry.Height = Height;
887     NewEntry.Depth = Depth;
888     NewEntry.MipLevels = MipLevels;
889     NewEntry.Usage = Usage;
890     NewEntry.Format = Format;
891     NewEntry.Pool = Pool;
892     NewEntry.Type = D3DRTYPE_VOLUMETEXTURE;
893     (*ppVolumeTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
894 
895     m_TextureCache.Add( NewEntry );
896     return S_OK;
897 }
898 
899 
900 //--------------------------------------------------------------------------------------
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)901 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 )
902 {
903     D3DXFONT_DESCW Desc;
904 
905     Desc.Height = Height;
906     Desc.Width = Width;
907     Desc.Weight = Weight;
908     Desc.MipLevels = MipLevels;
909     Desc.Italic = Italic;
910     Desc.CharSet = (BYTE)CharSet;
911     Desc.OutputPrecision = (BYTE)OutputPrecision;
912     Desc.Quality = (BYTE)Quality;
913     Desc.PitchAndFamily = (BYTE)PitchAndFamily;
914     StringCchCopy( Desc.FaceName, LF_FACESIZE, pFacename );
915 
916     return CreateFontIndirect( pDevice, &Desc, ppFont );
917 }
918 
919 
920 //--------------------------------------------------------------------------------------
CreateFontIndirect(LPDIRECT3DDEVICE9 pDevice,CONST D3DXFONT_DESC * pDesc,LPD3DXFONT * ppFont)921 HRESULT CDXUTResourceCache::CreateFontIndirect( LPDIRECT3DDEVICE9 pDevice, CONST D3DXFONT_DESC *pDesc, LPD3DXFONT *ppFont )
922 {
923     // Search the cache for a matching entry.
924     for( int i = 0; i < m_FontCache.GetSize(); ++i )
925     {
926         DXUTCache_Font &Entry = m_FontCache[i];
927 
928         if( Entry.Width == pDesc->Width &&
929             Entry.Height == pDesc->Height &&
930             Entry.Weight == pDesc->Weight &&
931             Entry.MipLevels == pDesc->MipLevels &&
932             Entry.Italic == pDesc->Italic &&
933             Entry.CharSet == pDesc->CharSet &&
934             Entry.OutputPrecision == pDesc->OutputPrecision &&
935             Entry.Quality == pDesc->Quality &&
936             Entry.PitchAndFamily == pDesc->PitchAndFamily &&
937             CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE,
938                            Entry.FaceName, -1,
939                            pDesc->FaceName, -1 ) == CSTR_EQUAL )
940         {
941             // A match is found.  Increment the reference and return the ID3DXFont object.
942             Entry.pFont->AddRef();
943             *ppFont = Entry.pFont;
944             return S_OK;
945         }
946     }
947 
948     HRESULT hr;
949 
950     // No matching entry.  Load the resource and create a new entry.
951     hr = D3DXCreateFontIndirect( pDevice, pDesc, ppFont );
952     if( FAILED( hr ) )
953         return hr;
954 
955     DXUTCache_Font NewEntry;
956     (D3DXFONT_DESC &)NewEntry = *pDesc;
957     NewEntry.pFont = *ppFont;
958     NewEntry.pFont->AddRef();
959 
960     m_FontCache.Add( NewEntry );
961     return S_OK;
962 }
963 
964 
965 //--------------------------------------------------------------------------------------
CreateEffectFromFile(LPDIRECT3DDEVICE9 pDevice,LPCTSTR pSrcFile,const D3DXMACRO * pDefines,LPD3DXINCLUDE pInclude,DWORD Flags,LPD3DXEFFECTPOOL pPool,LPD3DXEFFECT * ppEffect,LPD3DXBUFFER * ppCompilationErrors)966 HRESULT CDXUTResourceCache::CreateEffectFromFile( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, const D3DXMACRO *pDefines, LPD3DXINCLUDE pInclude, DWORD Flags, LPD3DXEFFECTPOOL pPool, LPD3DXEFFECT *ppEffect, LPD3DXBUFFER *ppCompilationErrors )
967 {
968     // Search the cache for a matching entry.
969     for( int i = 0; i < m_EffectCache.GetSize(); ++i )
970     {
971         DXUTCache_Effect &Entry = m_EffectCache[i];
972 
973         if( Entry.Location == DXUTCACHE_LOCATION_FILE &&
974             !lstrcmpW( Entry.wszSource, pSrcFile ) &&
975             Entry.dwFlags == Flags )
976         {
977             // A match is found.  Increment the ref coutn and return the ID3DXEffect object.
978             *ppEffect = Entry.pEffect;
979             (*ppEffect)->AddRef();
980             return S_OK;
981         }
982     }
983 
984     HRESULT hr;
985 
986     // No matching entry.  Load the resource and create a new entry.
987     hr = D3DXCreateEffectFromFile( pDevice, pSrcFile, pDefines, pInclude, Flags, pPool, ppEffect, ppCompilationErrors );
988     if( FAILED( hr ) )
989         return hr;
990 
991     DXUTCache_Effect NewEntry;
992     NewEntry.Location = DXUTCACHE_LOCATION_FILE;
993     StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcFile );
994     NewEntry.dwFlags = Flags;
995     NewEntry.pEffect = *ppEffect;
996     NewEntry.pEffect->AddRef();
997 
998     m_EffectCache.Add( NewEntry );
999     return S_OK;
1000 }
1001 
1002 
1003 //--------------------------------------------------------------------------------------
CreateEffectFromResource(LPDIRECT3DDEVICE9 pDevice,HMODULE hSrcModule,LPCTSTR pSrcResource,const D3DXMACRO * pDefines,LPD3DXINCLUDE pInclude,DWORD Flags,LPD3DXEFFECTPOOL pPool,LPD3DXEFFECT * ppEffect,LPD3DXBUFFER * ppCompilationErrors)1004 HRESULT CDXUTResourceCache::CreateEffectFromResource( LPDIRECT3DDEVICE9 pDevice, HMODULE hSrcModule, LPCTSTR pSrcResource, const D3DXMACRO *pDefines, LPD3DXINCLUDE pInclude, DWORD Flags, LPD3DXEFFECTPOOL pPool, LPD3DXEFFECT *ppEffect, LPD3DXBUFFER *ppCompilationErrors )
1005 {
1006     // Search the cache for a matching entry.
1007     for( int i = 0; i < m_EffectCache.GetSize(); ++i )
1008     {
1009         DXUTCache_Effect &Entry = m_EffectCache[i];
1010 
1011         if( Entry.Location == DXUTCACHE_LOCATION_RESOURCE &&
1012             Entry.hSrcModule == hSrcModule &&
1013             !lstrcmpW( Entry.wszSource, pSrcResource ) &&
1014             Entry.dwFlags == Flags )
1015         {
1016             // A match is found.  Increment the ref coutn and return the ID3DXEffect object.
1017             *ppEffect = Entry.pEffect;
1018             (*ppEffect)->AddRef();
1019             return S_OK;
1020         }
1021     }
1022 
1023     HRESULT hr;
1024 
1025     // No matching entry.  Load the resource and create a new entry.
1026     hr = D3DXCreateEffectFromResource( pDevice, hSrcModule, pSrcResource, pDefines, pInclude, Flags,
1027                                        pPool, ppEffect, ppCompilationErrors );
1028     if( FAILED( hr ) )
1029         return hr;
1030 
1031     DXUTCache_Effect NewEntry;
1032     NewEntry.Location = DXUTCACHE_LOCATION_RESOURCE;
1033     NewEntry.hSrcModule = hSrcModule;
1034     StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcResource );
1035     NewEntry.dwFlags = Flags;
1036     NewEntry.pEffect = *ppEffect;
1037     NewEntry.pEffect->AddRef();
1038 
1039     m_EffectCache.Add( NewEntry );
1040     return S_OK;
1041 }
1042 
1043 
1044 //--------------------------------------------------------------------------------------
1045 // Device event callbacks
1046 //--------------------------------------------------------------------------------------
1047 
1048 
1049 //--------------------------------------------------------------------------------------
OnCreateDevice(IDirect3DDevice9 * pd3dDevice)1050 HRESULT CDXUTResourceCache::OnCreateDevice( IDirect3DDevice9 *pd3dDevice )
1051 {
1052     return S_OK;
1053 }
1054 
1055 
1056 //--------------------------------------------------------------------------------------
OnResetDevice(IDirect3DDevice9 * pd3dDevice)1057 HRESULT CDXUTResourceCache::OnResetDevice( IDirect3DDevice9 *pd3dDevice )
1058 {
1059     // Call OnResetDevice on all effect and font objects
1060     for( int i = 0; i < m_EffectCache.GetSize(); ++i )
1061         m_EffectCache[i].pEffect->OnResetDevice();
1062     for( int i = 0; i < m_FontCache.GetSize(); ++i )
1063         m_FontCache[i].pFont->OnResetDevice();
1064 
1065 
1066     return S_OK;
1067 }
1068 
1069 
1070 //--------------------------------------------------------------------------------------
OnLostDevice()1071 HRESULT CDXUTResourceCache::OnLostDevice()
1072 {
1073     // Call OnLostDevice on all effect and font objects
1074     for( int i = 0; i < m_EffectCache.GetSize(); ++i )
1075         m_EffectCache[i].pEffect->OnLostDevice();
1076     for( int i = 0; i < m_FontCache.GetSize(); ++i )
1077         m_FontCache[i].pFont->OnLostDevice();
1078 
1079     // Release all the default pool textures
1080     for( int i = m_TextureCache.GetSize() - 1; i >= 0; --i )
1081         if( m_TextureCache[i].Pool == D3DPOOL_DEFAULT )
1082         {
1083             SAFE_RELEASE( m_TextureCache[i].pTexture );
1084             m_TextureCache.Remove( i );  // Remove the entry
1085         }
1086 
1087     return S_OK;
1088 }
1089 
1090 
1091 //--------------------------------------------------------------------------------------
OnDestroyDevice()1092 HRESULT CDXUTResourceCache::OnDestroyDevice()
1093 {
1094     // Release all resources
1095     for( int i = m_EffectCache.GetSize() - 1; i >= 0; --i )
1096     {
1097         SAFE_RELEASE( m_EffectCache[i].pEffect );
1098         m_EffectCache.Remove( i );
1099     }
1100     for( int i = m_FontCache.GetSize() - 1; i >= 0; --i )
1101     {
1102         SAFE_RELEASE( m_FontCache[i].pFont );
1103         m_FontCache.Remove( i );
1104     }
1105     for( int i = m_TextureCache.GetSize() - 1; i >= 0; --i )
1106     {
1107         SAFE_RELEASE( m_TextureCache[i].pTexture );
1108         m_TextureCache.Remove( i );
1109     }
1110 
1111     return S_OK;
1112 }
1113 
1114 
1115 //--------------------------------------------------------------------------------------
CD3DArcBall()1116 CD3DArcBall::CD3DArcBall()
1117 {
1118     Reset();
1119     m_vDownPt = D3DXVECTOR3(0,0,0);
1120     m_vCurrentPt = D3DXVECTOR3(0,0,0);
1121     m_Offset.x = m_Offset.y = 0;
1122 
1123     RECT rc;
1124     GetClientRect( GetForegroundWindow(), &rc );
1125     SetWindow( rc.right, rc.bottom );
1126 }
1127 
1128 
1129 
1130 
1131 
1132 //--------------------------------------------------------------------------------------
Reset()1133 void CD3DArcBall::Reset()
1134 {
1135     D3DXQuaternionIdentity( &m_qDown );
1136     D3DXQuaternionIdentity( &m_qNow );
1137     D3DXMatrixIdentity( &m_mRotation );
1138     D3DXMatrixIdentity( &m_mTranslation );
1139     D3DXMatrixIdentity( &m_mTranslationDelta );
1140     m_bDrag = FALSE;
1141     m_fRadiusTranslation = 1.0f;
1142     m_fRadius = 1.0f;
1143 }
1144 
1145 
1146 
1147 
1148 //--------------------------------------------------------------------------------------
ScreenToVector(float fScreenPtX,float fScreenPtY)1149 D3DXVECTOR3 CD3DArcBall::ScreenToVector( float fScreenPtX, float fScreenPtY )
1150 {
1151     // Scale to screen
1152     FLOAT x   = -(fScreenPtX - m_Offset.x - m_nWidth/2)  / (m_fRadius*m_nWidth/2);
1153     FLOAT y   =  (fScreenPtY - m_Offset.y - m_nHeight/2) / (m_fRadius*m_nHeight/2);
1154 
1155     FLOAT z   = 0.0f;
1156     FLOAT mag = x*x + y*y;
1157 
1158     if( mag > 1.0f )
1159     {
1160         FLOAT scale = 1.0f/sqrtf(mag);
1161         x *= scale;
1162         y *= scale;
1163     }
1164     else
1165         z = sqrtf( 1.0f - mag );
1166 
1167     // Return vector
1168     return D3DXVECTOR3( x, y, z );
1169 }
1170 
1171 
1172 
1173 
1174 //--------------------------------------------------------------------------------------
QuatFromBallPoints(const D3DXVECTOR3 & vFrom,const D3DXVECTOR3 & vTo)1175 D3DXQUATERNION CD3DArcBall::QuatFromBallPoints(const D3DXVECTOR3 &vFrom, const D3DXVECTOR3 &vTo)
1176 {
1177     D3DXVECTOR3 vPart;
1178     float fDot = D3DXVec3Dot(&vFrom, &vTo);
1179     D3DXVec3Cross(&vPart, &vFrom, &vTo);
1180 
1181     return D3DXQUATERNION(vPart.x, vPart.y, vPart.z, fDot);
1182 }
1183 
1184 
1185 
1186 
1187 //--------------------------------------------------------------------------------------
OnBegin(int nX,int nY)1188 void CD3DArcBall::OnBegin( int nX, int nY )
1189 {
1190     // Only enter the drag state if the click falls
1191     // inside the click rectangle.
1192     if( nX >= m_Offset.x &&
1193         nX < m_Offset.x + m_nWidth &&
1194         nY >= m_Offset.y &&
1195         nY < m_Offset.y + m_nHeight )
1196     {
1197         m_bDrag = true;
1198         m_qDown = m_qNow;
1199         m_vDownPt = ScreenToVector( (float)nX, (float)nY );
1200     }
1201 }
1202 
1203 
1204 
1205 
1206 //--------------------------------------------------------------------------------------
OnMove(int nX,int nY)1207 void CD3DArcBall::OnMove( int nX, int nY )
1208 {
1209     if (m_bDrag)
1210     {
1211         m_vCurrentPt = ScreenToVector( (float)nX, (float)nY );
1212         m_qNow = m_qDown * QuatFromBallPoints( m_vDownPt, m_vCurrentPt );
1213     }
1214 }
1215 
1216 
1217 
1218 
1219 //--------------------------------------------------------------------------------------
OnEnd()1220 void CD3DArcBall::OnEnd()
1221 {
1222     m_bDrag = false;
1223 }
1224 
1225 
1226 
1227 
1228 //--------------------------------------------------------------------------------------
1229 // Desc:
1230 //--------------------------------------------------------------------------------------
HandleMessages(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)1231 LRESULT CD3DArcBall::HandleMessages( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1232 {
1233     // Current mouse position
1234     int iMouseX = (short)LOWORD(lParam);
1235     int iMouseY = (short)HIWORD(lParam);
1236 
1237     switch( uMsg )
1238     {
1239         case WM_LBUTTONDOWN:
1240         case WM_LBUTTONDBLCLK:
1241             SetCapture( hWnd );
1242             OnBegin( iMouseX, iMouseY );
1243             return TRUE;
1244 
1245         case WM_LBUTTONUP:
1246             ReleaseCapture();
1247             OnEnd();
1248             return TRUE;
1249 
1250         case WM_CAPTURECHANGED:
1251             if( (HWND)lParam != hWnd )
1252             {
1253                 ReleaseCapture();
1254                 OnEnd();
1255             }
1256             return TRUE;
1257 
1258         case WM_RBUTTONDOWN:
1259         case WM_RBUTTONDBLCLK:
1260         case WM_MBUTTONDOWN:
1261         case WM_MBUTTONDBLCLK:
1262             SetCapture( hWnd );
1263             // Store off the position of the cursor when the button is pressed
1264             m_ptLastMouse.x = iMouseX;
1265             m_ptLastMouse.y = iMouseY;
1266             return TRUE;
1267 
1268         case WM_RBUTTONUP:
1269         case WM_MBUTTONUP:
1270             ReleaseCapture();
1271             return TRUE;
1272 
1273         case WM_MOUSEMOVE:
1274             if( MK_LBUTTON&wParam )
1275             {
1276                 OnMove( iMouseX, iMouseY );
1277             }
1278             else if( (MK_RBUTTON&wParam) || (MK_MBUTTON&wParam) )
1279             {
1280                 // Normalize based on size of window and bounding sphere radius
1281                 FLOAT fDeltaX = ( m_ptLastMouse.x-iMouseX ) * m_fRadiusTranslation / m_nWidth;
1282                 FLOAT fDeltaY = ( m_ptLastMouse.y-iMouseY ) * m_fRadiusTranslation / m_nHeight;
1283 
1284                 if( wParam & MK_RBUTTON )
1285                 {
1286                     D3DXMatrixTranslation( &m_mTranslationDelta, -2*fDeltaX, 2*fDeltaY, 0.0f );
1287                     D3DXMatrixMultiply( &m_mTranslation, &m_mTranslation, &m_mTranslationDelta );
1288                 }
1289                 else  // wParam & MK_MBUTTON
1290                 {
1291                     D3DXMatrixTranslation( &m_mTranslationDelta, 0.0f, 0.0f, 5*fDeltaY );
1292                     D3DXMatrixMultiply( &m_mTranslation, &m_mTranslation, &m_mTranslationDelta );
1293                 }
1294 
1295                 // Store mouse coordinate
1296                 m_ptLastMouse.x = iMouseX;
1297                 m_ptLastMouse.y = iMouseY;
1298             }
1299             return TRUE;
1300     }
1301 
1302     return FALSE;
1303 }
1304 
1305 
1306 
1307 
1308 //--------------------------------------------------------------------------------------
1309 // Constructor
1310 //--------------------------------------------------------------------------------------
CBaseCamera()1311 CBaseCamera::CBaseCamera()
1312 {
1313     m_cKeysDown = 0;
1314     ZeroMemory( m_aKeys, sizeof(BYTE)*CAM_MAX_KEYS );
1315     ZeroMemory( m_GamePad, sizeof(DXUT_GAMEPAD)*DXUT_MAX_CONTROLLERS );
1316 
1317     // Set attributes for the view matrix
1318     D3DXVECTOR3 vEyePt    = D3DXVECTOR3(0.0f,0.0f,0.0f);
1319     D3DXVECTOR3 vLookatPt = D3DXVECTOR3(0.0f,0.0f,1.0f);
1320 
1321     // Setup the view matrix
1322     SetViewParams( &vEyePt, &vLookatPt );
1323 
1324     // Setup the projection matrix
1325     SetProjParams( D3DX_PI/4, 1.0f, 1.0f, 1000.0f );
1326 
1327     GetCursorPos( &m_ptLastMousePosition );
1328     m_bMouseLButtonDown = false;
1329     m_bMouseMButtonDown = false;
1330     m_bMouseRButtonDown = false;
1331     m_nCurrentButtonMask = 0;
1332     m_nMouseWheelDelta = 0;
1333 
1334     m_fCameraYawAngle = 0.0f;
1335     m_fCameraPitchAngle = 0.0f;
1336 
1337     SetRect( &m_rcDrag, LONG_MIN, LONG_MIN, LONG_MAX, LONG_MAX );
1338     m_vVelocity     = D3DXVECTOR3(0,0,0);
1339     m_bMovementDrag = false;
1340     m_vVelocityDrag = D3DXVECTOR3(0,0,0);
1341     m_fDragTimer    = 0.0f;
1342     m_fTotalDragTimeToZero = 0.25;
1343     m_vRotVelocity = D3DXVECTOR2(0,0);
1344 
1345     m_fRotationScaler = 0.01f;
1346     m_fMoveScaler = 5.0f;
1347 
1348     m_bInvertPitch = false;
1349     m_bEnableYAxisMovement = true;
1350     m_bEnablePositionMovement = true;
1351 
1352     m_vMouseDelta   = D3DXVECTOR2(0,0);
1353     m_fFramesToSmoothMouseData = 2.0f;
1354 
1355     m_bClipToBoundary = false;
1356     m_vMinBoundary = D3DXVECTOR3(-1,-1,-1);
1357     m_vMaxBoundary = D3DXVECTOR3(1,1,1);
1358 }
1359 
1360 
1361 //--------------------------------------------------------------------------------------
1362 // Client can call this to change the position and direction of camera
1363 //--------------------------------------------------------------------------------------
SetViewParams(D3DXVECTOR3 * pvEyePt,D3DXVECTOR3 * pvLookatPt)1364 VOID CBaseCamera::SetViewParams( D3DXVECTOR3* pvEyePt, D3DXVECTOR3* pvLookatPt )
1365 {
1366     if( NULL == pvEyePt || NULL == pvLookatPt )
1367         return;
1368 
1369     m_vDefaultEye = m_vEye = *pvEyePt;
1370     m_vDefaultLookAt = m_vLookAt = *pvLookatPt;
1371 
1372     // Calc the view matrix
1373     D3DXVECTOR3 vUp(0,1,0);
1374     D3DXMatrixLookAtLH( &m_mView, pvEyePt, pvLookatPt, &vUp );
1375 
1376     D3DXMATRIX mInvView;
1377     D3DXMatrixInverse( &mInvView, NULL, &m_mView );
1378 
1379     // The axis basis vectors and camera position are stored inside the
1380     // position matrix in the 4 rows of the camera's world matrix.
1381     // To figure out the yaw/pitch of the camera, we just need the Z basis vector
1382     D3DXVECTOR3* pZBasis = (D3DXVECTOR3*) &mInvView._31;
1383 
1384     m_fCameraYawAngle   = atan2f( pZBasis->x, pZBasis->z );
1385     float fLen = sqrtf(pZBasis->z*pZBasis->z + pZBasis->x*pZBasis->x);
1386     m_fCameraPitchAngle = -atan2f( pZBasis->y, fLen );
1387 }
1388 
1389 
1390 
1391 
1392 //--------------------------------------------------------------------------------------
1393 // Calculates the projection matrix based on input params
1394 //--------------------------------------------------------------------------------------
SetProjParams(FLOAT fFOV,FLOAT fAspect,FLOAT fNearPlane,FLOAT fFarPlane)1395 VOID CBaseCamera::SetProjParams( FLOAT fFOV, FLOAT fAspect, FLOAT fNearPlane,
1396                                    FLOAT fFarPlane )
1397 {
1398     // Set attributes for the projection matrix
1399     m_fFOV        = fFOV;
1400     m_fAspect     = fAspect;
1401     m_fNearPlane  = fNearPlane;
1402     m_fFarPlane   = fFarPlane;
1403 
1404     D3DXMatrixPerspectiveFovLH( &m_mProj, fFOV, fAspect, fNearPlane, fFarPlane );
1405 }
1406 
1407 
1408 
1409 
1410 //--------------------------------------------------------------------------------------
1411 // Call this from your message proc so this class can handle window messages
1412 //--------------------------------------------------------------------------------------
HandleMessages(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)1413 LRESULT CBaseCamera::HandleMessages( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1414 {
1415     UNREFERENCED_PARAMETER( hWnd );
1416     UNREFERENCED_PARAMETER( lParam );
1417 
1418     switch( uMsg )
1419     {
1420         case WM_KEYDOWN:
1421         {
1422             // Map this key to a D3DUtil_CameraKeys enum and update the
1423             // state of m_aKeys[] by adding the KEY_WAS_DOWN_MASK|KEY_IS_DOWN_MASK mask
1424             // only if the key is not down
1425             D3DUtil_CameraKeys mappedKey = MapKey( (UINT)wParam );
1426             if( mappedKey != CAM_UNKNOWN )
1427             {
1428                 if( FALSE == IsKeyDown(m_aKeys[mappedKey]) )
1429                 {
1430                     m_aKeys[ mappedKey ] = KEY_WAS_DOWN_MASK | KEY_IS_DOWN_MASK;
1431                     ++m_cKeysDown;
1432                 }
1433             }
1434             break;
1435         }
1436 
1437         case WM_KEYUP:
1438         {
1439             // Map this key to a D3DUtil_CameraKeys enum and update the
1440             // state of m_aKeys[] by removing the KEY_IS_DOWN_MASK mask.
1441             D3DUtil_CameraKeys mappedKey = MapKey( (UINT)wParam );
1442             if( mappedKey != CAM_UNKNOWN && (DWORD)mappedKey < 8 )
1443             {
1444                 m_aKeys[ mappedKey ] &= ~KEY_IS_DOWN_MASK;
1445                 --m_cKeysDown;
1446             }
1447             break;
1448         }
1449 
1450         case WM_RBUTTONDOWN:
1451         case WM_MBUTTONDOWN:
1452         case WM_LBUTTONDOWN:
1453         case WM_RBUTTONDBLCLK:
1454         case WM_MBUTTONDBLCLK:
1455         case WM_LBUTTONDBLCLK:
1456         {
1457             // Compute the drag rectangle in screen coord.
1458             POINT ptCursor = { (short)LOWORD(lParam), (short)HIWORD(lParam) };
1459 
1460             // Update member var state
1461             if( ( uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK ) && PtInRect( &m_rcDrag, ptCursor ) )
1462                 { m_bMouseLButtonDown = true; m_nCurrentButtonMask |= MOUSE_LEFT_BUTTON; }
1463             if( ( uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONDBLCLK ) && PtInRect( &m_rcDrag, ptCursor ) )
1464                 { m_bMouseMButtonDown = true; m_nCurrentButtonMask |= MOUSE_MIDDLE_BUTTON; }
1465             if( ( uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONDBLCLK ) && PtInRect( &m_rcDrag, ptCursor ) )
1466                 { m_bMouseRButtonDown = true; m_nCurrentButtonMask |= MOUSE_RIGHT_BUTTON; }
1467 
1468             // Capture the mouse, so if the mouse button is
1469             // released outside the window, we'll get the WM_LBUTTONUP message
1470             SetCapture(hWnd);
1471             GetCursorPos( &m_ptLastMousePosition );
1472             return TRUE;
1473         }
1474 
1475         case WM_RBUTTONUP:
1476         case WM_MBUTTONUP:
1477         case WM_LBUTTONUP:
1478         {
1479             // Update member var state
1480             if( uMsg == WM_LBUTTONUP ) { m_bMouseLButtonDown = false; m_nCurrentButtonMask &= ~MOUSE_LEFT_BUTTON; }
1481             if( uMsg == WM_MBUTTONUP ) { m_bMouseMButtonDown = false; m_nCurrentButtonMask &= ~MOUSE_MIDDLE_BUTTON; }
1482             if( uMsg == WM_RBUTTONUP ) { m_bMouseRButtonDown = false; m_nCurrentButtonMask &= ~MOUSE_RIGHT_BUTTON; }
1483 
1484             // Release the capture if no mouse buttons down
1485             if( !m_bMouseLButtonDown  &&
1486                 !m_bMouseRButtonDown &&
1487                 !m_bMouseMButtonDown )
1488             {
1489                 ReleaseCapture();
1490             }
1491             break;
1492         }
1493 
1494         case WM_CAPTURECHANGED:
1495         {
1496             if( (HWND)lParam != hWnd )
1497             {
1498                 if( (m_nCurrentButtonMask & MOUSE_LEFT_BUTTON) ||
1499                     (m_nCurrentButtonMask & MOUSE_MIDDLE_BUTTON) ||
1500                     (m_nCurrentButtonMask & MOUSE_RIGHT_BUTTON) )
1501                 {
1502                     m_bMouseLButtonDown = false;
1503                     m_bMouseMButtonDown = false;
1504                     m_bMouseRButtonDown = false;
1505                     m_nCurrentButtonMask &= ~MOUSE_LEFT_BUTTON;
1506                     m_nCurrentButtonMask &= ~MOUSE_MIDDLE_BUTTON;
1507                     m_nCurrentButtonMask &= ~MOUSE_RIGHT_BUTTON;
1508                     ReleaseCapture();
1509                 }
1510             }
1511             break;
1512         }
1513 
1514         case WM_MOUSEWHEEL:
1515             // Update member var state
1516             m_nMouseWheelDelta = (short)HIWORD(wParam) / 120;
1517             break;
1518     }
1519 
1520     return FALSE;
1521 }
1522 
1523 
1524 //--------------------------------------------------------------------------------------
1525 // Figure out the velocity based on keyboard input & drag if any
1526 //--------------------------------------------------------------------------------------
GetInput(bool bGetKeyboardInput,bool bGetMouseInput,bool bGetGamepadInput,bool bResetCursorAfterMove)1527 void CBaseCamera::GetInput( bool bGetKeyboardInput, bool bGetMouseInput, bool bGetGamepadInput, bool bResetCursorAfterMove )
1528 {
1529     m_vKeyboardDirection = D3DXVECTOR3(0,0,0);
1530     if( bGetKeyboardInput )
1531     {
1532         // Update acceleration vector based on keyboard state
1533         if( IsKeyDown(m_aKeys[CAM_MOVE_FORWARD]) )
1534             m_vKeyboardDirection.z += 1.0f;
1535         if( IsKeyDown(m_aKeys[CAM_MOVE_BACKWARD]) )
1536             m_vKeyboardDirection.z -= 1.0f;
1537         if( m_bEnableYAxisMovement )
1538         {
1539             if( IsKeyDown(m_aKeys[CAM_MOVE_UP]) )
1540                 m_vKeyboardDirection.y += 1.0f;
1541             if( IsKeyDown(m_aKeys[CAM_MOVE_DOWN]) )
1542                 m_vKeyboardDirection.y -= 1.0f;
1543         }
1544         if( IsKeyDown(m_aKeys[CAM_STRAFE_RIGHT]) )
1545             m_vKeyboardDirection.x += 1.0f;
1546         if( IsKeyDown(m_aKeys[CAM_STRAFE_LEFT]) )
1547             m_vKeyboardDirection.x -= 1.0f;
1548     }
1549 
1550     if( bGetMouseInput )
1551     {
1552         // Get current position of mouse
1553         POINT ptCurMouseDelta;
1554         POINT ptCurMousePos;
1555 
1556         if( GetCursorPos( &ptCurMousePos ) )
1557         {
1558             // Calc how far it's moved since last frame
1559             ptCurMouseDelta.x = ptCurMousePos.x - m_ptLastMousePosition.x;
1560             ptCurMouseDelta.y = ptCurMousePos.y - m_ptLastMousePosition.y;
1561 
1562             // Record current position for next time
1563             m_ptLastMousePosition = ptCurMousePos;
1564         }
1565         else
1566         {
1567             // If GetCursorPos() returns false, just set delta to zero
1568             ptCurMouseDelta.x = 0;
1569             ptCurMouseDelta.y = 0;
1570         }
1571 
1572         if( bResetCursorAfterMove && DXUTIsActive() )
1573         {
1574             // Set position of camera to center of desktop,
1575             // so it always has room to move.  This is very useful
1576             // if the cursor is hidden.  If this isn't done and cursor is hidden,
1577             // then invisible cursor will hit the edge of the screen
1578             // and the user can't tell what happened
1579             POINT ptCenter;
1580 
1581             // Get the center of the current monitor
1582             MONITORINFO mi;
1583             mi.cbSize = sizeof(MONITORINFO);
1584             DXUTGetMonitorInfo( DXUTMonitorFromWindow(DXUTGetHWND(),MONITOR_DEFAULTTONEAREST), &mi );
1585             ptCenter.x = (mi.rcMonitor.left + mi.rcMonitor.right) / 2;
1586             ptCenter.y = (mi.rcMonitor.top + mi.rcMonitor.bottom) / 2;
1587             SetCursorPos( ptCenter.x, ptCenter.y );
1588             m_ptLastMousePosition = ptCenter;
1589         }
1590 
1591         // Smooth the relative mouse data over a few frames so it isn't
1592         // jerky when moving slowly at low frame rates.
1593         float fPercentOfNew =  1.0f / m_fFramesToSmoothMouseData;
1594         float fPercentOfOld =  1.0f - fPercentOfNew;
1595         m_vMouseDelta.x = m_vMouseDelta.x*fPercentOfOld + ptCurMouseDelta.x*fPercentOfNew;
1596         m_vMouseDelta.y = m_vMouseDelta.y*fPercentOfOld + ptCurMouseDelta.y*fPercentOfNew;
1597 
1598     }
1599 
1600     if( bGetGamepadInput )
1601     {
1602         m_vGamePadLeftThumb = D3DXVECTOR3(0,0,0);
1603         m_vGamePadRightThumb = D3DXVECTOR3(0,0,0);
1604 
1605         // Get controller state
1606         for( DWORD iUserIndex=0; iUserIndex<DXUT_MAX_CONTROLLERS; iUserIndex++ )
1607         {
1608             DXUTGetGamepadState( iUserIndex, &m_GamePad[iUserIndex], true, true );
1609 
1610             // Mark time if the controller is in a non-zero state
1611             if( m_GamePad[iUserIndex].wButtons ||
1612                 m_GamePad[iUserIndex].sThumbLX || m_GamePad[iUserIndex].sThumbLX ||
1613                 m_GamePad[iUserIndex].sThumbRX || m_GamePad[iUserIndex].sThumbRY ||
1614                 m_GamePad[iUserIndex].bLeftTrigger || m_GamePad[iUserIndex].bRightTrigger )
1615             {
1616                 m_GamePadLastActive[iUserIndex] = DXUTGetTime();
1617             }
1618         }
1619 
1620         // Find out which controller was non-zero last
1621         int iMostRecentlyActive = -1;
1622         double fMostRecentlyActiveTime = 0.0f;
1623         for( DWORD iUserIndex=0; iUserIndex<DXUT_MAX_CONTROLLERS; iUserIndex++ )
1624         {
1625             if( m_GamePadLastActive[iUserIndex] > fMostRecentlyActiveTime )
1626             {
1627                 fMostRecentlyActiveTime = m_GamePadLastActive[iUserIndex];
1628                 iMostRecentlyActive = iUserIndex;
1629             }
1630         }
1631 
1632         // Use the most recent non-zero controller if its connected
1633         if( iMostRecentlyActive >= 0 && m_GamePad[iMostRecentlyActive].bConnected )
1634         {
1635             m_vGamePadLeftThumb.x = m_GamePad[iMostRecentlyActive].fThumbLX;
1636             m_vGamePadLeftThumb.y = 0.0f;
1637             m_vGamePadLeftThumb.z = m_GamePad[iMostRecentlyActive].fThumbLY;
1638 
1639             m_vGamePadRightThumb.x = m_GamePad[iMostRecentlyActive].fThumbRX;
1640             m_vGamePadRightThumb.y = 0.0f;
1641             m_vGamePadRightThumb.z = m_GamePad[iMostRecentlyActive].fThumbRY;
1642         }
1643     }
1644 }
1645 
1646 
1647 //--------------------------------------------------------------------------------------
1648 // Figure out the velocity based on keyboard input & drag if any
1649 //--------------------------------------------------------------------------------------
UpdateVelocity(float fElapsedTime)1650 void CBaseCamera::UpdateVelocity( float fElapsedTime )
1651 {
1652     D3DXMATRIX mRotDelta;
1653 
1654     D3DXVECTOR2 vGamePadRightThumb = D3DXVECTOR2(m_vGamePadRightThumb.x, -m_vGamePadRightThumb.z);
1655     m_vRotVelocity = m_vMouseDelta * m_fRotationScaler + vGamePadRightThumb * 0.02f;
1656 
1657     D3DXVECTOR3 vAccel = m_vKeyboardDirection + m_vGamePadLeftThumb;
1658 
1659     // Normalize vector so if moving 2 dirs (left & forward),
1660     // the camera doesn't move faster than if moving in 1 dir
1661     D3DXVec3Normalize( &vAccel, &vAccel );
1662 
1663     // Scale the acceleration vector
1664     vAccel *= m_fMoveScaler;
1665 
1666     if( m_bMovementDrag )
1667     {
1668         // Is there any acceleration this frame?
1669         if( D3DXVec3LengthSq( &vAccel ) > 0 )
1670         {
1671             // If so, then this means the user has pressed a movement key\
1672             // so change the velocity immediately to acceleration
1673             // upon keyboard input.  This isn't normal physics
1674             // but it will give a quick response to keyboard input
1675             m_vVelocity = vAccel;
1676             m_fDragTimer = m_fTotalDragTimeToZero;
1677             m_vVelocityDrag = vAccel / m_fDragTimer;
1678         }
1679         else
1680         {
1681             // If no key being pressed, then slowly decrease velocity to 0
1682             if( m_fDragTimer > 0 )
1683             {
1684                 // Drag until timer is <= 0
1685                 m_vVelocity -= m_vVelocityDrag * fElapsedTime;
1686                 m_fDragTimer -= fElapsedTime;
1687             }
1688             else
1689             {
1690                 // Zero velocity
1691                 m_vVelocity = D3DXVECTOR3(0,0,0);
1692             }
1693         }
1694     }
1695     else
1696     {
1697         // No drag, so immediately change the velocity
1698         m_vVelocity = vAccel;
1699     }
1700 }
1701 
1702 
1703 
1704 
1705 //--------------------------------------------------------------------------------------
1706 // Clamps pV to lie inside m_vMinBoundary & m_vMaxBoundary
1707 //--------------------------------------------------------------------------------------
ConstrainToBoundary(D3DXVECTOR3 * pV)1708 void CBaseCamera::ConstrainToBoundary( D3DXVECTOR3* pV )
1709 {
1710     // Constrain vector to a bounding box
1711     pV->x = __max(pV->x, m_vMinBoundary.x);
1712     pV->y = __max(pV->y, m_vMinBoundary.y);
1713     pV->z = __max(pV->z, m_vMinBoundary.z);
1714 
1715     pV->x = __min(pV->x, m_vMaxBoundary.x);
1716     pV->y = __min(pV->y, m_vMaxBoundary.y);
1717     pV->z = __min(pV->z, m_vMaxBoundary.z);
1718 }
1719 
1720 
1721 
1722 
1723 //--------------------------------------------------------------------------------------
1724 // Maps a windows virtual key to an enum
1725 //--------------------------------------------------------------------------------------
MapKey(UINT nKey)1726 D3DUtil_CameraKeys CBaseCamera::MapKey( UINT nKey )
1727 {
1728     // This could be upgraded to a method that's user-definable but for
1729     // simplicity, we'll use a hardcoded mapping.
1730     switch( nKey )
1731     {
1732         case VK_CONTROL:  return CAM_CONTROLDOWN;
1733         case VK_LEFT:  return CAM_STRAFE_LEFT;
1734         case VK_RIGHT: return CAM_STRAFE_RIGHT;
1735         case VK_UP:    return CAM_MOVE_FORWARD;
1736         case VK_DOWN:  return CAM_MOVE_BACKWARD;
1737         case VK_PRIOR: return CAM_MOVE_UP;        // pgup
1738         case VK_NEXT:  return CAM_MOVE_DOWN;      // pgdn
1739 
1740         case 'A':      return CAM_STRAFE_LEFT;
1741         case 'D':      return CAM_STRAFE_RIGHT;
1742         case 'W':      return CAM_MOVE_FORWARD;
1743         case 'S':      return CAM_MOVE_BACKWARD;
1744         case 'Q':      return CAM_MOVE_DOWN;
1745         case 'E':      return CAM_MOVE_UP;
1746 
1747         case VK_NUMPAD4: return CAM_STRAFE_LEFT;
1748         case VK_NUMPAD6: return CAM_STRAFE_RIGHT;
1749         case VK_NUMPAD8: return CAM_MOVE_FORWARD;
1750         case VK_NUMPAD2: return CAM_MOVE_BACKWARD;
1751         case VK_NUMPAD9: return CAM_MOVE_UP;
1752         case VK_NUMPAD3: return CAM_MOVE_DOWN;
1753 
1754         case VK_HOME:   return CAM_RESET;
1755     }
1756 
1757     return CAM_UNKNOWN;
1758 }
1759 
1760 
1761 
1762 
1763 //--------------------------------------------------------------------------------------
1764 // Reset the camera's position back to the default
1765 //--------------------------------------------------------------------------------------
Reset()1766 VOID CBaseCamera::Reset()
1767 {
1768     SetViewParams( &m_vDefaultEye, &m_vDefaultLookAt );
1769 }
1770 
1771 
1772 
1773 
1774 //--------------------------------------------------------------------------------------
1775 // Constructor
1776 //--------------------------------------------------------------------------------------
CFirstPersonCamera()1777 CFirstPersonCamera::CFirstPersonCamera() :
1778     m_nActiveButtonMask( 0x07 )
1779 {
1780     m_bRotateWithoutButtonDown = false;
1781 }
1782 
1783 
1784 
1785 
1786 //--------------------------------------------------------------------------------------
1787 // Update the view matrix based on user input & elapsed time
1788 //--------------------------------------------------------------------------------------
FrameMove(FLOAT fElapsedTime)1789 VOID CFirstPersonCamera::FrameMove( FLOAT fElapsedTime )
1790 {
1791     if( DXUTGetGlobalTimer()->IsStopped() )
1792         fElapsedTime = 1.0f / DXUTGetFPS();
1793 
1794     if( IsKeyDown(m_aKeys[CAM_RESET]) )
1795         Reset();
1796 
1797     // Get keyboard/mouse/gamepad input
1798     GetInput( m_bEnablePositionMovement, (m_nActiveButtonMask & m_nCurrentButtonMask) || m_bRotateWithoutButtonDown, true, m_bResetCursorAfterMove );
1799 
1800     // Get amount of velocity based on the keyboard input and drag (if any)
1801     UpdateVelocity( fElapsedTime );
1802 
1803     // Simple euler method to calculate position delta
1804     D3DXVECTOR3 vPosDelta = m_vVelocity * fElapsedTime;
1805 
1806     // If rotating the camera
1807     if( (m_nActiveButtonMask & m_nCurrentButtonMask) ||
1808         m_bRotateWithoutButtonDown ||
1809         m_vGamePadRightThumb.x != 0 ||
1810         m_vGamePadRightThumb.z != 0 )
1811     {
1812         // Update the pitch & yaw angle based on mouse movement
1813         float fYawDelta   = m_vRotVelocity.x;
1814         float fPitchDelta = m_vRotVelocity.y;
1815 
1816         // Invert pitch if requested
1817         if( m_bInvertPitch )
1818             fPitchDelta = -fPitchDelta;
1819 
1820         m_fCameraPitchAngle += fPitchDelta;
1821         m_fCameraYawAngle   += fYawDelta;
1822 
1823         // Limit pitch to straight up or straight down
1824         m_fCameraPitchAngle = __max( -D3DX_PI/2.0f,  m_fCameraPitchAngle );
1825         m_fCameraPitchAngle = __min( +D3DX_PI/2.0f,  m_fCameraPitchAngle );
1826     }
1827 
1828     // Make a rotation matrix based on the camera's yaw & pitch
1829     D3DXMATRIX mCameraRot;
1830     D3DXMatrixRotationYawPitchRoll( &mCameraRot, m_fCameraYawAngle, m_fCameraPitchAngle, 0 );
1831 
1832     // Transform vectors based on camera's rotation matrix
1833     D3DXVECTOR3 vWorldUp, vWorldAhead;
1834     D3DXVECTOR3 vLocalUp    = D3DXVECTOR3(0,1,0);
1835     D3DXVECTOR3 vLocalAhead = D3DXVECTOR3(0,0,1);
1836     D3DXVec3TransformCoord( &vWorldUp, &vLocalUp, &mCameraRot );
1837     D3DXVec3TransformCoord( &vWorldAhead, &vLocalAhead, &mCameraRot );
1838 
1839     // Transform the position delta by the camera's rotation
1840     D3DXVECTOR3 vPosDeltaWorld;
1841     if( !m_bEnableYAxisMovement )
1842     {
1843         // If restricting Y movement, do not include pitch
1844         // when transforming position delta vector.
1845         D3DXMatrixRotationYawPitchRoll( &mCameraRot, m_fCameraYawAngle, 0.0f, 0.0f );
1846     }
1847     D3DXVec3TransformCoord( &vPosDeltaWorld, &vPosDelta, &mCameraRot );
1848 
1849     // Move the eye position
1850     m_vEye += vPosDeltaWorld;
1851     if( m_bClipToBoundary )
1852         ConstrainToBoundary( &m_vEye );
1853 
1854     // Update the lookAt position based on the eye position
1855     m_vLookAt = m_vEye + vWorldAhead;
1856 
1857     // Update the view matrix
1858     D3DXMatrixLookAtLH( &m_mView, &m_vEye, &m_vLookAt, &vWorldUp );
1859 
1860     D3DXMatrixInverse( &m_mCameraWorld, NULL, &m_mView );
1861 }
1862 
1863 
1864 //--------------------------------------------------------------------------------------
1865 // Enable or disable each of the mouse buttons for rotation drag.
1866 //--------------------------------------------------------------------------------------
SetRotateButtons(bool bLeft,bool bMiddle,bool bRight,bool bRotateWithoutButtonDown)1867 void CFirstPersonCamera::SetRotateButtons( bool bLeft, bool bMiddle, bool bRight, bool bRotateWithoutButtonDown )
1868 {
1869     m_nActiveButtonMask = ( bLeft ? MOUSE_LEFT_BUTTON : 0 ) |
1870                           ( bMiddle ? MOUSE_MIDDLE_BUTTON : 0 ) |
1871                           ( bRight ? MOUSE_RIGHT_BUTTON : 0 );
1872     m_bRotateWithoutButtonDown = bRotateWithoutButtonDown;
1873 }
1874 
1875 
1876 //--------------------------------------------------------------------------------------
1877 // Constructor
1878 //--------------------------------------------------------------------------------------
CModelViewerCamera()1879 CModelViewerCamera::CModelViewerCamera()
1880 {
1881     D3DXMatrixIdentity( &m_mWorld );
1882     D3DXMatrixIdentity( &m_mModelRot );
1883     D3DXMatrixIdentity( &m_mModelLastRot );
1884     D3DXMatrixIdentity( &m_mCameraRotLast );
1885     m_vModelCenter = D3DXVECTOR3(0,0,0);
1886     m_fRadius    = 5.0f;
1887     m_fDefaultRadius = 5.0f;
1888     m_fMinRadius = 1.0f;
1889     m_fMaxRadius = FLT_MAX;
1890     m_bLimitPitch = false;
1891     m_bEnablePositionMovement = false;
1892     m_bAttachCameraToModel = false;
1893 
1894     m_nRotateModelButtonMask  = MOUSE_LEFT_BUTTON;
1895     m_nZoomButtonMask         = MOUSE_WHEEL;
1896     m_nRotateCameraButtonMask = MOUSE_RIGHT_BUTTON;
1897     m_bDragSinceLastUpdate    = true;
1898 }
1899 
1900 
1901 
1902 
1903 //--------------------------------------------------------------------------------------
1904 // Update the view matrix & the model's world matrix based
1905 //       on user input & elapsed time
1906 //--------------------------------------------------------------------------------------
FrameMove(FLOAT fElapsedTime)1907 VOID CModelViewerCamera::FrameMove( FLOAT fElapsedTime )
1908 {
1909     if( IsKeyDown(m_aKeys[CAM_RESET]) )
1910         Reset();
1911 
1912     // If no dragged has happend since last time FrameMove is called,
1913     // and no camera key is held down, then no need to handle again.
1914     if( !m_bDragSinceLastUpdate && 0 == m_cKeysDown )
1915         return;
1916     m_bDragSinceLastUpdate = false;
1917 
1918     // Get keyboard/mouse/gamepad input
1919     GetInput( m_bEnablePositionMovement, m_nCurrentButtonMask != 0, true, false );
1920 
1921     // Get amount of velocity based on the keyboard input and drag (if any)
1922     UpdateVelocity( fElapsedTime );
1923 
1924     // Simple euler method to calculate position delta
1925     D3DXVECTOR3 vPosDelta = m_vVelocity * fElapsedTime;
1926 
1927     // Change the radius from the camera to the model based on wheel scrolling
1928     if( m_nMouseWheelDelta && m_nZoomButtonMask == MOUSE_WHEEL )
1929         m_fRadius -= m_nMouseWheelDelta * m_fRadius * 0.1f;
1930     m_fRadius = __min( m_fMaxRadius, m_fRadius );
1931     m_fRadius = __max( m_fMinRadius, m_fRadius );
1932     m_nMouseWheelDelta = 0;
1933 
1934     // Get the inverse of the arcball's rotation matrix
1935     D3DXMATRIX mCameraRot;
1936     D3DXMatrixInverse( &mCameraRot, NULL, m_ViewArcBall.GetRotationMatrix() );
1937 
1938     // Transform vectors based on camera's rotation matrix
1939     D3DXVECTOR3 vWorldUp, vWorldAhead;
1940     D3DXVECTOR3 vLocalUp    = D3DXVECTOR3(0,1,0);
1941     D3DXVECTOR3 vLocalAhead = D3DXVECTOR3(0,0,1);
1942     D3DXVec3TransformCoord( &vWorldUp, &vLocalUp, &mCameraRot );
1943     D3DXVec3TransformCoord( &vWorldAhead, &vLocalAhead, &mCameraRot );
1944 
1945     // Transform the position delta by the camera's rotation
1946     D3DXVECTOR3 vPosDeltaWorld;
1947     D3DXVec3TransformCoord( &vPosDeltaWorld, &vPosDelta, &mCameraRot );
1948 
1949     // Move the lookAt position
1950     m_vLookAt += vPosDeltaWorld;
1951     if( m_bClipToBoundary )
1952         ConstrainToBoundary( &m_vLookAt );
1953 
1954     // Update the eye point based on a radius away from the lookAt position
1955     m_vEye = m_vLookAt - vWorldAhead * m_fRadius;
1956 
1957     // Update the view matrix
1958     D3DXMatrixLookAtLH( &m_mView, &m_vEye, &m_vLookAt, &vWorldUp );
1959 
1960     D3DXMATRIX mInvView;
1961     D3DXMatrixInverse( &mInvView, NULL, &m_mView );
1962     mInvView._41 = mInvView._42 = mInvView._43 = 0;
1963 
1964     D3DXMATRIX mModelLastRotInv;
1965     D3DXMatrixInverse(&mModelLastRotInv, NULL, &m_mModelLastRot);
1966 
1967     // Accumulate the delta of the arcball's rotation in view space.
1968     // Note that per-frame delta rotations could be problematic over long periods of time.
1969     D3DXMATRIX mModelRot;
1970     mModelRot = *m_WorldArcBall.GetRotationMatrix();
1971     m_mModelRot *= m_mView * mModelLastRotInv * mModelRot * mInvView;
1972 
1973     if( m_ViewArcBall.IsBeingDragged() && m_bAttachCameraToModel && !IsKeyDown(m_aKeys[CAM_CONTROLDOWN]) )
1974     {
1975         // Attach camera to model by inverse of the model rotation
1976         D3DXMATRIX mCameraLastRotInv;
1977         D3DXMatrixInverse(&mCameraLastRotInv, NULL, &m_mCameraRotLast);
1978         D3DXMATRIX mCameraRotDelta = mCameraLastRotInv * mCameraRot; // local to world matrix
1979         m_mModelRot *= mCameraRotDelta;
1980     }
1981     m_mCameraRotLast = mCameraRot;
1982 
1983     m_mModelLastRot = mModelRot;
1984 
1985     // Since we're accumulating delta rotations, we need to orthonormalize
1986     // the matrix to prevent eventual matrix skew
1987     D3DXVECTOR3* pXBasis = (D3DXVECTOR3*) &m_mModelRot._11;
1988     D3DXVECTOR3* pYBasis = (D3DXVECTOR3*) &m_mModelRot._21;
1989     D3DXVECTOR3* pZBasis = (D3DXVECTOR3*) &m_mModelRot._31;
1990     D3DXVec3Normalize( pXBasis, pXBasis );
1991     D3DXVec3Cross( pYBasis, pZBasis, pXBasis );
1992     D3DXVec3Normalize( pYBasis, pYBasis );
1993     D3DXVec3Cross( pZBasis, pXBasis, pYBasis );
1994 
1995     // Translate the rotation matrix to the same position as the lookAt position
1996     m_mModelRot._41 = m_vLookAt.x;
1997     m_mModelRot._42 = m_vLookAt.y;
1998     m_mModelRot._43 = m_vLookAt.z;
1999 
2000     // Translate world matrix so its at the center of the model
2001     D3DXMATRIX mTrans;
2002     D3DXMatrixTranslation( &mTrans, -m_vModelCenter.x, -m_vModelCenter.y, -m_vModelCenter.z );
2003     m_mWorld = mTrans * m_mModelRot;
2004 }
2005 
2006 
SetDragRect(RECT & rc)2007 void CModelViewerCamera::SetDragRect( RECT &rc )
2008 {
2009     CBaseCamera::SetDragRect( rc );
2010 
2011     m_WorldArcBall.SetOffset( rc.left, rc.top );
2012     m_ViewArcBall.SetOffset( rc.left, rc.top );
2013     SetWindow( rc.right - rc.left, rc.bottom - rc.top );
2014 }
2015 
2016 
2017 //--------------------------------------------------------------------------------------
2018 // Reset the camera's position back to the default
2019 //--------------------------------------------------------------------------------------
Reset()2020 VOID CModelViewerCamera::Reset()
2021 {
2022     CBaseCamera::Reset();
2023 
2024     D3DXMatrixIdentity( &m_mWorld );
2025     D3DXMatrixIdentity( &m_mModelRot );
2026     D3DXMatrixIdentity( &m_mModelLastRot );
2027     D3DXMatrixIdentity( &m_mCameraRotLast );
2028 
2029     m_fRadius = m_fDefaultRadius;
2030     m_WorldArcBall.Reset();
2031     m_ViewArcBall.Reset();
2032 }
2033 
2034 
2035 //--------------------------------------------------------------------------------------
2036 // Override for setting the view parameters
2037 //--------------------------------------------------------------------------------------
SetViewParams(D3DXVECTOR3 * pvEyePt,D3DXVECTOR3 * pvLookatPt)2038 void CModelViewerCamera::SetViewParams( D3DXVECTOR3* pvEyePt, D3DXVECTOR3* pvLookatPt )
2039 {
2040     CBaseCamera::SetViewParams( pvEyePt, pvLookatPt );
2041 
2042     // Propogate changes to the member arcball
2043     D3DXQUATERNION quat;
2044     D3DXMATRIXA16 mRotation;
2045     D3DXVECTOR3 vUp(0,1,0);
2046     D3DXMatrixLookAtLH( &mRotation, pvEyePt, pvLookatPt, &vUp );
2047     D3DXQuaternionRotationMatrix( &quat, &mRotation );
2048     m_ViewArcBall.SetQuatNow( quat );
2049 
2050     // Set the radius according to the distance
2051     D3DXVECTOR3 vEyeToPoint;
2052     D3DXVec3Subtract( &vEyeToPoint, pvLookatPt, pvEyePt );
2053     SetRadius( D3DXVec3Length( &vEyeToPoint ) );
2054 
2055     // View information changed. FrameMove should be called.
2056     m_bDragSinceLastUpdate = true;
2057 }
2058 
2059 
2060 
2061 //--------------------------------------------------------------------------------------
2062 // Call this from your message proc so this class can handle window messages
2063 //--------------------------------------------------------------------------------------
HandleMessages(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)2064 LRESULT CModelViewerCamera::HandleMessages( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
2065 {
2066     CBaseCamera::HandleMessages( hWnd, uMsg, wParam, lParam );
2067 
2068     if( ( (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK ) && m_nRotateModelButtonMask & MOUSE_LEFT_BUTTON) ||
2069         ( (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONDBLCLK ) && m_nRotateModelButtonMask & MOUSE_MIDDLE_BUTTON) ||
2070         ( (uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONDBLCLK ) && m_nRotateModelButtonMask & MOUSE_RIGHT_BUTTON) )
2071     {
2072         int iMouseX = (short)LOWORD(lParam);
2073         int iMouseY = (short)HIWORD(lParam);
2074         m_WorldArcBall.OnBegin( iMouseX, iMouseY );
2075     }
2076 
2077     if( ( (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK ) && m_nRotateCameraButtonMask & MOUSE_LEFT_BUTTON) ||
2078         ( (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONDBLCLK ) && m_nRotateCameraButtonMask & MOUSE_MIDDLE_BUTTON) ||
2079         ( (uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONDBLCLK ) && m_nRotateCameraButtonMask & MOUSE_RIGHT_BUTTON) )
2080     {
2081         int iMouseX = (short)LOWORD(lParam);
2082         int iMouseY = (short)HIWORD(lParam);
2083         m_ViewArcBall.OnBegin( iMouseX, iMouseY );
2084     }
2085 
2086     if( uMsg == WM_MOUSEMOVE )
2087     {
2088         int iMouseX = (short)LOWORD(lParam);
2089         int iMouseY = (short)HIWORD(lParam);
2090         m_WorldArcBall.OnMove( iMouseX, iMouseY );
2091         m_ViewArcBall.OnMove( iMouseX, iMouseY );
2092     }
2093 
2094     if( (uMsg == WM_LBUTTONUP && m_nRotateModelButtonMask & MOUSE_LEFT_BUTTON) ||
2095         (uMsg == WM_MBUTTONUP && m_nRotateModelButtonMask & MOUSE_MIDDLE_BUTTON) ||
2096         (uMsg == WM_RBUTTONUP && m_nRotateModelButtonMask & MOUSE_RIGHT_BUTTON) )
2097     {
2098         m_WorldArcBall.OnEnd();
2099     }
2100 
2101     if( (uMsg == WM_LBUTTONUP && m_nRotateCameraButtonMask & MOUSE_LEFT_BUTTON) ||
2102         (uMsg == WM_MBUTTONUP && m_nRotateCameraButtonMask & MOUSE_MIDDLE_BUTTON) ||
2103         (uMsg == WM_RBUTTONUP && m_nRotateCameraButtonMask & MOUSE_RIGHT_BUTTON) )
2104     {
2105         m_ViewArcBall.OnEnd();
2106     }
2107 
2108     if( uMsg == WM_CAPTURECHANGED )
2109     {
2110         if( (HWND)lParam != hWnd )
2111         {
2112             if( (m_nRotateModelButtonMask & MOUSE_LEFT_BUTTON) ||
2113                 (m_nRotateModelButtonMask & MOUSE_MIDDLE_BUTTON) ||
2114                 (m_nRotateModelButtonMask & MOUSE_RIGHT_BUTTON) )
2115             {
2116                 m_WorldArcBall.OnEnd();
2117             }
2118 
2119             if( (m_nRotateCameraButtonMask & MOUSE_LEFT_BUTTON) ||
2120                 (m_nRotateCameraButtonMask & MOUSE_MIDDLE_BUTTON) ||
2121                 (m_nRotateCameraButtonMask & MOUSE_RIGHT_BUTTON) )
2122             {
2123                 m_ViewArcBall.OnEnd();
2124             }
2125         }
2126     }
2127 
2128     if( uMsg == WM_LBUTTONDOWN ||
2129         uMsg == WM_LBUTTONDBLCLK ||
2130         uMsg == WM_MBUTTONDOWN ||
2131         uMsg == WM_MBUTTONDBLCLK ||
2132         uMsg == WM_RBUTTONDOWN ||
2133         uMsg == WM_RBUTTONDBLCLK ||
2134         uMsg == WM_LBUTTONUP ||
2135         uMsg == WM_MBUTTONUP ||
2136         uMsg == WM_RBUTTONUP ||
2137         uMsg == WM_MOUSEWHEEL ||
2138         uMsg == WM_MOUSEMOVE )
2139     {
2140         m_bDragSinceLastUpdate = true;
2141     }
2142 
2143     return FALSE;
2144 }
2145 
2146 
2147 
2148 
2149 //--------------------------------------------------------------------------------------
2150 // Desc: Returns a view matrix for rendering to a face of a cubemap.
2151 //--------------------------------------------------------------------------------------
DXUTGetCubeMapViewMatrix(DWORD dwFace)2152 D3DXMATRIX DXUTGetCubeMapViewMatrix( DWORD dwFace )
2153 {
2154     D3DXVECTOR3 vEyePt   = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
2155     D3DXVECTOR3 vLookDir;
2156     D3DXVECTOR3 vUpDir;
2157 
2158     switch( dwFace )
2159     {
2160         case D3DCUBEMAP_FACE_POSITIVE_X:
2161             vLookDir = D3DXVECTOR3( 1.0f, 0.0f, 0.0f );
2162             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
2163             break;
2164         case D3DCUBEMAP_FACE_NEGATIVE_X:
2165             vLookDir = D3DXVECTOR3(-1.0f, 0.0f, 0.0f );
2166             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
2167             break;
2168         case D3DCUBEMAP_FACE_POSITIVE_Y:
2169             vLookDir = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
2170             vUpDir   = D3DXVECTOR3( 0.0f, 0.0f,-1.0f );
2171             break;
2172         case D3DCUBEMAP_FACE_NEGATIVE_Y:
2173             vLookDir = D3DXVECTOR3( 0.0f,-1.0f, 0.0f );
2174             vUpDir   = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
2175             break;
2176         case D3DCUBEMAP_FACE_POSITIVE_Z:
2177             vLookDir = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
2178             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
2179             break;
2180         case D3DCUBEMAP_FACE_NEGATIVE_Z:
2181             vLookDir = D3DXVECTOR3( 0.0f, 0.0f,-1.0f );
2182             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
2183             break;
2184     }
2185 
2186     // Set the view transform for this cubemap surface
2187     D3DXMATRIXA16 mView;
2188     D3DXMatrixLookAtLH( &mView, &vEyePt, &vLookDir, &vUpDir );
2189     return mView;
2190 }
2191 
2192 
2193 //--------------------------------------------------------------------------------------
2194 // Returns the string for the given D3DFORMAT.
2195 //--------------------------------------------------------------------------------------
DXUTD3DFormatToString(D3DFORMAT format,bool bWithPrefix)2196 LPCWSTR DXUTD3DFormatToString( D3DFORMAT format, bool bWithPrefix )
2197 {
2198     WCHAR* pstr = NULL;
2199     switch( format )
2200     {
2201     case D3DFMT_UNKNOWN:         pstr = L"D3DFMT_UNKNOWN"; break;
2202     case D3DFMT_R8G8B8:          pstr = L"D3DFMT_R8G8B8"; break;
2203     case D3DFMT_A8R8G8B8:        pstr = L"D3DFMT_A8R8G8B8"; break;
2204     case D3DFMT_X8R8G8B8:        pstr = L"D3DFMT_X8R8G8B8"; break;
2205     case D3DFMT_R5G6B5:          pstr = L"D3DFMT_R5G6B5"; break;
2206     case D3DFMT_X1R5G5B5:        pstr = L"D3DFMT_X1R5G5B5"; break;
2207     case D3DFMT_A1R5G5B5:        pstr = L"D3DFMT_A1R5G5B5"; break;
2208     case D3DFMT_A4R4G4B4:        pstr = L"D3DFMT_A4R4G4B4"; break;
2209     case D3DFMT_R3G3B2:          pstr = L"D3DFMT_R3G3B2"; break;
2210     case D3DFMT_A8:              pstr = L"D3DFMT_A8"; break;
2211     case D3DFMT_A8R3G3B2:        pstr = L"D3DFMT_A8R3G3B2"; break;
2212     case D3DFMT_X4R4G4B4:        pstr = L"D3DFMT_X4R4G4B4"; break;
2213     case D3DFMT_A2B10G10R10:     pstr = L"D3DFMT_A2B10G10R10"; break;
2214     case D3DFMT_A8B8G8R8:        pstr = L"D3DFMT_A8B8G8R8"; break;
2215     case D3DFMT_X8B8G8R8:        pstr = L"D3DFMT_X8B8G8R8"; break;
2216     case D3DFMT_G16R16:          pstr = L"D3DFMT_G16R16"; break;
2217     case D3DFMT_A2R10G10B10:     pstr = L"D3DFMT_A2R10G10B10"; break;
2218     case D3DFMT_A16B16G16R16:    pstr = L"D3DFMT_A16B16G16R16"; break;
2219     case D3DFMT_A8P8:            pstr = L"D3DFMT_A8P8"; break;
2220     case D3DFMT_P8:              pstr = L"D3DFMT_P8"; break;
2221     case D3DFMT_L8:              pstr = L"D3DFMT_L8"; break;
2222     case D3DFMT_A8L8:            pstr = L"D3DFMT_A8L8"; break;
2223     case D3DFMT_A4L4:            pstr = L"D3DFMT_A4L4"; break;
2224     case D3DFMT_V8U8:            pstr = L"D3DFMT_V8U8"; break;
2225     case D3DFMT_L6V5U5:          pstr = L"D3DFMT_L6V5U5"; break;
2226     case D3DFMT_X8L8V8U8:        pstr = L"D3DFMT_X8L8V8U8"; break;
2227     case D3DFMT_Q8W8V8U8:        pstr = L"D3DFMT_Q8W8V8U8"; break;
2228     case D3DFMT_V16U16:          pstr = L"D3DFMT_V16U16"; break;
2229     case D3DFMT_A2W10V10U10:     pstr = L"D3DFMT_A2W10V10U10"; break;
2230     case D3DFMT_UYVY:            pstr = L"D3DFMT_UYVY"; break;
2231     case D3DFMT_YUY2:            pstr = L"D3DFMT_YUY2"; break;
2232     case D3DFMT_DXT1:            pstr = L"D3DFMT_DXT1"; break;
2233     case D3DFMT_DXT2:            pstr = L"D3DFMT_DXT2"; break;
2234     case D3DFMT_DXT3:            pstr = L"D3DFMT_DXT3"; break;
2235     case D3DFMT_DXT4:            pstr = L"D3DFMT_DXT4"; break;
2236     case D3DFMT_DXT5:            pstr = L"D3DFMT_DXT5"; break;
2237     case D3DFMT_D16_LOCKABLE:    pstr = L"D3DFMT_D16_LOCKABLE"; break;
2238     case D3DFMT_D32:             pstr = L"D3DFMT_D32"; break;
2239     case D3DFMT_D15S1:           pstr = L"D3DFMT_D15S1"; break;
2240     case D3DFMT_D24S8:           pstr = L"D3DFMT_D24S8"; break;
2241     case D3DFMT_D24X8:           pstr = L"D3DFMT_D24X8"; break;
2242     case D3DFMT_D24X4S4:         pstr = L"D3DFMT_D24X4S4"; break;
2243     case D3DFMT_D16:             pstr = L"D3DFMT_D16"; break;
2244     case D3DFMT_L16:             pstr = L"D3DFMT_L16"; break;
2245     case D3DFMT_VERTEXDATA:      pstr = L"D3DFMT_VERTEXDATA"; break;
2246     case D3DFMT_INDEX16:         pstr = L"D3DFMT_INDEX16"; break;
2247     case D3DFMT_INDEX32:         pstr = L"D3DFMT_INDEX32"; break;
2248     case D3DFMT_Q16W16V16U16:    pstr = L"D3DFMT_Q16W16V16U16"; break;
2249     case D3DFMT_MULTI2_ARGB8:    pstr = L"D3DFMT_MULTI2_ARGB8"; break;
2250     case D3DFMT_R16F:            pstr = L"D3DFMT_R16F"; break;
2251     case D3DFMT_G16R16F:         pstr = L"D3DFMT_G16R16F"; break;
2252     case D3DFMT_A16B16G16R16F:   pstr = L"D3DFMT_A16B16G16R16F"; break;
2253     case D3DFMT_R32F:            pstr = L"D3DFMT_R32F"; break;
2254     case D3DFMT_G32R32F:         pstr = L"D3DFMT_G32R32F"; break;
2255     case D3DFMT_A32B32G32R32F:   pstr = L"D3DFMT_A32B32G32R32F"; break;
2256     case D3DFMT_CxV8U8:          pstr = L"D3DFMT_CxV8U8"; break;
2257     default:                     pstr = L"Unknown format"; break;
2258     }
2259     if( bWithPrefix || wcsstr( pstr, L"D3DFMT_" )== NULL )
2260         return pstr;
2261     else
2262         return pstr + lstrlen( L"D3DFMT_" );
2263 }
2264 
2265 
2266 
2267 //--------------------------------------------------------------------------------------
2268 // Outputs to the debug stream a formatted Unicode string with a variable-argument list.
2269 //--------------------------------------------------------------------------------------
DXUTOutputDebugStringW(LPCWSTR strMsg,...)2270 VOID DXUTOutputDebugStringW( LPCWSTR strMsg, ... )
2271 {
2272 #if defined(DEBUG) || defined(_DEBUG)
2273     WCHAR strBuffer[512];
2274 
2275     va_list args;
2276     va_start(args, strMsg);
2277     StringCchVPrintfW( strBuffer, 512, strMsg, args );
2278     strBuffer[511] = L'\0';
2279     va_end(args);
2280 
2281     OutputDebugString( strBuffer );
2282 #else
2283     UNREFERENCED_PARAMETER(strMsg);
2284 #endif
2285 }
2286 
2287 
2288 //--------------------------------------------------------------------------------------
2289 // Outputs to the debug stream a formatted MBCS string with a variable-argument list.
2290 //--------------------------------------------------------------------------------------
DXUTOutputDebugStringA(LPCSTR strMsg,...)2291 VOID DXUTOutputDebugStringA( LPCSTR strMsg, ... )
2292 {
2293 #if defined(DEBUG) || defined(_DEBUG)
2294     CHAR strBuffer[512];
2295 
2296     va_list args;
2297     va_start(args, strMsg);
2298     StringCchVPrintfA( strBuffer, 512, strMsg, args );
2299     strBuffer[511] = '\0';
2300     va_end(args);
2301 
2302     OutputDebugStringA( strBuffer );
2303 #else
2304     UNREFERENCED_PARAMETER(strMsg);
2305 #endif
2306 }
2307 
2308 
2309 //--------------------------------------------------------------------------------------
CDXUTLineManager()2310 CDXUTLineManager::CDXUTLineManager()
2311 {
2312     m_pd3dDevice = NULL;
2313     m_pD3DXLine = NULL;
2314 }
2315 
2316 
2317 //--------------------------------------------------------------------------------------
~CDXUTLineManager()2318 CDXUTLineManager::~CDXUTLineManager()
2319 {
2320     OnDeletedDevice();
2321 }
2322 
2323 
2324 //--------------------------------------------------------------------------------------
OnCreatedDevice(IDirect3DDevice9 * pd3dDevice)2325 HRESULT CDXUTLineManager::OnCreatedDevice( IDirect3DDevice9* pd3dDevice )
2326 {
2327     m_pd3dDevice = pd3dDevice;
2328 
2329     HRESULT hr;
2330     hr = D3DXCreateLine( m_pd3dDevice, &m_pD3DXLine );
2331     if( FAILED(hr) )
2332         return hr;
2333 
2334     return S_OK;
2335 }
2336 
2337 
2338 //--------------------------------------------------------------------------------------
OnResetDevice()2339 HRESULT CDXUTLineManager::OnResetDevice()
2340 {
2341     if( m_pD3DXLine )
2342         m_pD3DXLine->OnResetDevice();
2343 
2344     return S_OK;
2345 }
2346 
2347 
2348 //--------------------------------------------------------------------------------------
OnRender()2349 HRESULT CDXUTLineManager::OnRender()
2350 {
2351     HRESULT hr;
2352     if( NULL == m_pD3DXLine )
2353         return E_INVALIDARG;
2354 
2355     bool bDrawingHasBegun = false;
2356     float fLastWidth = 0.0f;
2357     bool bLastAntiAlias = false;
2358 
2359     for( int i=0; i<m_LinesList.GetSize(); i++ )
2360     {
2361         LINE_NODE* pLineNode = m_LinesList.GetAt(i);
2362         if( pLineNode )
2363         {
2364             if( !bDrawingHasBegun ||
2365                 fLastWidth != pLineNode->fWidth ||
2366                 bLastAntiAlias != pLineNode->bAntiAlias )
2367             {
2368                 if( bDrawingHasBegun )
2369                 {
2370                     hr = m_pD3DXLine->End();
2371                     if( FAILED(hr) )
2372                         return hr;
2373                 }
2374 
2375                 m_pD3DXLine->SetWidth( pLineNode->fWidth );
2376                 m_pD3DXLine->SetAntialias( pLineNode->bAntiAlias );
2377 
2378                 fLastWidth = pLineNode->fWidth;
2379                 bLastAntiAlias = pLineNode->bAntiAlias;
2380 
2381                 hr = m_pD3DXLine->Begin();
2382                 if( FAILED(hr) )
2383                     return hr;
2384                 bDrawingHasBegun = true;
2385             }
2386 
2387             hr = m_pD3DXLine->Draw( pLineNode->pVertexList, pLineNode->dwVertexListCount, pLineNode->Color );
2388             if( FAILED(hr) )
2389                 return hr;
2390         }
2391     }
2392 
2393     if( bDrawingHasBegun )
2394     {
2395         hr = m_pD3DXLine->End();
2396         if( FAILED(hr) )
2397             return hr;
2398     }
2399 
2400     return S_OK;
2401 }
2402 
2403 
2404 //--------------------------------------------------------------------------------------
OnLostDevice()2405 HRESULT CDXUTLineManager::OnLostDevice()
2406 {
2407     if( m_pD3DXLine )
2408         m_pD3DXLine->OnLostDevice();
2409 
2410     return S_OK;
2411 }
2412 
2413 
2414 //--------------------------------------------------------------------------------------
OnDeletedDevice()2415 HRESULT CDXUTLineManager::OnDeletedDevice()
2416 {
2417     RemoveAllLines();
2418     SAFE_RELEASE( m_pD3DXLine );
2419 
2420     return S_OK;
2421 }
2422 
2423 
2424 //--------------------------------------------------------------------------------------
AddLine(int * pnLineID,D3DXVECTOR2 * pVertexList,DWORD dwVertexListCount,D3DCOLOR Color,float fWidth,float fScaleRatio,bool bAntiAlias)2425 HRESULT CDXUTLineManager::AddLine( int* pnLineID, D3DXVECTOR2* pVertexList, DWORD dwVertexListCount, D3DCOLOR Color, float fWidth, float fScaleRatio, bool bAntiAlias )
2426 {
2427     if( pVertexList == NULL || dwVertexListCount == 0 )
2428         return E_INVALIDARG;
2429 
2430     LINE_NODE* pLineNode = new LINE_NODE;
2431     if( pLineNode == NULL )
2432         return E_OUTOFMEMORY;
2433     ZeroMemory( pLineNode, sizeof(LINE_NODE) );
2434 
2435     pLineNode->nLineID = m_LinesList.GetSize();
2436     pLineNode->Color = Color;
2437     pLineNode->fWidth = fWidth;
2438     pLineNode->bAntiAlias = bAntiAlias;
2439     pLineNode->dwVertexListCount = dwVertexListCount;
2440 
2441     if( pnLineID )
2442         *pnLineID = pLineNode->nLineID;
2443 
2444     pLineNode->pVertexList = new D3DXVECTOR2[dwVertexListCount];
2445     if( pLineNode->pVertexList == NULL )
2446     {
2447         delete pLineNode;
2448         return E_OUTOFMEMORY;
2449     }
2450     for( DWORD i=0; i<dwVertexListCount; i++ )
2451     {
2452         pLineNode->pVertexList[i] = pVertexList[i] * fScaleRatio;
2453     }
2454 
2455     m_LinesList.Add( pLineNode );
2456 
2457     return S_OK;
2458 }
2459 
2460 
2461 //--------------------------------------------------------------------------------------
AddRect(int * pnLineID,RECT rc,D3DCOLOR Color,float fWidth,float fScaleRatio,bool bAntiAlias)2462 HRESULT CDXUTLineManager::AddRect( int* pnLineID, RECT rc, D3DCOLOR Color, float fWidth, float fScaleRatio, bool bAntiAlias )
2463 {
2464     if( fWidth > 2.0f )
2465     {
2466         D3DXVECTOR2 vertexList[8];
2467 
2468         vertexList[0].x = (float)rc.left;
2469         vertexList[0].y = (float)rc.top - (fWidth/2.0f);
2470 
2471         vertexList[1].x = (float)rc.left;
2472         vertexList[1].y = (float)rc.bottom + (fWidth/2.0f);
2473 
2474         vertexList[2].x = (float)rc.left;
2475         vertexList[2].y = (float)rc.bottom - 0.5f;
2476 
2477         vertexList[3].x = (float)rc.right;
2478         vertexList[3].y = (float)rc.bottom - 0.5f;
2479 
2480         vertexList[4].x = (float)rc.right;
2481         vertexList[4].y = (float)rc.bottom + (fWidth/2.0f);
2482 
2483         vertexList[5].x = (float)rc.right;
2484         vertexList[5].y = (float)rc.top - (fWidth/2.0f);
2485 
2486         vertexList[6].x = (float)rc.right;
2487         vertexList[6].y = (float)rc.top;
2488 
2489         vertexList[7].x = (float)rc.left;
2490         vertexList[7].y = (float)rc.top;
2491 
2492         return AddLine( pnLineID, vertexList, 8, Color, fWidth, fScaleRatio, bAntiAlias );
2493     }
2494     else
2495     {
2496         D3DXVECTOR2 vertexList[5];
2497         vertexList[0].x = (float)rc.left;
2498         vertexList[0].y = (float)rc.top;
2499 
2500         vertexList[1].x = (float)rc.left;
2501         vertexList[1].y = (float)rc.bottom;
2502 
2503         vertexList[2].x = (float)rc.right;
2504         vertexList[2].y = (float)rc.bottom;
2505 
2506         vertexList[3].x = (float)rc.right;
2507         vertexList[3].y = (float)rc.top;
2508 
2509         vertexList[4].x = (float)rc.left;
2510         vertexList[4].y = (float)rc.top;
2511 
2512         return AddLine( pnLineID, vertexList, 5, Color, fWidth, fScaleRatio, bAntiAlias );
2513     }
2514 }
2515 
2516 
2517 
2518 //--------------------------------------------------------------------------------------
RemoveLine(int nLineID)2519 HRESULT CDXUTLineManager::RemoveLine( int nLineID )
2520 {
2521     for( int i=0; i<m_LinesList.GetSize(); i++ )
2522     {
2523         LINE_NODE* pLineNode = m_LinesList.GetAt(i);
2524         if( pLineNode && pLineNode->nLineID == nLineID )
2525         {
2526             SAFE_DELETE_ARRAY( pLineNode->pVertexList );
2527             delete pLineNode;
2528             m_LinesList.SetAt(i, NULL);
2529         }
2530     }
2531 
2532     return S_OK;
2533 }
2534 
2535 
2536 //--------------------------------------------------------------------------------------
RemoveAllLines()2537 HRESULT CDXUTLineManager::RemoveAllLines()
2538 {
2539     for( int i=0; i<m_LinesList.GetSize(); i++ )
2540     {
2541         LINE_NODE* pLineNode = m_LinesList.GetAt(i);
2542         if( pLineNode )
2543         {
2544             SAFE_DELETE_ARRAY( pLineNode->pVertexList );
2545             delete pLineNode;
2546         }
2547     }
2548     m_LinesList.RemoveAll();
2549 
2550     return S_OK;
2551 }
2552 
2553 
2554 //--------------------------------------------------------------------------------------
CDXUTTextHelper(ID3DXFont * pFont,ID3DXSprite * pSprite,int nLineHeight)2555 CDXUTTextHelper::CDXUTTextHelper( ID3DXFont* pFont, ID3DXSprite* pSprite, int nLineHeight )
2556 {
2557     m_pFont = pFont;
2558     m_pSprite = pSprite;
2559     m_clr = D3DXCOLOR(1,1,1,1);
2560     m_pt.x = 0;
2561     m_pt.y = 0;
2562     m_nLineHeight = nLineHeight;
2563 }
2564 
2565 
2566 //--------------------------------------------------------------------------------------
DrawFormattedTextLine(const WCHAR * strMsg,...)2567 HRESULT CDXUTTextHelper::DrawFormattedTextLine( const WCHAR* strMsg, ... )
2568 {
2569     WCHAR strBuffer[512];
2570 
2571     va_list args;
2572     va_start(args, strMsg);
2573     StringCchVPrintf( strBuffer, 512, strMsg, args );
2574     strBuffer[511] = L'\0';
2575     va_end(args);
2576 
2577     return DrawTextLine( strBuffer );
2578 }
2579 
2580 
2581 //--------------------------------------------------------------------------------------
DrawTextLine(const WCHAR * strMsg)2582 HRESULT CDXUTTextHelper::DrawTextLine( const WCHAR* strMsg )
2583 {
2584     if( NULL == m_pFont )
2585         return DXUT_ERR_MSGBOX( L"DrawTextLine", E_INVALIDARG );
2586 
2587     HRESULT hr;
2588     RECT rc;
2589     SetRect( &rc, m_pt.x, m_pt.y, 0, 0 );
2590     hr = m_pFont->DrawText( m_pSprite, strMsg, -1, &rc, DT_NOCLIP, m_clr );
2591     if( FAILED(hr) )
2592         return DXTRACE_ERR_MSGBOX( L"DrawText", hr );
2593 
2594     m_pt.y += m_nLineHeight;
2595 
2596     return S_OK;
2597 }
2598 
2599 
DrawFormattedTextLine(RECT & rc,DWORD dwFlags,const WCHAR * strMsg,...)2600 HRESULT CDXUTTextHelper::DrawFormattedTextLine( RECT &rc, DWORD dwFlags, const WCHAR* strMsg, ... )
2601 {
2602     WCHAR strBuffer[512];
2603 
2604     va_list args;
2605     va_start(args, strMsg);
2606     StringCchVPrintf( strBuffer, 512, strMsg, args );
2607     strBuffer[511] = L'\0';
2608     va_end(args);
2609 
2610     return DrawTextLine( rc, dwFlags, strBuffer );
2611 }
2612 
2613 
DrawTextLine(RECT & rc,DWORD dwFlags,const WCHAR * strMsg)2614 HRESULT CDXUTTextHelper::DrawTextLine( RECT &rc, DWORD dwFlags, const WCHAR* strMsg )
2615 {
2616     if( NULL == m_pFont )
2617         return DXUT_ERR_MSGBOX( L"DrawTextLine", E_INVALIDARG );
2618 
2619     HRESULT hr;
2620     hr = m_pFont->DrawText( m_pSprite, strMsg, -1, &rc, dwFlags, m_clr );
2621     if( FAILED(hr) )
2622         return DXTRACE_ERR_MSGBOX( L"DrawText", hr );
2623 
2624     m_pt.y += m_nLineHeight;
2625 
2626     return S_OK;
2627 }
2628 
2629 
2630 //--------------------------------------------------------------------------------------
Begin()2631 void CDXUTTextHelper::Begin()
2632 {
2633     if( m_pSprite )
2634         m_pSprite->Begin( D3DXSPRITE_ALPHABLEND | D3DXSPRITE_SORT_TEXTURE );
2635 }
End()2636 void CDXUTTextHelper::End()
2637 {
2638     if( m_pSprite )
2639         m_pSprite->End();
2640 }
2641 
2642 
2643 //--------------------------------------------------------------------------------------
2644 IDirect3DDevice9* CDXUTDirectionWidget::s_pd3dDevice = NULL;
2645 ID3DXEffect*      CDXUTDirectionWidget::s_pEffect = NULL;
2646 ID3DXMesh*        CDXUTDirectionWidget::s_pMesh = NULL;
2647 
2648 
2649 //--------------------------------------------------------------------------------------
CDXUTDirectionWidget()2650 CDXUTDirectionWidget::CDXUTDirectionWidget()
2651 {
2652     m_fRadius = 1.0f;
2653     m_vDefaultDir = D3DXVECTOR3(0,1,0);
2654     m_vCurrentDir = m_vDefaultDir;
2655     m_nRotateMask = MOUSE_RIGHT_BUTTON;
2656 
2657     D3DXMatrixIdentity( &m_mView );
2658     D3DXMatrixIdentity( &m_mRot );
2659     D3DXMatrixIdentity( &m_mRotSnapshot );
2660 }
2661 
2662 
2663 //--------------------------------------------------------------------------------------
StaticOnCreateDevice(IDirect3DDevice9 * pd3dDevice)2664 HRESULT CDXUTDirectionWidget::StaticOnCreateDevice( IDirect3DDevice9* pd3dDevice )
2665 {
2666     HRESULT hr;
2667 
2668     s_pd3dDevice = pd3dDevice;
2669 
2670     const char* g_strBuffer =
2671     "float4 g_MaterialDiffuseColor;      // Material's diffuse color\r\n"
2672     "float3 g_LightDir;                  // Light's direction in world space\r\n"
2673     "float4x4 g_mWorld;                  // World matrix for object\r\n"
2674     "float4x4 g_mWorldViewProjection;    // World * View * Projection matrix\r\n"
2675     "\r\n"
2676     "struct VS_OUTPUT\r\n"
2677     "{\r\n"
2678     "    float4 Position   : POSITION;   // vertex position\r\n"
2679     "    float4 Diffuse    : COLOR0;     // vertex diffuse color\r\n"
2680     "};\r\n"
2681     "\r\n"
2682     "VS_OUTPUT RenderWith1LightNoTextureVS( float4 vPos : POSITION,\r\n"
2683     "                                       float3 vNormal : NORMAL )\r\n"
2684     "{\r\n"
2685     "    VS_OUTPUT Output;\r\n"
2686     "\r\n"
2687     "    // Transform the position from object space to homogeneous projection space\r\n"
2688     "    Output.Position = mul(vPos, g_mWorldViewProjection);\r\n"
2689     "\r\n"
2690     "    // Transform the normal from object space to world space\r\n"
2691     "    float3 vNormalWorldSpace;\r\n"
2692     "    vNormalWorldSpace = normalize(mul(vNormal, (float3x3)g_mWorld)); // normal (world space)\r\n"
2693     "\r\n"
2694     "    // Compute simple directional lighting equation\r\n"
2695     "    Output.Diffuse.rgb = g_MaterialDiffuseColor * max(0,dot(vNormalWorldSpace, g_LightDir));\r\n"
2696     "    Output.Diffuse.a = 1.0f;\r\n"
2697     "\r\n"
2698     "    return Output;\r\n"
2699     "}\r\n"
2700     "\r\n"
2701     "float4 RenderWith1LightNoTexturePS( float4 Diffuse : COLOR0 ) : COLOR0\r\n"
2702     "{\r\n"
2703     "    return Diffuse;\r\n"
2704     "}\r\n"
2705     "\r\n"
2706     "technique RenderWith1LightNoTexture\r\n"
2707     "{\r\n"
2708     "    pass P0\r\n"
2709     "    {\r\n"
2710     "        VertexShader = compile vs_1_1 RenderWith1LightNoTextureVS();\r\n"
2711     "        PixelShader  = compile ps_1_1 RenderWith1LightNoTexturePS();\r\n"
2712     "    }\r\n"
2713     "}\r\n"
2714     "";
2715 
2716     UINT dwBufferSize = (UINT)strlen(g_strBuffer) + 1;
2717 
2718     V_RETURN( D3DXCreateEffect( s_pd3dDevice, g_strBuffer, dwBufferSize, NULL, NULL, D3DXFX_NOT_CLONEABLE, NULL, &s_pEffect, NULL ) );
2719 
2720     // Load the mesh with D3DX and get back a ID3DXMesh*.  For this
2721     // sample we'll ignore the X file's embedded materials since we know
2722     // exactly the model we're loading.  See the mesh samples such as
2723     // "OptimizedMesh" for a more generic mesh loading example.
2724     V_RETURN( DXUTCreateArrowMeshFromInternalArray( s_pd3dDevice, &s_pMesh ) );
2725 
2726     // Optimize the mesh for this graphics card's vertex cache
2727     // so when rendering the mesh's triangle list the vertices will
2728     // cache hit more often so it won't have to re-execute the vertex shader
2729     // on those vertices so it will improve perf.
2730     DWORD* rgdwAdjacency = new DWORD[s_pMesh->GetNumFaces() * 3];
2731     if( rgdwAdjacency == NULL )
2732         return E_OUTOFMEMORY;
2733     V( s_pMesh->GenerateAdjacency(1e-6f,rgdwAdjacency) );
2734     V( s_pMesh->OptimizeInplace(D3DXMESHOPT_VERTEXCACHE, rgdwAdjacency, NULL, NULL, NULL) );
2735     delete []rgdwAdjacency;
2736 
2737     return S_OK;
2738 }
2739 
2740 
2741 //--------------------------------------------------------------------------------------
OnResetDevice(const D3DSURFACE_DESC * pBackBufferSurfaceDesc)2742 HRESULT CDXUTDirectionWidget::OnResetDevice( const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
2743 {
2744     m_ArcBall.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
2745     return S_OK;
2746 }
2747 
2748 
2749 //--------------------------------------------------------------------------------------
StaticOnLostDevice()2750 void CDXUTDirectionWidget::StaticOnLostDevice()
2751 {
2752     if( s_pEffect )
2753         s_pEffect->OnLostDevice();
2754 }
2755 
2756 
2757 //--------------------------------------------------------------------------------------
StaticOnDestroyDevice()2758 void CDXUTDirectionWidget::StaticOnDestroyDevice()
2759 {
2760     SAFE_RELEASE(s_pEffect);
2761     SAFE_RELEASE(s_pMesh);
2762 }
2763 
2764 
2765 //--------------------------------------------------------------------------------------
HandleMessages(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)2766 LRESULT CDXUTDirectionWidget::HandleMessages( HWND hWnd, UINT uMsg,
2767                                               WPARAM wParam, LPARAM lParam )
2768 {
2769     switch( uMsg )
2770     {
2771         case WM_LBUTTONDOWN:
2772         case WM_MBUTTONDOWN:
2773         case WM_RBUTTONDOWN:
2774         {
2775             if( ((m_nRotateMask & MOUSE_LEFT_BUTTON) != 0 && uMsg == WM_LBUTTONDOWN) ||
2776                 ((m_nRotateMask & MOUSE_MIDDLE_BUTTON) != 0 && uMsg == WM_MBUTTONDOWN) ||
2777                 ((m_nRotateMask & MOUSE_RIGHT_BUTTON) != 0 && uMsg == WM_RBUTTONDOWN) )
2778             {
2779                 int iMouseX = (int)(short)LOWORD(lParam);
2780                 int iMouseY = (int)(short)HIWORD(lParam);
2781                 m_ArcBall.OnBegin( iMouseX, iMouseY );
2782                 SetCapture(hWnd);
2783             }
2784             return TRUE;
2785         }
2786 
2787         case WM_MOUSEMOVE:
2788         {
2789             if( m_ArcBall.IsBeingDragged() )
2790             {
2791                 int iMouseX = (int)(short)LOWORD(lParam);
2792                 int iMouseY = (int)(short)HIWORD(lParam);
2793                 m_ArcBall.OnMove( iMouseX, iMouseY );
2794                 UpdateLightDir();
2795             }
2796             return TRUE;
2797         }
2798 
2799         case WM_LBUTTONUP:
2800         case WM_MBUTTONUP:
2801         case WM_RBUTTONUP:
2802         {
2803             if( ((m_nRotateMask & MOUSE_LEFT_BUTTON) != 0 && uMsg == WM_LBUTTONUP) ||
2804                 ((m_nRotateMask & MOUSE_MIDDLE_BUTTON) != 0 && uMsg == WM_MBUTTONUP) ||
2805                 ((m_nRotateMask & MOUSE_RIGHT_BUTTON) != 0 && uMsg == WM_RBUTTONUP) )
2806             {
2807                 m_ArcBall.OnEnd();
2808                 ReleaseCapture();
2809             }
2810 
2811             UpdateLightDir();
2812             return TRUE;
2813         }
2814 
2815         case WM_CAPTURECHANGED:
2816         {
2817             if( (HWND)lParam != hWnd )
2818             {
2819                 if( (m_nRotateMask & MOUSE_LEFT_BUTTON) ||
2820                     (m_nRotateMask & MOUSE_MIDDLE_BUTTON) ||
2821                     (m_nRotateMask & MOUSE_RIGHT_BUTTON) )
2822                 {
2823                     m_ArcBall.OnEnd();
2824                     ReleaseCapture();
2825                 }
2826             }
2827 
2828             return TRUE;
2829         }
2830     }
2831 
2832     return 0;
2833 }
2834 
2835 
2836 //--------------------------------------------------------------------------------------
OnRender(D3DXCOLOR color,const D3DXMATRIX * pmView,const D3DXMATRIX * pmProj,const D3DXVECTOR3 * pEyePt)2837 HRESULT CDXUTDirectionWidget::OnRender( D3DXCOLOR color, const D3DXMATRIX* pmView,
2838                                         const D3DXMATRIX* pmProj, const D3DXVECTOR3* pEyePt )
2839 {
2840     m_mView = *pmView;
2841 
2842     // Render the light spheres so the user can visually see the light dir
2843     UINT iPass, cPasses;
2844     D3DXMATRIX mRotate;
2845     D3DXMATRIX mScale;
2846     D3DXMATRIX mTrans;
2847     D3DXMATRIXA16 mWorldViewProj;
2848     HRESULT hr;
2849 
2850     V( s_pEffect->SetTechnique( "RenderWith1LightNoTexture" ) );
2851     V( s_pEffect->SetVector( "g_MaterialDiffuseColor", (D3DXVECTOR4*)&color ) );
2852 
2853     D3DXVECTOR3 vEyePt;
2854     D3DXVec3Normalize( &vEyePt, pEyePt );
2855     V( s_pEffect->SetValue( "g_LightDir", &vEyePt, sizeof(D3DXVECTOR3) ) );
2856 
2857     // Rotate arrow model to point towards origin
2858     D3DXMATRIX mRotateA, mRotateB;
2859     D3DXVECTOR3 vAt = D3DXVECTOR3(0,0,0);
2860     D3DXVECTOR3 vUp = D3DXVECTOR3(0,1,0);
2861     D3DXMatrixRotationX( &mRotateB, D3DX_PI );
2862     D3DXMatrixLookAtLH( &mRotateA, &m_vCurrentDir, &vAt, &vUp );
2863     D3DXMatrixInverse( &mRotateA, NULL, &mRotateA );
2864     mRotate = mRotateB * mRotateA;
2865 
2866     D3DXVECTOR3 vL = m_vCurrentDir * m_fRadius * 1.0f;
2867     D3DXMatrixTranslation( &mTrans, vL.x, vL.y, vL.z );
2868     D3DXMatrixScaling( &mScale, m_fRadius*0.2f, m_fRadius*0.2f, m_fRadius*0.2f );
2869 
2870     D3DXMATRIX mWorld = mRotate * mScale * mTrans;
2871     mWorldViewProj = mWorld * (m_mView) * (*pmProj);
2872 
2873     V( s_pEffect->SetMatrix( "g_mWorldViewProjection", &mWorldViewProj ) );
2874     V( s_pEffect->SetMatrix( "g_mWorld", &mWorld ) );
2875 
2876     for( int iSubset=0; iSubset<2; iSubset++ )
2877     {
2878         V( s_pEffect->Begin(&cPasses, 0) );
2879         for (iPass = 0; iPass < cPasses; iPass++)
2880         {
2881             V( s_pEffect->BeginPass(iPass) );
2882             V( s_pMesh->DrawSubset(iSubset) );
2883             V( s_pEffect->EndPass() );
2884         }
2885         V( s_pEffect->End() );
2886     }
2887 
2888     return S_OK;
2889 }
2890 
2891 
2892 //--------------------------------------------------------------------------------------
UpdateLightDir()2893 HRESULT CDXUTDirectionWidget::UpdateLightDir()
2894 {
2895     D3DXMATRIX mInvView;
2896     D3DXMatrixInverse(&mInvView, NULL, &m_mView);
2897     mInvView._41 = mInvView._42 = mInvView._43 = 0;
2898 
2899     D3DXMATRIX mLastRotInv;
2900     D3DXMatrixInverse(&mLastRotInv, NULL, &m_mRotSnapshot);
2901 
2902     D3DXMATRIX mRot = *m_ArcBall.GetRotationMatrix();
2903     m_mRotSnapshot = mRot;
2904 
2905     // Accumulate the delta of the arcball's rotation in view space.
2906     // Note that per-frame delta rotations could be problematic over long periods of time.
2907     m_mRot *= m_mView * mLastRotInv * mRot * mInvView;
2908 
2909     // Since we're accumulating delta rotations, we need to orthonormalize
2910     // the matrix to prevent eventual matrix skew
2911     D3DXVECTOR3* pXBasis = (D3DXVECTOR3*) &m_mRot._11;
2912     D3DXVECTOR3* pYBasis = (D3DXVECTOR3*) &m_mRot._21;
2913     D3DXVECTOR3* pZBasis = (D3DXVECTOR3*) &m_mRot._31;
2914     D3DXVec3Normalize( pXBasis, pXBasis );
2915     D3DXVec3Cross( pYBasis, pZBasis, pXBasis );
2916     D3DXVec3Normalize( pYBasis, pYBasis );
2917     D3DXVec3Cross( pZBasis, pXBasis, pYBasis );
2918 
2919     // Transform the default direction vector by the light's rotation matrix
2920     D3DXVec3TransformNormal( &m_vCurrentDir, &m_vDefaultDir, &m_mRot );
2921 
2922     return S_OK;
2923 }
2924 
2925 //--------------------------------------------------------------------------------------
2926 // Direct3D9 dynamic linking support -- calls top-level D3D9 APIs with graceful
2927 // failure if APIs are not present.
2928 //--------------------------------------------------------------------------------------
2929 
2930 // Function prototypes
2931 typedef IDirect3D9* (WINAPI * LPDIRECT3DCREATE9) (UINT);
2932 typedef INT         (WINAPI * LPD3DPERF_BEGINEVENT)(D3DCOLOR, LPCWSTR);
2933 typedef INT         (WINAPI * LPD3DPERF_ENDEVENT)(void);
2934 typedef VOID        (WINAPI * LPD3DPERF_SETMARKER)(D3DCOLOR, LPCWSTR);
2935 typedef VOID        (WINAPI * LPD3DPERF_SETREGION)(D3DCOLOR, LPCWSTR);
2936 typedef BOOL        (WINAPI * LPD3DPERF_QUERYREPEATFRAME)(void);
2937 typedef VOID        (WINAPI * LPD3DPERF_SETOPTIONS)( DWORD dwOptions );
2938 typedef DWORD       (WINAPI * LPD3DPERF_GETSTATUS)( void );
2939 
2940 // Module and function pointers
2941 static HMODULE s_hModD3D9 = NULL;
2942 static LPDIRECT3DCREATE9 s_DynamicDirect3DCreate9 = NULL;
2943 static LPD3DPERF_BEGINEVENT s_DynamicD3DPERF_BeginEvent = NULL;
2944 static LPD3DPERF_ENDEVENT s_DynamicD3DPERF_EndEvent = NULL;
2945 static LPD3DPERF_SETMARKER s_DynamicD3DPERF_SetMarker = NULL;
2946 static LPD3DPERF_SETREGION s_DynamicD3DPERF_SetRegion = NULL;
2947 static LPD3DPERF_QUERYREPEATFRAME s_DynamicD3DPERF_QueryRepeatFrame = NULL;
2948 static LPD3DPERF_SETOPTIONS s_DynamicD3DPERF_SetOptions = NULL;
2949 static LPD3DPERF_GETSTATUS s_DynamicD3DPERF_GetStatus = NULL;
2950 
2951 // Ensure function pointers are initialized
DXUT_EnsureD3DAPIs(void)2952 static bool DXUT_EnsureD3DAPIs( void )
2953 {
2954     // If module is non-NULL, this function has already been called.  Note
2955     // that this doesn't guarantee that all D3D9 procaddresses were found.
2956     if( s_hModD3D9 != NULL )
2957         return true;
2958 
2959     // This may fail if DirectX 9 isn't installed
2960     WCHAR wszPath[MAX_PATH+1];
2961     if( !::GetSystemDirectory( wszPath, MAX_PATH+1 ) )
2962         return false;
2963     StringCchCat( wszPath, MAX_PATH, L"\\d3d9.dll" );
2964     s_hModD3D9 = LoadLibrary( wszPath );
2965     if( s_hModD3D9 == NULL )
2966         return false;
2967     s_DynamicDirect3DCreate9 = (LPDIRECT3DCREATE9)GetProcAddress( s_hModD3D9, "Direct3DCreate9" );
2968     s_DynamicD3DPERF_BeginEvent = (LPD3DPERF_BEGINEVENT)GetProcAddress( s_hModD3D9, "D3DPERF_BeginEvent" );
2969     s_DynamicD3DPERF_EndEvent = (LPD3DPERF_ENDEVENT)GetProcAddress( s_hModD3D9, "D3DPERF_EndEvent" );
2970     s_DynamicD3DPERF_SetMarker = (LPD3DPERF_SETMARKER)GetProcAddress( s_hModD3D9, "D3DPERF_SetMarker" );
2971     s_DynamicD3DPERF_SetRegion = (LPD3DPERF_SETREGION)GetProcAddress( s_hModD3D9, "D3DPERF_SetRegion" );
2972     s_DynamicD3DPERF_QueryRepeatFrame = (LPD3DPERF_QUERYREPEATFRAME)GetProcAddress( s_hModD3D9, "D3DPERF_QueryRepeatFrame" );
2973     s_DynamicD3DPERF_SetOptions = (LPD3DPERF_SETOPTIONS)GetProcAddress( s_hModD3D9, "D3DPERF_SetOptions" );
2974     s_DynamicD3DPERF_GetStatus = (LPD3DPERF_GETSTATUS)GetProcAddress( s_hModD3D9, "D3DPERF_GetStatus" );
2975     return true;
2976 }
2977 
DXUT_Dynamic_Direct3DCreate9(UINT SDKVersion)2978 IDirect3D9 * WINAPI DXUT_Dynamic_Direct3DCreate9(UINT SDKVersion)
2979 {
2980     if( DXUT_EnsureD3DAPIs() && s_DynamicDirect3DCreate9 != NULL )
2981         return s_DynamicDirect3DCreate9( SDKVersion );
2982     else
2983         return NULL;
2984 }
2985 
DXUT_Dynamic_D3DPERF_BeginEvent(D3DCOLOR col,LPCWSTR wszName)2986 int WINAPI DXUT_Dynamic_D3DPERF_BeginEvent( D3DCOLOR col, LPCWSTR wszName )
2987 {
2988     if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_BeginEvent != NULL )
2989         return s_DynamicD3DPERF_BeginEvent( col, wszName );
2990     else
2991         return -1;
2992 }
2993 
DXUT_Dynamic_D3DPERF_EndEvent(void)2994 int WINAPI DXUT_Dynamic_D3DPERF_EndEvent( void )
2995 {
2996     if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_EndEvent != NULL )
2997         return s_DynamicD3DPERF_EndEvent();
2998     else
2999         return -1;
3000 }
3001 
DXUT_Dynamic_D3DPERF_SetMarker(D3DCOLOR col,LPCWSTR wszName)3002 void WINAPI DXUT_Dynamic_D3DPERF_SetMarker( D3DCOLOR col, LPCWSTR wszName )
3003 {
3004     if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_SetMarker != NULL )
3005         s_DynamicD3DPERF_SetMarker( col, wszName );
3006 }
3007 
DXUT_Dynamic_D3DPERF_SetRegion(D3DCOLOR col,LPCWSTR wszName)3008 void WINAPI DXUT_Dynamic_D3DPERF_SetRegion( D3DCOLOR col, LPCWSTR wszName )
3009 {
3010     if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_SetRegion != NULL )
3011         s_DynamicD3DPERF_SetRegion( col, wszName );
3012 }
3013 
DXUT_Dynamic_D3DPERF_QueryRepeatFrame(void)3014 BOOL WINAPI DXUT_Dynamic_D3DPERF_QueryRepeatFrame( void )
3015 {
3016     if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_QueryRepeatFrame != NULL )
3017         return s_DynamicD3DPERF_QueryRepeatFrame();
3018     else
3019         return FALSE;
3020 }
3021 
DXUT_Dynamic_D3DPERF_SetOptions(DWORD dwOptions)3022 void WINAPI DXUT_Dynamic_D3DPERF_SetOptions( DWORD dwOptions )
3023 {
3024     if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_SetOptions != NULL )
3025         s_DynamicD3DPERF_SetOptions( dwOptions );
3026 }
3027 
DXUT_Dynamic_D3DPERF_GetStatus(void)3028 DWORD WINAPI DXUT_Dynamic_D3DPERF_GetStatus( void )
3029 {
3030     if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_GetStatus != NULL )
3031         return s_DynamicD3DPERF_GetStatus();
3032     else
3033         return 0;
3034 }
3035 
3036 
3037 //--------------------------------------------------------------------------------------
3038 // Trace a string description of a decl
3039 //--------------------------------------------------------------------------------------
DXUTTraceDecl(D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE])3040 void DXUTTraceDecl( D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE] )
3041 {
3042     int iDecl=0;
3043     for( iDecl=0; iDecl<MAX_FVF_DECL_SIZE; iDecl++ )
3044     {
3045         if( decl[iDecl].Stream == 0xFF )
3046             break;
3047 
3048         DXUTOutputDebugString( L"decl[%d]=Stream:%d, Offset:%d, %s, %s, %s, UsageIndex:%d\n", iDecl,
3049                     decl[iDecl].Stream,
3050                     decl[iDecl].Offset,
3051                     DXUTTraceD3DDECLTYPEtoString( decl[iDecl].Type ),
3052                     DXUTTraceD3DDECLMETHODtoString( decl[iDecl].Method ),
3053                     DXUTTraceD3DDECLUSAGEtoString( decl[iDecl].Usage ),
3054                     decl[iDecl].UsageIndex );
3055     }
3056 
3057     DXUTOutputDebugString( L"decl[%d]=D3DDECL_END\n", iDecl );
3058 }
3059 
3060 
3061 //--------------------------------------------------------------------------------------
DXUTTraceD3DDECLTYPEtoString(BYTE t)3062 WCHAR* DXUTTraceD3DDECLTYPEtoString( BYTE t )
3063 {
3064     switch( t )
3065     {
3066         case D3DDECLTYPE_FLOAT1: return L"D3DDECLTYPE_FLOAT1";
3067         case D3DDECLTYPE_FLOAT2: return L"D3DDECLTYPE_FLOAT2";
3068         case D3DDECLTYPE_FLOAT3: return L"D3DDECLTYPE_FLOAT3";
3069         case D3DDECLTYPE_FLOAT4: return L"D3DDECLTYPE_FLOAT4";
3070         case D3DDECLTYPE_D3DCOLOR: return L"D3DDECLTYPE_D3DCOLOR";
3071         case D3DDECLTYPE_UBYTE4: return L"D3DDECLTYPE_UBYTE4";
3072         case D3DDECLTYPE_SHORT2: return L"D3DDECLTYPE_SHORT2";
3073         case D3DDECLTYPE_SHORT4: return L"D3DDECLTYPE_SHORT4";
3074         case D3DDECLTYPE_UBYTE4N: return L"D3DDECLTYPE_UBYTE4N";
3075         case D3DDECLTYPE_SHORT2N: return L"D3DDECLTYPE_SHORT2N";
3076         case D3DDECLTYPE_SHORT4N: return L"D3DDECLTYPE_SHORT4N";
3077         case D3DDECLTYPE_USHORT2N: return L"D3DDECLTYPE_USHORT2N";
3078         case D3DDECLTYPE_USHORT4N: return L"D3DDECLTYPE_USHORT4N";
3079         case D3DDECLTYPE_UDEC3: return L"D3DDECLTYPE_UDEC3";
3080         case D3DDECLTYPE_DEC3N: return L"D3DDECLTYPE_DEC3N";
3081         case D3DDECLTYPE_FLOAT16_2: return L"D3DDECLTYPE_FLOAT16_2";
3082         case D3DDECLTYPE_FLOAT16_4: return L"D3DDECLTYPE_FLOAT16_4";
3083         case D3DDECLTYPE_UNUSED: return L"D3DDECLTYPE_UNUSED";
3084         default: return L"D3DDECLTYPE Unknown";
3085     }
3086 }
3087 
DXUTTraceD3DDECLMETHODtoString(BYTE m)3088 WCHAR* DXUTTraceD3DDECLMETHODtoString( BYTE m )
3089 {
3090     switch( m )
3091     {
3092         case D3DDECLMETHOD_DEFAULT: return L"D3DDECLMETHOD_DEFAULT";
3093         case D3DDECLMETHOD_PARTIALU: return L"D3DDECLMETHOD_PARTIALU";
3094         case D3DDECLMETHOD_PARTIALV: return L"D3DDECLMETHOD_PARTIALV";
3095         case D3DDECLMETHOD_CROSSUV: return L"D3DDECLMETHOD_CROSSUV";
3096         case D3DDECLMETHOD_UV: return L"D3DDECLMETHOD_UV";
3097         case D3DDECLMETHOD_LOOKUP: return L"D3DDECLMETHOD_LOOKUP";
3098         case D3DDECLMETHOD_LOOKUPPRESAMPLED: return L"D3DDECLMETHOD_LOOKUPPRESAMPLED";
3099         default: return L"D3DDECLMETHOD Unknown";
3100     }
3101 }
3102 
DXUTTraceD3DDECLUSAGEtoString(BYTE u)3103 WCHAR* DXUTTraceD3DDECLUSAGEtoString( BYTE u )
3104 {
3105     switch( u )
3106     {
3107         case D3DDECLUSAGE_POSITION: return L"D3DDECLUSAGE_POSITION";
3108         case D3DDECLUSAGE_BLENDWEIGHT: return L"D3DDECLUSAGE_BLENDWEIGHT";
3109         case D3DDECLUSAGE_BLENDINDICES: return L"D3DDECLUSAGE_BLENDINDICES";
3110         case D3DDECLUSAGE_NORMAL: return L"D3DDECLUSAGE_NORMAL";
3111         case D3DDECLUSAGE_PSIZE: return L"D3DDECLUSAGE_PSIZE";
3112         case D3DDECLUSAGE_TEXCOORD: return L"D3DDECLUSAGE_TEXCOORD";
3113         case D3DDECLUSAGE_TANGENT: return L"D3DDECLUSAGE_TANGENT";
3114         case D3DDECLUSAGE_BINORMAL: return L"D3DDECLUSAGE_BINORMAL";
3115         case D3DDECLUSAGE_TESSFACTOR: return L"D3DDECLUSAGE_TESSFACTOR";
3116         case D3DDECLUSAGE_POSITIONT: return L"D3DDECLUSAGE_POSITIONT";
3117         case D3DDECLUSAGE_COLOR: return L"D3DDECLUSAGE_COLOR";
3118         case D3DDECLUSAGE_FOG: return L"D3DDECLUSAGE_FOG";
3119         case D3DDECLUSAGE_DEPTH: return L"D3DDECLUSAGE_DEPTH";
3120         case D3DDECLUSAGE_SAMPLE: return L"D3DDECLUSAGE_SAMPLE";
3121         default: return L"D3DDECLUSAGE Unknown";
3122     }
3123 }
3124 
3125 
3126 //--------------------------------------------------------------------------------------
3127 // Multimon API handling for OSes with or without multimon API support
3128 //--------------------------------------------------------------------------------------
3129 #define DXUT_PRIMARY_MONITOR ((HMONITOR)0x12340042)
3130 typedef HMONITOR (WINAPI* LPMONITORFROMWINDOW)(HWND, DWORD);
3131 typedef BOOL     (WINAPI* LPGETMONITORINFO)(HMONITOR, LPMONITORINFO);
3132 
DXUTGetMonitorInfo(HMONITOR hMonitor,LPMONITORINFO lpMonitorInfo)3133 BOOL DXUTGetMonitorInfo(HMONITOR hMonitor, LPMONITORINFO lpMonitorInfo)
3134 {
3135     static bool s_bInited = false;
3136     static LPGETMONITORINFO s_pFnGetMonitorInfo = NULL;
3137     if( !s_bInited )
3138     {
3139         s_bInited = true;
3140         HMODULE hUser32 = GetModuleHandle( L"USER32" );
3141         if (hUser32 )
3142         {
3143             OSVERSIONINFOA osvi = {0}; osvi.dwOSVersionInfoSize = sizeof(osvi); GetVersionExA((OSVERSIONINFOA*)&osvi);
3144             bool bNT = (VER_PLATFORM_WIN32_NT == osvi.dwPlatformId);
3145             s_pFnGetMonitorInfo = (LPGETMONITORINFO) (bNT ? GetProcAddress(hUser32,"GetMonitorInfoW") : GetProcAddress(hUser32,"GetMonitorInfoA"));
3146         }
3147     }
3148 
3149     if( s_pFnGetMonitorInfo )
3150         return s_pFnGetMonitorInfo(hMonitor, lpMonitorInfo);
3151 
3152     RECT rcWork;
3153     if ((hMonitor == DXUT_PRIMARY_MONITOR) && lpMonitorInfo && (lpMonitorInfo->cbSize >= sizeof(MONITORINFO)) && SystemParametersInfoA(SPI_GETWORKAREA, 0, &rcWork, 0))
3154     {
3155         lpMonitorInfo->rcMonitor.left = 0;
3156         lpMonitorInfo->rcMonitor.top  = 0;
3157         lpMonitorInfo->rcMonitor.right  = GetSystemMetrics(SM_CXSCREEN);
3158         lpMonitorInfo->rcMonitor.bottom = GetSystemMetrics(SM_CYSCREEN);
3159         lpMonitorInfo->rcWork = rcWork;
3160         lpMonitorInfo->dwFlags = MONITORINFOF_PRIMARY;
3161         return TRUE;
3162     }
3163     return FALSE;
3164 }
3165 
3166 
DXUTMonitorFromWindow(HWND hWnd,DWORD dwFlags)3167 HMONITOR DXUTMonitorFromWindow(HWND hWnd, DWORD dwFlags)
3168 {
3169     static bool s_bInited = false;
3170     static LPMONITORFROMWINDOW s_pFnGetMonitorFronWindow = NULL;
3171     if( !s_bInited )
3172     {
3173         s_bInited = true;
3174         HMODULE hUser32 = GetModuleHandle( L"USER32" );
3175         if (hUser32 ) s_pFnGetMonitorFronWindow = (LPMONITORFROMWINDOW) GetProcAddress(hUser32,"MonitorFromWindow");
3176     }
3177 
3178     if( s_pFnGetMonitorFronWindow )
3179         return s_pFnGetMonitorFronWindow(hWnd, dwFlags);
3180     if (dwFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST))
3181         return DXUT_PRIMARY_MONITOR;
3182     return NULL;
3183 }
3184 
3185 
3186 //--------------------------------------------------------------------------------------
3187 // Get the desktop resolution of an adapter. This isn't the same as the current resolution
3188 // from GetAdapterDisplayMode since the device might be fullscreen
3189 //--------------------------------------------------------------------------------------
DXUTGetDesktopResolution(UINT AdapterOrdinal,UINT * pWidth,UINT * pHeight)3190 void DXUTGetDesktopResolution( UINT AdapterOrdinal, UINT* pWidth, UINT* pHeight )
3191 {
3192     CD3DEnumeration* pd3dEnum = DXUTGetEnumeration();
3193     CD3DEnumAdapterInfo* pAdapterInfo = pd3dEnum->GetAdapterInfo( AdapterOrdinal );
3194     DEVMODE devMode;
3195     ZeroMemory( &devMode, sizeof(DEVMODE) );
3196     devMode.dmSize = sizeof(DEVMODE);
3197     WCHAR strDeviceName[256];
3198     MultiByteToWideChar( CP_ACP, 0, pAdapterInfo->AdapterIdentifier.DeviceName, -1, strDeviceName, 256 );
3199     strDeviceName[255] = 0;
3200     EnumDisplaySettings( strDeviceName, ENUM_REGISTRY_SETTINGS, &devMode );
3201 
3202     if( pWidth )
3203         *pWidth = devMode.dmPelsWidth;
3204     if( pHeight )
3205         *pHeight = devMode.dmPelsHeight;
3206 }
3207 
3208 
3209 //--------------------------------------------------------------------------------------
DXUTCreateRefDevice(HWND hWnd,bool bNullRef)3210 IDirect3DDevice9* DXUTCreateRefDevice( HWND hWnd, bool bNullRef )
3211 {
3212     HRESULT hr;
3213     IDirect3D9* pD3D = DXUT_Dynamic_Direct3DCreate9( D3D_SDK_VERSION );
3214     if( NULL == pD3D )
3215         return NULL;
3216 
3217     D3DDISPLAYMODE Mode;
3218     pD3D->GetAdapterDisplayMode(0, &Mode);
3219 
3220     D3DPRESENT_PARAMETERS pp;
3221     ZeroMemory( &pp, sizeof(D3DPRESENT_PARAMETERS) );
3222     pp.BackBufferWidth  = 1;
3223     pp.BackBufferHeight = 1;
3224     pp.BackBufferFormat = Mode.Format;
3225     pp.BackBufferCount  = 1;
3226     pp.SwapEffect       = D3DSWAPEFFECT_COPY;
3227     pp.Windowed         = TRUE;
3228     pp.hDeviceWindow    = hWnd;
3229 
3230     IDirect3DDevice9* pd3dDevice = NULL;
3231     hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, bNullRef ? D3DDEVTYPE_NULLREF : D3DDEVTYPE_REF,
3232                              hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &pp, &pd3dDevice );
3233 
3234     SAFE_RELEASE( pD3D );
3235     return pd3dDevice;
3236 }
3237 
3238 
3239 typedef DWORD (WINAPI* LPXINPUTGETSTATE)(DWORD dwUserIndex, XINPUT_STATE* pState );
3240 typedef DWORD (WINAPI* LPXINPUTSETSTATE)(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration );
3241 typedef DWORD (WINAPI* LPXINPUTGETCAPABILITIES)( DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities );
3242 typedef void  (WINAPI* LPXINPUTENABLE)(BOOL bEnable);
3243 
3244 
3245 
3246 //--------------------------------------------------------------------------------------
3247 // Does extra processing on XInput data to make it slightly more convenient to use
3248 //--------------------------------------------------------------------------------------
DXUTGetGamepadState(DWORD dwPort,DXUT_GAMEPAD * pGamePad,bool bThumbstickDeadZone,bool bSnapThumbstickToCardinals)3249 HRESULT DXUTGetGamepadState( DWORD dwPort, DXUT_GAMEPAD* pGamePad, bool bThumbstickDeadZone, bool bSnapThumbstickToCardinals )
3250 {
3251     if( dwPort >= DXUT_MAX_CONTROLLERS || pGamePad == NULL )
3252         return E_FAIL;
3253 
3254     static LPXINPUTGETSTATE s_pXInputGetState = NULL;
3255     static LPXINPUTGETCAPABILITIES s_pXInputGetCapabilities = NULL;
3256     if( NULL == s_pXInputGetState || NULL == s_pXInputGetCapabilities )
3257     {
3258         WCHAR wszPath[MAX_PATH];
3259         if( GetSystemDirectory( wszPath, MAX_PATH ) )
3260         {
3261             StringCchCat( wszPath, MAX_PATH, L"\\" );
3262             StringCchCat( wszPath, MAX_PATH, XINPUT_DLL );
3263             HINSTANCE hInst = LoadLibrary( wszPath );
3264             if( hInst )
3265             {
3266                 s_pXInputGetState = (LPXINPUTGETSTATE)GetProcAddress( hInst, "XInputGetState" );
3267                 s_pXInputGetCapabilities = (LPXINPUTGETCAPABILITIES)GetProcAddress( hInst, "XInputGetCapabilities" );
3268             }
3269         }
3270     }
3271     if( s_pXInputGetState == NULL )
3272         return E_FAIL;
3273 
3274     XINPUT_STATE InputState;
3275     DWORD dwResult = s_pXInputGetState( dwPort, &InputState );
3276 
3277     // Track insertion and removals
3278     BOOL bWasConnected = pGamePad->bConnected;
3279     pGamePad->bConnected = (dwResult == ERROR_SUCCESS);
3280     pGamePad->bRemoved  = (  bWasConnected && !pGamePad->bConnected );
3281     pGamePad->bInserted = ( !bWasConnected &&  pGamePad->bConnected );
3282 
3283     // Don't update rest of the state if not connected
3284     if( !pGamePad->bConnected )
3285         return S_OK;
3286 
3287     // Store the capabilities of the device
3288     if( pGamePad->bInserted )
3289     {
3290         ZeroMemory( pGamePad, sizeof(DXUT_GAMEPAD) );
3291         pGamePad->bConnected = true;
3292         pGamePad->bInserted  = true;
3293         if( s_pXInputGetCapabilities )
3294             s_pXInputGetCapabilities( dwPort, XINPUT_DEVTYPE_GAMEPAD, &pGamePad->caps );
3295     }
3296 
3297     // Copy gamepad to local structure (assumes that XINPUT_GAMEPAD at the front in CONTROLER_STATE)
3298     memcpy( pGamePad, &InputState.Gamepad, sizeof(XINPUT_GAMEPAD) );
3299 
3300     if( bSnapThumbstickToCardinals )
3301     {
3302         // Apply deadzone to each axis independantly to slightly snap to up/down/left/right
3303         if( pGamePad->sThumbLX < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE && pGamePad->sThumbLX > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE )
3304             pGamePad->sThumbLX = 0;
3305         if( pGamePad->sThumbLY < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE && pGamePad->sThumbLY > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE )
3306             pGamePad->sThumbLY = 0;
3307         if( pGamePad->sThumbRX < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE && pGamePad->sThumbRX > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE )
3308             pGamePad->sThumbRX = 0;
3309         if( pGamePad->sThumbRY < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE && pGamePad->sThumbRY > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE )
3310             pGamePad->sThumbRY = 0;
3311     }
3312     else if( bThumbstickDeadZone )
3313     {
3314         // Apply deadzone if centered
3315         if( (pGamePad->sThumbLX < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE && pGamePad->sThumbLX > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) &&
3316             (pGamePad->sThumbLY < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE && pGamePad->sThumbLY > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) )
3317         {
3318             pGamePad->sThumbLX = 0;
3319             pGamePad->sThumbLY = 0;
3320         }
3321         if( (pGamePad->sThumbRX < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE && pGamePad->sThumbRX > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) &&
3322             (pGamePad->sThumbRY < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE && pGamePad->sThumbRY > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) )
3323         {
3324             pGamePad->sThumbRX = 0;
3325             pGamePad->sThumbRY = 0;
3326         }
3327     }
3328 
3329     // Convert [-1,+1] range
3330     pGamePad->fThumbLX = pGamePad->sThumbLX / 32767.0f;
3331     pGamePad->fThumbLY = pGamePad->sThumbLY / 32767.0f;
3332     pGamePad->fThumbRX = pGamePad->sThumbRX / 32767.0f;
3333     pGamePad->fThumbRY = pGamePad->sThumbRY / 32767.0f;
3334 
3335     // Get the boolean buttons that have been pressed since the last call.
3336     // Each button is represented by one bit.
3337     pGamePad->wPressedButtons = ( pGamePad->wLastButtons ^ pGamePad->wButtons ) & pGamePad->wButtons;
3338     pGamePad->wLastButtons    = pGamePad->wButtons;
3339 
3340     // Figure out if the left trigger has been pressed or released
3341     bool bPressed = ( pGamePad->bLeftTrigger > DXUT_GAMEPAD_TRIGGER_THRESHOLD );
3342     pGamePad->bPressedLeftTrigger = ( bPressed ) ? !pGamePad->bLastLeftTrigger : false;
3343     pGamePad->bLastLeftTrigger = bPressed;
3344 
3345     // Figure out if the right trigger has been pressed or released
3346     bPressed = ( pGamePad->bRightTrigger > DXUT_GAMEPAD_TRIGGER_THRESHOLD );
3347     pGamePad->bPressedRightTrigger = ( bPressed ) ? !pGamePad->bLastRightTrigger : false;
3348     pGamePad->bLastRightTrigger = bPressed;
3349 
3350     return S_OK;
3351 }
3352 
3353 
3354 //--------------------------------------------------------------------------------------
3355 // Don't pause the game or deactive the window without first stopping rumble otherwise
3356 // the controller will continue to rumble
3357 //--------------------------------------------------------------------------------------
DXUTEnableXInput(bool bEnable)3358 void DXUTEnableXInput( bool bEnable )
3359 {
3360     static LPXINPUTENABLE s_pXInputEnable = NULL;
3361     if( NULL == s_pXInputEnable )
3362     {
3363         WCHAR wszPath[MAX_PATH];
3364         if( GetSystemDirectory( wszPath, MAX_PATH ) )
3365         {
3366             StringCchCat( wszPath, MAX_PATH, L"\\" );
3367             StringCchCat( wszPath, MAX_PATH, XINPUT_DLL );
3368             HINSTANCE hInst = LoadLibrary( wszPath );
3369             if( hInst )
3370                 s_pXInputEnable = (LPXINPUTENABLE)GetProcAddress( hInst, "XInputEnable" );
3371         }
3372     }
3373 
3374     if( s_pXInputEnable )
3375         s_pXInputEnable( bEnable );
3376 }
3377 
3378 
3379 //--------------------------------------------------------------------------------------
3380 // Don't pause the game or deactive the window without first stopping rumble otherwise
3381 // the controller will continue to rumble
3382 //--------------------------------------------------------------------------------------
DXUTStopRumbleOnAllControllers()3383 HRESULT DXUTStopRumbleOnAllControllers()
3384 {
3385     static LPXINPUTSETSTATE s_pXInputSetState = NULL;
3386     if( NULL == s_pXInputSetState )
3387     {
3388         WCHAR wszPath[MAX_PATH];
3389         if( GetSystemDirectory( wszPath, MAX_PATH ) )
3390         {
3391             StringCchCat( wszPath, MAX_PATH, L"\\" );
3392             StringCchCat( wszPath, MAX_PATH, XINPUT_DLL );
3393             HINSTANCE hInst = LoadLibrary( wszPath );
3394             if( hInst )
3395                 s_pXInputSetState = (LPXINPUTSETSTATE)GetProcAddress( hInst, "XInputSetState" );
3396         }
3397     }
3398     if( s_pXInputSetState == NULL )
3399         return E_FAIL;
3400 
3401     XINPUT_VIBRATION vibration;
3402     vibration.wLeftMotorSpeed  = 0;
3403     vibration.wRightMotorSpeed = 0;
3404     for( int iUserIndex=0; iUserIndex<DXUT_MAX_CONTROLLERS; iUserIndex++ )
3405         s_pXInputSetState( iUserIndex, &vibration );
3406 
3407     return S_OK;
3408 }
3409 
3410 
3411 //--------------------------------------------------------------------------------------
3412 // Helper function to launch the Media Center UI after the program terminates
3413 //--------------------------------------------------------------------------------------
DXUTReLaunchMediaCenter()3414 bool DXUTReLaunchMediaCenter()
3415 {
3416     // Skip if not running on a Media Center
3417     if( GetSystemMetrics( 87 ) == 0 ) //  SM_MEDIACENTER == 87, but is only defined if _WIN32_WINNT >= 0x0501
3418         return false;
3419 
3420     // Get the path to Media Center
3421     WCHAR szExpandedPath[MAX_PATH];
3422     if( !ExpandEnvironmentStrings( L"%SystemRoot%\\ehome\\ehshell.exe", szExpandedPath, MAX_PATH) )
3423         return false;
3424 
3425     // Skip if ehshell.exe doesn't exist
3426     if( GetFileAttributes( szExpandedPath ) == 0xFFFFFFFF )
3427         return false;
3428 
3429     // Launch ehshell.exe
3430     INT_PTR result = (INT_PTR)ShellExecute( NULL, TEXT("open"), szExpandedPath, NULL, NULL, SW_SHOWNORMAL);
3431     return (result > 32);
3432 }
3433