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