source: GTP-Internal/trunk/App/Demos/Illum/Ocean/Common/DXUTmisc.cpp @ 1777

Revision 1777, 128.2 KB checked in by szirmay, 18 years ago (diff)
Line 
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//--------------------------------------------------------------------------------------
16CDXUTResourceCache& DXUTGetGlobalResourceCache()
17{
18    // Using an accessor function gives control of the construction order
19    static CDXUTResourceCache cache;
20    return cache;
21}
22CDXUTTimer* 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//--------------------------------------------------------------------------------------
33bool DXUTFindMediaSearchTypicalDirs( WCHAR* strSearchPath, int cchSearch, LPCWSTR strLeaf, WCHAR* strExePath, WCHAR* strExeName );
34bool DXUTFindMediaSearchParentDirs( WCHAR* strSearchPath, int cchSearch, WCHAR* strStartAt, WCHAR* strLeafName );
35INT_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//--------------------------------------------------------------------------------------
41void 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//--------------------------------------------------------------------------------------
100INT_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//--------------------------------------------------------------------------------------
129CDXUTTimer::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//--------------------------------------------------------------------------------------
146void 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//--------------------------------------------------------------------------------------
158void 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//--------------------------------------------------------------------------------------
173void 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//--------------------------------------------------------------------------------------
187void CDXUTTimer::Advance()
188{
189    m_llStopTime += m_llQPFTicksPerSec/10;
190}
191
192
193//--------------------------------------------------------------------------------------
194double 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//--------------------------------------------------------------------------------------
206double 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//--------------------------------------------------------------------------------------
217void 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//--------------------------------------------------------------------------------------
243double 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//--------------------------------------------------------------------------------------
261LARGE_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//--------------------------------------------------------------------------------------
273bool 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//--------------------------------------------------------------------------------------
284void 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//--------------------------------------------------------------------------------------
314WCHAR* DXUTMediaSearchPath()
315{
316    static WCHAR s_strMediaSearchPath[MAX_PATH] = {0};
317    return s_strMediaSearchPath;
318
319}   
320
321//--------------------------------------------------------------------------------------
322LPCWSTR DXUTGetMediaSearchPath()
323{
324    return DXUTMediaSearchPath();
325}
326
327
328//--------------------------------------------------------------------------------------
329HRESULT 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//--------------------------------------------------------------------------------------
356HRESULT 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//--------------------------------------------------------------------------------------
439bool 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//--------------------------------------------------------------------------------------
516bool 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
549CDXUTResourceCache::~CDXUTResourceCache()
550{
551    OnDestroyDevice();
552
553    m_TextureCache.RemoveAll();
554    m_EffectCache.RemoveAll();
555    m_FontCache.RemoveAll();
556}
557
558
559HRESULT 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//--------------------------------------------------------------------------------------
568HRESULT 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//--------------------------------------------------------------------------------------
615HRESULT 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//--------------------------------------------------------------------------------------
624HRESULT 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//--------------------------------------------------------------------------------------
673HRESULT 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//--------------------------------------------------------------------------------------
682HRESULT 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//--------------------------------------------------------------------------------------
727HRESULT 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//--------------------------------------------------------------------------------------
736HRESULT 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//--------------------------------------------------------------------------------------
783HRESULT 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//--------------------------------------------------------------------------------------
792HRESULT 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//--------------------------------------------------------------------------------------
841HRESULT 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//--------------------------------------------------------------------------------------
850HRESULT 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//--------------------------------------------------------------------------------------
901HRESULT 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//--------------------------------------------------------------------------------------
921HRESULT 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//--------------------------------------------------------------------------------------
966HRESULT 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//--------------------------------------------------------------------------------------
1004HRESULT 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//--------------------------------------------------------------------------------------
1050HRESULT CDXUTResourceCache::OnCreateDevice( IDirect3DDevice9 *pd3dDevice )
1051{
1052    return S_OK;
1053}
1054
1055
1056//--------------------------------------------------------------------------------------
1057HRESULT 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//--------------------------------------------------------------------------------------
1071HRESULT 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//--------------------------------------------------------------------------------------
1092HRESULT 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//--------------------------------------------------------------------------------------
1116CD3DArcBall::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//--------------------------------------------------------------------------------------
1133void 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//--------------------------------------------------------------------------------------
1149D3DXVECTOR3 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//--------------------------------------------------------------------------------------
1175D3DXQUATERNION 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//--------------------------------------------------------------------------------------
1188void 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//--------------------------------------------------------------------------------------
1207void 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//--------------------------------------------------------------------------------------
1220void CD3DArcBall::OnEnd()
1221{
1222    m_bDrag = false;
1223}
1224
1225
1226
1227
1228//--------------------------------------------------------------------------------------
1229// Desc:
1230//--------------------------------------------------------------------------------------
1231LRESULT 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//--------------------------------------------------------------------------------------
1311CBaseCamera::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//--------------------------------------------------------------------------------------
1364VOID 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//--------------------------------------------------------------------------------------
1395VOID 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//--------------------------------------------------------------------------------------
1413LRESULT 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//--------------------------------------------------------------------------------------
1527void 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//--------------------------------------------------------------------------------------
1650void 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//--------------------------------------------------------------------------------------
1708void 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//--------------------------------------------------------------------------------------
1726D3DUtil_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//--------------------------------------------------------------------------------------
1766VOID CBaseCamera::Reset()
1767{
1768    SetViewParams( &m_vDefaultEye, &m_vDefaultLookAt );
1769}
1770
1771
1772
1773
1774//--------------------------------------------------------------------------------------
1775// Constructor
1776//--------------------------------------------------------------------------------------
1777CFirstPersonCamera::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//--------------------------------------------------------------------------------------
1789VOID 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//--------------------------------------------------------------------------------------
1867void 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//--------------------------------------------------------------------------------------
1879CModelViewerCamera::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//--------------------------------------------------------------------------------------
1907VOID 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
2007void 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//--------------------------------------------------------------------------------------
2020VOID 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//--------------------------------------------------------------------------------------
2038void 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//--------------------------------------------------------------------------------------
2064LRESULT 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//--------------------------------------------------------------------------------------
2152D3DXMATRIX 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//--------------------------------------------------------------------------------------
2196LPCWSTR 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//--------------------------------------------------------------------------------------
2270VOID 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//--------------------------------------------------------------------------------------
2291VOID 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//--------------------------------------------------------------------------------------
2310CDXUTLineManager::CDXUTLineManager()
2311{
2312    m_pd3dDevice = NULL;
2313    m_pD3DXLine = NULL;
2314}
2315
2316
2317//--------------------------------------------------------------------------------------
2318CDXUTLineManager::~CDXUTLineManager()
2319{
2320    OnDeletedDevice();
2321}
2322
2323
2324//--------------------------------------------------------------------------------------
2325HRESULT 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//--------------------------------------------------------------------------------------
2339HRESULT CDXUTLineManager::OnResetDevice()
2340{
2341    if( m_pD3DXLine )
2342        m_pD3DXLine->OnResetDevice();
2343
2344    return S_OK;
2345}
2346
2347
2348//--------------------------------------------------------------------------------------
2349HRESULT 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//--------------------------------------------------------------------------------------
2405HRESULT CDXUTLineManager::OnLostDevice()
2406{
2407    if( m_pD3DXLine )
2408        m_pD3DXLine->OnLostDevice();
2409
2410    return S_OK;
2411}
2412
2413
2414//--------------------------------------------------------------------------------------
2415HRESULT CDXUTLineManager::OnDeletedDevice()
2416{
2417    RemoveAllLines();
2418    SAFE_RELEASE( m_pD3DXLine );
2419
2420    return S_OK;
2421}
2422
2423
2424//--------------------------------------------------------------------------------------
2425HRESULT 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//--------------------------------------------------------------------------------------
2462HRESULT 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//--------------------------------------------------------------------------------------
2519HRESULT 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//--------------------------------------------------------------------------------------
2537HRESULT 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//--------------------------------------------------------------------------------------
2555CDXUTTextHelper::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//--------------------------------------------------------------------------------------
2567HRESULT 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//--------------------------------------------------------------------------------------
2582HRESULT 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
2600HRESULT 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
2614HRESULT 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//--------------------------------------------------------------------------------------
2631void CDXUTTextHelper::Begin()
2632{
2633    if( m_pSprite )
2634        m_pSprite->Begin( D3DXSPRITE_ALPHABLEND | D3DXSPRITE_SORT_TEXTURE );
2635}
2636void CDXUTTextHelper::End()
2637{
2638    if( m_pSprite )
2639        m_pSprite->End();
2640}
2641
2642
2643//--------------------------------------------------------------------------------------
2644IDirect3DDevice9* CDXUTDirectionWidget::s_pd3dDevice = NULL;
2645ID3DXEffect*      CDXUTDirectionWidget::s_pEffect = NULL;       
2646ID3DXMesh*        CDXUTDirectionWidget::s_pMesh = NULL;   
2647
2648
2649//--------------------------------------------------------------------------------------
2650CDXUTDirectionWidget::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//--------------------------------------------------------------------------------------
2664HRESULT 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//--------------------------------------------------------------------------------------
2742HRESULT CDXUTDirectionWidget::OnResetDevice( const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
2743{
2744    m_ArcBall.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
2745    return S_OK;
2746}
2747
2748
2749//--------------------------------------------------------------------------------------
2750void CDXUTDirectionWidget::StaticOnLostDevice()
2751{
2752    if( s_pEffect )
2753        s_pEffect->OnLostDevice();
2754}
2755
2756
2757//--------------------------------------------------------------------------------------
2758void CDXUTDirectionWidget::StaticOnDestroyDevice()
2759{
2760    SAFE_RELEASE(s_pEffect);
2761    SAFE_RELEASE(s_pMesh);
2762}   
2763
2764
2765//--------------------------------------------------------------------------------------
2766LRESULT 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//--------------------------------------------------------------------------------------
2837HRESULT 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//--------------------------------------------------------------------------------------
2893HRESULT 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
2931typedef IDirect3D9* (WINAPI * LPDIRECT3DCREATE9) (UINT);
2932typedef INT         (WINAPI * LPD3DPERF_BEGINEVENT)(D3DCOLOR, LPCWSTR);
2933typedef INT         (WINAPI * LPD3DPERF_ENDEVENT)(void);
2934typedef VOID        (WINAPI * LPD3DPERF_SETMARKER)(D3DCOLOR, LPCWSTR);
2935typedef VOID        (WINAPI * LPD3DPERF_SETREGION)(D3DCOLOR, LPCWSTR);
2936typedef BOOL        (WINAPI * LPD3DPERF_QUERYREPEATFRAME)(void);
2937typedef VOID        (WINAPI * LPD3DPERF_SETOPTIONS)( DWORD dwOptions );
2938typedef DWORD       (WINAPI * LPD3DPERF_GETSTATUS)( void );
2939
2940// Module and function pointers
2941static HMODULE s_hModD3D9 = NULL;
2942static LPDIRECT3DCREATE9 s_DynamicDirect3DCreate9 = NULL;
2943static LPD3DPERF_BEGINEVENT s_DynamicD3DPERF_BeginEvent = NULL;
2944static LPD3DPERF_ENDEVENT s_DynamicD3DPERF_EndEvent = NULL;
2945static LPD3DPERF_SETMARKER s_DynamicD3DPERF_SetMarker = NULL;
2946static LPD3DPERF_SETREGION s_DynamicD3DPERF_SetRegion = NULL;
2947static LPD3DPERF_QUERYREPEATFRAME s_DynamicD3DPERF_QueryRepeatFrame = NULL;
2948static LPD3DPERF_SETOPTIONS s_DynamicD3DPERF_SetOptions = NULL;
2949static LPD3DPERF_GETSTATUS s_DynamicD3DPERF_GetStatus = NULL;
2950
2951// Ensure function pointers are initialized
2952static 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
2978IDirect3D9 * 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
2986int 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
2994int 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
3002void 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
3008void 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
3014BOOL 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
3022void WINAPI DXUT_Dynamic_D3DPERF_SetOptions( DWORD dwOptions )
3023{
3024    if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_SetOptions != NULL )
3025        s_DynamicD3DPERF_SetOptions( dwOptions );
3026}
3027
3028DWORD 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//--------------------------------------------------------------------------------------
3040void 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//--------------------------------------------------------------------------------------
3062WCHAR* 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
3088WCHAR* 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
3103WCHAR* 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)
3130typedef HMONITOR (WINAPI* LPMONITORFROMWINDOW)(HWND, DWORD);
3131typedef BOOL     (WINAPI* LPGETMONITORINFO)(HMONITOR, LPMONITORINFO);
3132
3133BOOL 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
3167HMONITOR 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//--------------------------------------------------------------------------------------
3190void 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//--------------------------------------------------------------------------------------
3210IDirect3DDevice9* 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
3239typedef DWORD (WINAPI* LPXINPUTGETSTATE)(DWORD dwUserIndex, XINPUT_STATE* pState );
3240typedef DWORD (WINAPI* LPXINPUTSETSTATE)(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration );
3241typedef DWORD (WINAPI* LPXINPUTGETCAPABILITIES)( DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities );
3242
3243
3244
3245//--------------------------------------------------------------------------------------
3246// Does extra processing on XInput data to make it slightly more convenient to use
3247//--------------------------------------------------------------------------------------
3248HRESULT DXUTGetGamepadState( DWORD dwPort, DXUT_GAMEPAD* pGamePad, bool bThumbstickDeadZone, bool bSnapThumbstickToCardinals )
3249{
3250    if( dwPort >= DXUT_MAX_CONTROLLERS || pGamePad == NULL )
3251        return E_FAIL;
3252
3253    static LPXINPUTGETSTATE s_pXInputGetState = NULL;
3254    static LPXINPUTGETCAPABILITIES s_pXInputGetCapabilities = NULL;
3255    if( NULL == s_pXInputGetState || NULL == s_pXInputGetCapabilities )
3256    {
3257        WCHAR wszPath[MAX_PATH];
3258        if( GetSystemDirectory( wszPath, MAX_PATH ) )
3259        {
3260            StringCchCat( wszPath, MAX_PATH, L"\\" );
3261            StringCchCat( wszPath, MAX_PATH, XINPUT_DLL );
3262            HINSTANCE hInst = LoadLibrary( wszPath );
3263            if( hInst )
3264            {
3265                s_pXInputGetState = (LPXINPUTGETSTATE)GetProcAddress( hInst, "XInputGetState" );
3266                s_pXInputGetCapabilities = (LPXINPUTGETCAPABILITIES)GetProcAddress( hInst, "XInputGetCapabilities" );
3267            }
3268        }
3269    }
3270    if( s_pXInputGetState == NULL )
3271        return E_FAIL;
3272
3273    XINPUT_STATE InputState;
3274    DWORD dwResult = s_pXInputGetState( dwPort, &InputState );
3275
3276    // Track insertion and removals
3277    BOOL bWasConnected = pGamePad->bConnected;
3278    pGamePad->bConnected = (dwResult == ERROR_SUCCESS);
3279    pGamePad->bRemoved  = (  bWasConnected && !pGamePad->bConnected );
3280    pGamePad->bInserted = ( !bWasConnected &&  pGamePad->bConnected );
3281
3282    // Don't update rest of the state if not connected
3283    if( !pGamePad->bConnected )
3284        return S_OK;
3285
3286    // Store the capabilities of the device
3287    if( pGamePad->bInserted )
3288    {
3289        ZeroMemory( pGamePad, sizeof(DXUT_GAMEPAD) );
3290        pGamePad->bConnected = true;
3291        pGamePad->bInserted  = true;
3292        if( s_pXInputGetCapabilities )
3293            s_pXInputGetCapabilities( dwPort, XINPUT_DEVTYPE_GAMEPAD, &pGamePad->caps );
3294    }
3295
3296    // Copy gamepad to local structure (assumes that XINPUT_GAMEPAD at the front in CONTROLER_STATE)
3297    memcpy( pGamePad, &InputState.Gamepad, sizeof(XINPUT_GAMEPAD) );
3298
3299    if( bSnapThumbstickToCardinals )
3300    {
3301        // Apply deadzone to each axis independantly to slightly snap to up/down/left/right
3302        if( pGamePad->sThumbLX < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE && pGamePad->sThumbLX > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE )
3303            pGamePad->sThumbLX = 0;
3304        if( pGamePad->sThumbLY < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE && pGamePad->sThumbLY > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE )
3305            pGamePad->sThumbLY = 0;
3306        if( pGamePad->sThumbRX < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE && pGamePad->sThumbRX > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE )
3307            pGamePad->sThumbRX = 0;
3308        if( pGamePad->sThumbRY < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE && pGamePad->sThumbRY > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE )
3309            pGamePad->sThumbRY = 0;
3310    }
3311    else if( bThumbstickDeadZone )
3312    {
3313        // Apply deadzone if centered
3314        if( (pGamePad->sThumbLX < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE && pGamePad->sThumbLX > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) &&
3315            (pGamePad->sThumbLY < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE && pGamePad->sThumbLY > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) )
3316        {   
3317            pGamePad->sThumbLX = 0;
3318            pGamePad->sThumbLY = 0;
3319        }
3320        if( (pGamePad->sThumbRX < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE && pGamePad->sThumbRX > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) &&
3321            (pGamePad->sThumbRY < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE && pGamePad->sThumbRY > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) )
3322        {
3323            pGamePad->sThumbRX = 0;
3324            pGamePad->sThumbRY = 0;
3325        }
3326    }
3327
3328    // Convert [-1,+1] range
3329    pGamePad->fThumbLX = pGamePad->sThumbLX / 32767.0f;
3330    pGamePad->fThumbLY = pGamePad->sThumbLY / 32767.0f;
3331    pGamePad->fThumbRX = pGamePad->sThumbRX / 32767.0f;
3332    pGamePad->fThumbRY = pGamePad->sThumbRY / 32767.0f;
3333
3334    // Get the boolean buttons that have been pressed since the last call.
3335    // Each button is represented by one bit.
3336    pGamePad->wPressedButtons = ( pGamePad->wLastButtons ^ pGamePad->wButtons ) & pGamePad->wButtons;
3337    pGamePad->wLastButtons    = pGamePad->wButtons;
3338
3339    // Figure out if the left trigger has been pressed or released
3340    bool bPressed = ( pGamePad->bLeftTrigger > DXUT_GAMEPAD_TRIGGER_THRESHOLD );
3341    pGamePad->bPressedLeftTrigger = ( bPressed ) ? !pGamePad->bLastLeftTrigger : false;
3342    pGamePad->bLastLeftTrigger = bPressed;
3343
3344    // Figure out if the right trigger has been pressed or released
3345    bPressed = ( pGamePad->bRightTrigger > DXUT_GAMEPAD_TRIGGER_THRESHOLD );
3346    pGamePad->bPressedRightTrigger = ( bPressed ) ? !pGamePad->bLastRightTrigger : false;
3347    pGamePad->bLastRightTrigger = bPressed;
3348
3349    return S_OK;
3350}
3351
3352
3353//--------------------------------------------------------------------------------------
3354// Don't pause the game or deactive the window without first stopping rumble otherwise
3355// the controller will continue to rumble
3356//--------------------------------------------------------------------------------------
3357HRESULT DXUTStopRumbleOnAllControllers()
3358{
3359    static LPXINPUTSETSTATE s_pXInputSetState = NULL;
3360    if( NULL == s_pXInputSetState )
3361    {
3362        WCHAR wszPath[MAX_PATH];
3363        if( GetSystemDirectory( wszPath, MAX_PATH ) )
3364        {
3365            StringCchCat( wszPath, MAX_PATH, L"\\" );
3366            StringCchCat( wszPath, MAX_PATH, XINPUT_DLL );
3367            HINSTANCE hInst = LoadLibrary( wszPath );
3368            if( hInst )
3369                s_pXInputSetState = (LPXINPUTSETSTATE)GetProcAddress( hInst, "XInputSetState" );
3370        }
3371    }
3372    if( s_pXInputSetState == NULL )
3373        return E_FAIL;
3374
3375    XINPUT_VIBRATION vibration;
3376    vibration.wLeftMotorSpeed  = 0;
3377    vibration.wRightMotorSpeed = 0;
3378    for( int iUserIndex=0; iUserIndex<DXUT_MAX_CONTROLLERS; iUserIndex++ )
3379        s_pXInputSetState( iUserIndex, &vibration );
3380
3381    return S_OK;
3382}
3383
3384
3385//--------------------------------------------------------------------------------------
3386// Helper function to launch the Media Center UI after the program terminates
3387//--------------------------------------------------------------------------------------
3388bool DXUTReLaunchMediaCenter()
3389{
3390    // Skip if not running on a Media Center
3391    if( GetSystemMetrics( 87 ) == 0 ) //  SM_MEDIACENTER == 87, but is only defined if _WIN32_WINNT >= 0x0501
3392        return false;
3393 
3394    // Get the path to Media Center
3395    WCHAR szExpandedPath[MAX_PATH];
3396    if( !ExpandEnvironmentStrings( L"%SystemRoot%\\ehome\\ehshell.exe", szExpandedPath, MAX_PATH) )
3397        return false;
3398
3399    // Skip if ehshell.exe doesn't exist
3400    if( GetFileAttributes( szExpandedPath ) == 0xFFFFFFFF )
3401        return false;
3402 
3403    // Launch ehshell.exe
3404    INT_PTR result = (INT_PTR)ShellExecute( NULL, TEXT("open"), szExpandedPath, NULL, NULL, SW_SHOWNORMAL);
3405    return (result > 32);
3406}
Note: See TracBrowser for help on using the repository browser.