source: GTP/branches/IllumWPdeliver2008dec/IlluminationWP/demos/Standalone/DepthOfField [DirectX]/Common/DXUTmisc.cpp @ 3255

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