source: GTP/trunk/App/Demos/Illum/Glow/Common/DXUTmisc.cpp @ 846

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