source: GTP/trunk/App/Demos/Illum/StochasticIteration/Common/DXUTmisc.cpp @ 1808

Revision 1808, 102.9 KB checked in by szirmay, 18 years ago (diff)
Line 
1//--------------------------------------------------------------------------------------
2// File: DXUTMisc.cpp
3//
4// Shortcut macros and functions for using DX objects
5//
6// Copyright (c) Microsoft Corporation. All rights reserved
7//--------------------------------------------------------------------------------------
8#include "dxstdafx.h"
9
10//--------------------------------------------------------------------------------------
11// Global/Static Members
12//--------------------------------------------------------------------------------------
13CDXUTResourceCache& DXUTGetGlobalResourceCache()
14{
15    // Using an accessor function gives control of the construction order
16    static CDXUTResourceCache cache;
17    return cache;
18}
19CDXUTTimer* DXUTGetGlobalTimer()
20{
21    // Using an accessor function gives control of the construction order
22    static CDXUTTimer timer;
23    return &timer;
24}
25
26
27//--------------------------------------------------------------------------------------
28// Internal functions forward declarations
29//--------------------------------------------------------------------------------------
30bool DXUTFindMediaSearchTypicalDirs( WCHAR* strSearchPath, int cchSearch, LPCWSTR strLeaf, WCHAR* strExePath, WCHAR* strExeName, LPCWSTR strMediaDir );
31bool DXUTFindMediaSearchParentDirs( WCHAR* strSearchPath, int cchSearch, WCHAR* strStartAt, WCHAR* strLeafName );
32
33
34//--------------------------------------------------------------------------------------
35CDXUTTimer::CDXUTTimer()
36{
37    m_bUsingQPF         = false;
38    m_bTimerStopped     = true;
39    m_llQPFTicksPerSec  = 0;
40
41    m_llStopTime        = 0;
42    m_llLastElapsedTime = 0;
43    m_llBaseTime        = 0;
44
45    // Use QueryPerformanceFrequency() to get frequency of timer. 
46    LARGE_INTEGER qwTicksPerSec;
47    m_bUsingQPF = (bool) (QueryPerformanceFrequency( &qwTicksPerSec ) != 0);
48    m_llQPFTicksPerSec = qwTicksPerSec.QuadPart;
49}
50
51
52//--------------------------------------------------------------------------------------
53void CDXUTTimer::Reset()
54{
55    if( !m_bUsingQPF )
56        return;
57
58    // Get either the current time or the stop time
59    LARGE_INTEGER qwTime;
60    if( m_llStopTime != 0 )
61        qwTime.QuadPart = m_llStopTime;
62    else
63        QueryPerformanceCounter( &qwTime );
64
65    m_llBaseTime        = qwTime.QuadPart;
66    m_llLastElapsedTime = qwTime.QuadPart;
67    m_llStopTime        = 0;
68    m_bTimerStopped     = FALSE;
69}
70
71
72//--------------------------------------------------------------------------------------
73void CDXUTTimer::Start()
74{
75    if( !m_bUsingQPF )
76        return;
77
78    // Get the current time
79    LARGE_INTEGER qwTime;
80    QueryPerformanceCounter( &qwTime );
81
82    if( m_bTimerStopped )
83        m_llBaseTime += qwTime.QuadPart - m_llStopTime;
84    m_llStopTime = 0;
85    m_llLastElapsedTime = qwTime.QuadPart;
86    m_bTimerStopped = FALSE;
87}
88
89
90//--------------------------------------------------------------------------------------
91void CDXUTTimer::Stop()
92{
93    if( !m_bUsingQPF )
94        return;
95
96    if( !m_bTimerStopped )
97    {
98        // Get either the current time or the stop time
99        LARGE_INTEGER qwTime;
100        if( m_llStopTime != 0 )
101            qwTime.QuadPart = m_llStopTime;
102        else
103            QueryPerformanceCounter( &qwTime );
104
105        m_llStopTime = qwTime.QuadPart;
106        m_llLastElapsedTime = qwTime.QuadPart;
107        m_bTimerStopped = TRUE;
108    }
109}
110
111
112//--------------------------------------------------------------------------------------
113void CDXUTTimer::Advance()
114{
115    if( !m_bUsingQPF )
116        return;
117
118    m_llStopTime += m_llQPFTicksPerSec/10;
119}
120
121
122//--------------------------------------------------------------------------------------
123double CDXUTTimer::GetAbsoluteTime()
124{
125    if( !m_bUsingQPF )
126        return -1.0;
127
128    // Get either the current time or the stop time
129    LARGE_INTEGER qwTime;
130    if( m_llStopTime != 0 )
131        qwTime.QuadPart = m_llStopTime;
132    else
133        QueryPerformanceCounter( &qwTime );
134
135    double fTime = qwTime.QuadPart / (double) m_llQPFTicksPerSec;
136
137    return fTime;
138}
139
140
141//--------------------------------------------------------------------------------------
142double CDXUTTimer::GetTime()
143{
144    if( !m_bUsingQPF )
145        return -1.0;
146
147    // Get either the current time or the stop time
148    LARGE_INTEGER qwTime;
149    if( m_llStopTime != 0 )
150        qwTime.QuadPart = m_llStopTime;
151    else
152        QueryPerformanceCounter( &qwTime );
153
154    double fAppTime = (double) ( qwTime.QuadPart - m_llBaseTime ) / (double) m_llQPFTicksPerSec;
155
156    return fAppTime;
157}
158
159
160//--------------------------------------------------------------------------------------
161double CDXUTTimer::GetElapsedTime()
162{
163    if( !m_bUsingQPF )
164        return -1.0;
165
166    // Get either the current time or the stop time
167    LARGE_INTEGER qwTime;
168    if( m_llStopTime != 0 )
169        qwTime.QuadPart = m_llStopTime;
170    else
171        QueryPerformanceCounter( &qwTime );
172
173    double fElapsedTime = (double) ( qwTime.QuadPart - m_llLastElapsedTime ) / (double) m_llQPFTicksPerSec;
174    m_llLastElapsedTime = qwTime.QuadPart;
175
176    return fElapsedTime;
177}
178
179
180//--------------------------------------------------------------------------------------
181bool CDXUTTimer::IsStopped()
182{
183    return m_bTimerStopped;
184}
185
186
187
188//--------------------------------------------------------------------------------------
189// Returns the DirectX SDK media path
190//       cchDest is the size in WCHARs of strDest.  Be careful not to
191//       pass in sizeof(strDest) on UNICODE builds.
192//--------------------------------------------------------------------------------------
193HRESULT DXUTGetDXSDKMediaPathCch( WCHAR* strDest, int cchDest )
194{
195    if( strDest == NULL || cchDest < 1 )
196        return E_INVALIDARG;
197
198    StringCchCopy( strDest, cchDest, TEXT("") );
199
200    // Open the appropriate registry key
201    HKEY  hKey;
202    LONG lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
203                                L"Software\\Microsoft\\DirectX SDK",
204                                0, KEY_READ, &hKey );
205    if( ERROR_SUCCESS != lResult )
206        return E_FAIL;
207
208    DWORD dwType;
209    DWORD dwSize = cchDest * sizeof(WCHAR);
210    lResult = RegQueryValueEx( hKey, L"DX9D4SDK Samples Path", NULL,
211                              &dwType, (BYTE*)strDest, &dwSize );
212    strDest[cchDest-1] = 0; // RegQueryValueEx doesn't NULL term if buffer too small
213    RegCloseKey( hKey );
214
215    if( ERROR_SUCCESS != lResult )
216        return E_FAIL;
217
218    const WCHAR* strMedia = L"\\Media\\";
219    if( lstrlen(strDest) + lstrlen(strMedia) < cchDest )
220        StringCchCat( strDest, cchDest, strMedia );
221    else
222        return E_INVALIDARG;
223
224    return S_OK;
225}
226
227
228//--------------------------------------------------------------------------------------
229// Tries to find the location of a SDK media file
230//       cchDest is the size in WCHARs of strDestPath.  Be careful not to
231//       pass in sizeof(strDest) on UNICODE builds.
232//--------------------------------------------------------------------------------------
233HRESULT DXUTFindDXSDKMediaFileCch( WCHAR* strDestPath, int cchDest, LPCWSTR strFilename )
234{
235    bool bFound;
236    WCHAR strSearchFor[MAX_PATH];
237   
238    if( NULL==strFilename || strFilename[0] == 0 || NULL==strDestPath || cchDest < 10 )
239        return E_INVALIDARG;
240
241    // Get the DirectX SDK's media dir if the SDK is installed
242    WCHAR strMediaDir[MAX_PATH] = {0};
243    DXUTGetDXSDKMediaPathCch( strMediaDir, MAX_PATH );
244
245    // Get the exe name, and exe path
246    WCHAR strExePath[MAX_PATH] = {0};
247    WCHAR strExeName[MAX_PATH] = {0};
248    WCHAR* strLastSlash = NULL;
249    GetModuleFileName( NULL, strExePath, MAX_PATH );
250    strExePath[MAX_PATH-1]=0;
251    strLastSlash = wcsrchr( strExePath, TEXT('\\') );
252    if( strLastSlash )
253    {
254        StringCchCopy( strExeName, MAX_PATH, &strLastSlash[1] );
255
256        // Chop the exe name from the exe path
257        *strLastSlash = 0;
258
259        // Chop the .exe from the exe name
260        strLastSlash = wcsrchr( strExeName, TEXT('.') );
261        if( strLastSlash )
262            *strLastSlash = 0;
263    }
264
265    // Typical directories:
266    //      .\
267    //      ..\
268    //      ..\..\
269    //      %EXE_DIR%\
270    //      %EXE_DIR%\..\
271    //      %EXE_DIR%\..\..\
272    //      %EXE_DIR%\..\%EXE_NAME%
273    //      %EXE_DIR%\..\..\%EXE_NAME%
274    //      DXSDK media path
275
276    // Typical directory search
277    bFound = DXUTFindMediaSearchTypicalDirs( strDestPath, cchDest, strFilename, strExePath, strExeName, strMediaDir );
278    if( bFound )
279        return S_OK;
280
281    // Typical directory search again, but also look in a subdir called "\media\"
282    StringCchPrintf( strSearchFor, MAX_PATH, L"media\\%s", strFilename );
283    bFound = DXUTFindMediaSearchTypicalDirs( strDestPath, cchDest, strSearchFor, strExePath, strExeName, strMediaDir );
284    if( bFound )
285        return S_OK;
286
287    WCHAR strLeafName[MAX_PATH] = {0};
288
289    // Search all parent directories starting at .\ and using strFilename as the leaf name
290    StringCchCopy( strLeafName, MAX_PATH, strFilename );
291    bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, L".", strLeafName );
292    if( bFound )
293        return S_OK;
294
295    // Search all parent directories starting at the exe's dir and using strFilename as the leaf name
296    bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, strExePath, strLeafName );
297    if( bFound )
298        return S_OK;
299
300    // Search all parent directories starting at .\ and using "media\strFilename" as the leaf name
301    StringCchPrintf( strLeafName, MAX_PATH, L"media\\%s", strFilename );
302    bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, L".", strLeafName );
303    if( bFound )
304        return S_OK;
305
306    // Search all parent directories starting at the exe's dir and using "media\strFilename" as the leaf name
307    bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, strExePath, strLeafName );
308    if( bFound )
309        return S_OK;
310
311    // On failure, return the file as the path but also return an error code
312    StringCchCopy( strDestPath, cchDest, strFilename );
313
314    return DXUTERR_MEDIANOTFOUND;
315}
316
317
318//--------------------------------------------------------------------------------------
319// Search a set of typical directories
320//--------------------------------------------------------------------------------------
321bool DXUTFindMediaSearchTypicalDirs( WCHAR* strSearchPath, int cchSearch, LPCWSTR strLeaf,
322                                     WCHAR* strExePath, WCHAR* strExeName, LPCWSTR strMediaDir )
323{
324    // Typical directories:
325    //      .\
326    //      ..\
327    //      ..\..\
328    //      %EXE_DIR%\
329    //      %EXE_DIR%\..\
330    //      %EXE_DIR%\..\..\
331    //      %EXE_DIR%\..\%EXE_NAME%
332    //      %EXE_DIR%\..\..\%EXE_NAME%
333    //      DXSDK media path
334
335    // Search in .\ 
336    StringCchCopy( strSearchPath, cchSearch, strLeaf );
337    if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
338        return true;
339
340    // Search in ..\ 
341    StringCchPrintf( strSearchPath, cchSearch, L"..\\%s", strLeaf );
342    if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
343        return true;
344
345    // Search in ..\..\
346    StringCchPrintf( strSearchPath, cchSearch, L"..\\..\\%s", strLeaf );
347    if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
348        return true;
349
350    // Search in ..\..\
351    StringCchPrintf( strSearchPath, cchSearch, L"..\\..\\%s", strLeaf );
352    if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
353        return true;
354
355    // Search in the %EXE_DIR%\
356    StringCchPrintf( strSearchPath, cchSearch, L"%s\\%s", strExePath, strLeaf );
357    if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
358        return true;
359
360    // Search in the %EXE_DIR%\..\
361    StringCchPrintf( strSearchPath, cchSearch, L"%s\\..\\%s", strExePath, strLeaf );
362    if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
363        return true;
364
365    // Search in the %EXE_DIR%\..\..\
366    StringCchPrintf( strSearchPath, cchSearch, L"%s\\..\\..\\%s", strExePath, strLeaf );
367    if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
368        return true;
369
370    // Search in "%EXE_DIR%\..\%EXE_NAME%\".  This matches the DirectX SDK layout
371    StringCchPrintf( strSearchPath, cchSearch, L"%s\\..\\%s\\%s", strExePath, strExeName, strLeaf );
372    if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
373        return true;
374
375    // Search in "%EXE_DIR%\..\..\%EXE_NAME%\".  This matches the DirectX SDK layout
376    StringCchPrintf( strSearchPath, cchSearch, L"%s\\..\\..\\%s\\%s", strExePath, strExeName, strLeaf );
377    if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
378        return true;
379
380    // Search in DirectX SDK's media dir
381    StringCchPrintf( strSearchPath, cchSearch, L"%s%s", strMediaDir, strLeaf );
382    if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
383        return true;
384
385    return false;
386}
387
388
389
390//--------------------------------------------------------------------------------------
391// Search parent directories starting at strStartAt, and appending strLeafName
392// at each parent directory.  It stops at the root directory.
393//--------------------------------------------------------------------------------------
394bool DXUTFindMediaSearchParentDirs( WCHAR* strSearchPath, int cchSearch, WCHAR* strStartAt, WCHAR* strLeafName )
395{
396    WCHAR strFullPath[MAX_PATH] = {0};
397    WCHAR strFullFileName[MAX_PATH] = {0};
398    WCHAR strSearch[MAX_PATH] = {0};
399    WCHAR* strFilePart = NULL;
400
401    GetFullPathName( strStartAt, MAX_PATH, strFullPath, &strFilePart );
402    if( strFilePart == NULL )
403        return false;
404   
405    while( strFilePart != NULL && *strFilePart != '\0' )
406    {
407        StringCchPrintf( strFullFileName, MAX_PATH, L"%s\\%s", strFullPath, strLeafName );
408        if( GetFileAttributes( strFullFileName ) != 0xFFFFFFFF )
409        {
410            StringCchCopy( strSearchPath, cchSearch, strFullFileName );
411            return true;
412        }
413
414        StringCchPrintf( strSearch, MAX_PATH, L"%s\\..", strFullPath );
415        GetFullPathName( strSearch, MAX_PATH, strFullPath, &strFilePart );
416    }
417
418    return false;
419}
420
421
422//--------------------------------------------------------------------------------------
423// CDXUTResourceCache
424//--------------------------------------------------------------------------------------
425
426
427CDXUTResourceCache::~CDXUTResourceCache()
428{
429    OnDestroyDevice();
430
431    m_TextureCache.RemoveAll();
432    m_EffectCache.RemoveAll();
433    m_FontCache.RemoveAll();
434}
435
436
437HRESULT CDXUTResourceCache::CreateTextureFromFile( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, LPDIRECT3DTEXTURE9 *ppTexture )
438{
439    return CreateTextureFromFileEx( pDevice, pSrcFile, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
440                                    0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT,
441                                    0, NULL, NULL, ppTexture );
442}
443
444
445//--------------------------------------------------------------------------------------
446HRESULT 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 )
447{
448    // Search the cache for a matching entry.
449    for( int i = 0; i < m_TextureCache.GetSize(); ++i )
450    {
451        DXUTCache_Texture &Entry = m_TextureCache[i];
452        if( Entry.Location == DXUTCACHE_LOCATION_FILE &&
453            !lstrcmpW( Entry.wszSource, pSrcFile ) &&
454            Entry.Width == Width &&
455            Entry.Height == Height &&
456            Entry.MipLevels == MipLevels &&
457            Entry.Usage == Usage &&
458            Entry.Format == Format &&
459            Entry.Pool == Pool &&
460            Entry.Type == D3DRTYPE_TEXTURE )
461        {
462            // A match is found. Obtain the IDirect3DTexture9 interface and return that.
463            return Entry.pTexture->QueryInterface( IID_IDirect3DTexture9, (LPVOID*)ppTexture );
464        }
465    }
466
467    HRESULT hr;
468
469    // No matching entry.  Load the resource and create a new entry.
470    hr = D3DXCreateTextureFromFileEx( pDevice, pSrcFile, Width, Height, MipLevels, Usage, Format,
471                                      Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppTexture );
472    if( FAILED( hr ) )
473        return hr;
474
475    DXUTCache_Texture NewEntry;
476    NewEntry.Location = DXUTCACHE_LOCATION_FILE;
477    StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcFile );
478    NewEntry.Width = Width;
479    NewEntry.Height = Height;
480    NewEntry.MipLevels = MipLevels;
481    NewEntry.Usage = Usage;
482    NewEntry.Format = Format;
483    NewEntry.Pool = Pool;
484    NewEntry.Type = D3DRTYPE_TEXTURE;
485    (*ppTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
486
487    m_TextureCache.Add( NewEntry );
488    return S_OK;
489}
490
491
492//--------------------------------------------------------------------------------------
493HRESULT CDXUTResourceCache::CreateTextureFromResource( LPDIRECT3DDEVICE9 pDevice, HMODULE hSrcModule, LPCTSTR pSrcResource, LPDIRECT3DTEXTURE9 *ppTexture )
494{
495    return CreateTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, D3DX_DEFAULT, D3DX_DEFAULT,
496                                        D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT,
497                                        D3DX_DEFAULT, 0, NULL, NULL, ppTexture );
498}
499
500
501//--------------------------------------------------------------------------------------
502HRESULT 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 )
503{
504    // Search the cache for a matching entry.
505    for( int i = 0; i < m_TextureCache.GetSize(); ++i )
506    {
507        DXUTCache_Texture &Entry = m_TextureCache[i];
508        if( Entry.Location == DXUTCACHE_LOCATION_RESOURCE &&
509            Entry.hSrcModule == hSrcModule &&
510            !lstrcmpW( Entry.wszSource, pSrcResource ) &&
511            Entry.Width == Width &&
512            Entry.Height == Height &&
513            Entry.MipLevels == MipLevels &&
514            Entry.Usage == Usage &&
515            Entry.Format == Format &&
516            Entry.Pool == Pool &&
517            Entry.Type == D3DRTYPE_TEXTURE )
518        {
519            // A match is found. Obtain the IDirect3DTexture9 interface and return that.
520            return Entry.pTexture->QueryInterface( IID_IDirect3DTexture9, (LPVOID*)ppTexture );
521        }
522    }
523
524    HRESULT hr;
525
526    // No matching entry.  Load the resource and create a new entry.
527    hr = D3DXCreateTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, Width, Height, MipLevels, Usage,
528                                          Format, Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppTexture );
529    if( FAILED( hr ) )
530        return hr;
531
532    DXUTCache_Texture NewEntry;
533    NewEntry.Location = DXUTCACHE_LOCATION_RESOURCE;
534    NewEntry.hSrcModule = hSrcModule;
535    StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcResource );
536    NewEntry.Width = Width;
537    NewEntry.Height = Height;
538    NewEntry.MipLevels = MipLevels;
539    NewEntry.Usage = Usage;
540    NewEntry.Format = Format;
541    NewEntry.Pool = Pool;
542    NewEntry.Type = D3DRTYPE_TEXTURE;
543    (*ppTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
544
545    m_TextureCache.Add( NewEntry );
546    return S_OK;
547}
548
549
550//--------------------------------------------------------------------------------------
551HRESULT CDXUTResourceCache::CreateCubeTextureFromFile( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, LPDIRECT3DCUBETEXTURE9 *ppCubeTexture )
552{
553    return CreateCubeTextureFromFileEx( pDevice, pSrcFile, D3DX_DEFAULT, D3DX_DEFAULT, 0,
554                                        D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT,
555                                        0, NULL, NULL, ppCubeTexture );
556}
557
558
559//--------------------------------------------------------------------------------------
560HRESULT 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 )
561{
562    // Search the cache for a matching entry.
563    for( int i = 0; i < m_TextureCache.GetSize(); ++i )
564    {
565        DXUTCache_Texture &Entry = m_TextureCache[i];
566        if( Entry.Location == DXUTCACHE_LOCATION_FILE &&
567            !lstrcmpW( Entry.wszSource, pSrcFile ) &&
568            Entry.Width == Size &&
569            Entry.MipLevels == MipLevels &&
570            Entry.Usage == Usage &&
571            Entry.Format == Format &&
572            Entry.Pool == Pool &&
573            Entry.Type == D3DRTYPE_CUBETEXTURE )
574        {
575            // A match is found. Obtain the IDirect3DCubeTexture9 interface and return that.
576            return Entry.pTexture->QueryInterface( IID_IDirect3DCubeTexture9, (LPVOID*)ppCubeTexture );
577        }
578    }
579
580    HRESULT hr;
581
582    // No matching entry.  Load the resource and create a new entry.
583    hr = D3DXCreateCubeTextureFromFileEx( pDevice, pSrcFile, Size, MipLevels, Usage, Format, Pool, Filter,
584                                          MipFilter, ColorKey, pSrcInfo, pPalette, ppCubeTexture );
585    if( FAILED( hr ) )
586        return hr;
587
588    DXUTCache_Texture NewEntry;
589    NewEntry.Location = DXUTCACHE_LOCATION_FILE;
590    StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcFile );
591    NewEntry.Width = Size;
592    NewEntry.MipLevels = MipLevels;
593    NewEntry.Usage = Usage;
594    NewEntry.Format = Format;
595    NewEntry.Pool = Pool;
596    NewEntry.Type = D3DRTYPE_CUBETEXTURE;
597    (*ppCubeTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
598
599    m_TextureCache.Add( NewEntry );
600    return S_OK;
601}
602
603
604//--------------------------------------------------------------------------------------
605HRESULT CDXUTResourceCache::CreateCubeTextureFromResource( LPDIRECT3DDEVICE9 pDevice, HMODULE hSrcModule, LPCTSTR pSrcResource, LPDIRECT3DCUBETEXTURE9 *ppCubeTexture )
606{
607    return CreateCubeTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, D3DX_DEFAULT, D3DX_DEFAULT,
608                                            0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT,
609                                            0, NULL, NULL, ppCubeTexture );
610}
611
612
613//--------------------------------------------------------------------------------------
614HRESULT 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 )
615{
616    // Search the cache for a matching entry.
617    for( int i = 0; i < m_TextureCache.GetSize(); ++i )
618    {
619        DXUTCache_Texture &Entry = m_TextureCache[i];
620        if( Entry.Location == DXUTCACHE_LOCATION_RESOURCE &&
621            Entry.hSrcModule == hSrcModule &&
622            !lstrcmpW( Entry.wszSource, pSrcResource ) &&
623            Entry.Width == Size &&
624            Entry.MipLevels == MipLevels &&
625            Entry.Usage == Usage &&
626            Entry.Format == Format &&
627            Entry.Pool == Pool &&
628            Entry.Type == D3DRTYPE_CUBETEXTURE )
629        {
630            // A match is found. Obtain the IDirect3DCubeTexture9 interface and return that.
631            return Entry.pTexture->QueryInterface( IID_IDirect3DCubeTexture9, (LPVOID*)ppCubeTexture );
632        }
633    }
634
635    HRESULT hr;
636
637    // No matching entry.  Load the resource and create a new entry.
638    hr = D3DXCreateCubeTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, Size, MipLevels, Usage, Format,
639                                              Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppCubeTexture );
640    if( FAILED( hr ) )
641        return hr;
642
643    DXUTCache_Texture NewEntry;
644    NewEntry.Location = DXUTCACHE_LOCATION_RESOURCE;
645    NewEntry.hSrcModule = hSrcModule;
646    StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcResource );
647    NewEntry.Width = Size;
648    NewEntry.MipLevels = MipLevels;
649    NewEntry.Usage = Usage;
650    NewEntry.Format = Format;
651    NewEntry.Pool = Pool;
652    NewEntry.Type = D3DRTYPE_CUBETEXTURE;
653    (*ppCubeTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
654
655    m_TextureCache.Add( NewEntry );
656    return S_OK;
657}
658
659
660//--------------------------------------------------------------------------------------
661HRESULT CDXUTResourceCache::CreateVolumeTextureFromFile( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, LPDIRECT3DVOLUMETEXTURE9 *ppVolumeTexture )
662{
663    return CreateVolumeTextureFromFileEx( pDevice, pSrcFile, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
664                                          0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT,
665                                          0, NULL, NULL, ppVolumeTexture );
666}
667
668
669//--------------------------------------------------------------------------------------
670HRESULT 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 )
671{
672    // Search the cache for a matching entry.
673    for( int i = 0; i < m_TextureCache.GetSize(); ++i )
674    {
675        DXUTCache_Texture &Entry = m_TextureCache[i];
676        if( Entry.Location == DXUTCACHE_LOCATION_FILE &&
677            !lstrcmpW( Entry.wszSource, pSrcFile ) &&
678            Entry.Width == Width &&
679            Entry.Height == Height &&
680            Entry.Depth == Depth &&
681            Entry.MipLevels == MipLevels &&
682            Entry.Usage == Usage &&
683            Entry.Format == Format &&
684            Entry.Pool == Pool &&
685            Entry.Type == D3DRTYPE_VOLUMETEXTURE )
686        {
687            // A match is found. Obtain the IDirect3DVolumeTexture9 interface and return that.
688            return Entry.pTexture->QueryInterface( IID_IDirect3DVolumeTexture9, (LPVOID*)ppTexture );
689        }
690    }
691
692    HRESULT hr;
693
694    // No matching entry.  Load the resource and create a new entry.
695    hr = D3DXCreateVolumeTextureFromFileEx( pDevice, pSrcFile, Width, Height, Depth, MipLevels, Usage, Format,
696                                            Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppTexture );
697    if( FAILED( hr ) )
698        return hr;
699
700    DXUTCache_Texture NewEntry;
701    NewEntry.Location = DXUTCACHE_LOCATION_FILE;
702    StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcFile );
703    NewEntry.Width = Width;
704    NewEntry.Height = Height;
705    NewEntry.Depth = Depth;
706    NewEntry.MipLevels = MipLevels;
707    NewEntry.Usage = Usage;
708    NewEntry.Format = Format;
709    NewEntry.Pool = Pool;
710    NewEntry.Type = D3DRTYPE_VOLUMETEXTURE;
711    (*ppTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
712
713    m_TextureCache.Add( NewEntry );
714    return S_OK;
715}
716
717
718//--------------------------------------------------------------------------------------
719HRESULT CDXUTResourceCache::CreateVolumeTextureFromResource( LPDIRECT3DDEVICE9 pDevice, HMODULE hSrcModule, LPCTSTR pSrcResource, LPDIRECT3DVOLUMETEXTURE9 *ppVolumeTexture )
720{
721    return CreateVolumeTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, D3DX_DEFAULT, D3DX_DEFAULT,
722                                              D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
723                                              D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, ppVolumeTexture );
724}
725
726
727//--------------------------------------------------------------------------------------
728HRESULT 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 )
729{
730    // Search the cache for a matching entry.
731    for( int i = 0; i < m_TextureCache.GetSize(); ++i )
732    {
733        DXUTCache_Texture &Entry = m_TextureCache[i];
734        if( Entry.Location == DXUTCACHE_LOCATION_RESOURCE &&
735            Entry.hSrcModule == hSrcModule &&
736            !lstrcmpW( Entry.wszSource, pSrcResource ) &&
737            Entry.Width == Width &&
738            Entry.Height == Height &&
739            Entry.Depth == Depth &&
740            Entry.MipLevels == MipLevels &&
741            Entry.Usage == Usage &&
742            Entry.Format == Format &&
743            Entry.Pool == Pool &&
744            Entry.Type == D3DRTYPE_VOLUMETEXTURE )
745        {
746            // A match is found. Obtain the IDirect3DVolumeTexture9 interface and return that.
747            return Entry.pTexture->QueryInterface( IID_IDirect3DVolumeTexture9, (LPVOID*)ppVolumeTexture );
748        }
749    }
750
751    HRESULT hr;
752
753    // No matching entry.  Load the resource and create a new entry.
754    hr = D3DXCreateVolumeTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, Width, Height, Depth, MipLevels, Usage,
755                                                Format, Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppVolumeTexture );
756    if( FAILED( hr ) )
757        return hr;
758
759    DXUTCache_Texture NewEntry;
760    NewEntry.Location = DXUTCACHE_LOCATION_RESOURCE;
761    NewEntry.hSrcModule = hSrcModule;
762    StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcResource );
763    NewEntry.Width = Width;
764    NewEntry.Height = Height;
765    NewEntry.Depth = Depth;
766    NewEntry.MipLevels = MipLevels;
767    NewEntry.Usage = Usage;
768    NewEntry.Format = Format;
769    NewEntry.Pool = Pool;
770    NewEntry.Type = D3DRTYPE_VOLUMETEXTURE;
771    (*ppVolumeTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
772
773    m_TextureCache.Add( NewEntry );
774    return S_OK;
775}
776
777
778//--------------------------------------------------------------------------------------
779HRESULT 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 )
780{
781    D3DXFONT_DESCW Desc;
782   
783    Desc.Height = Height;
784    Desc.Width = Width;
785    Desc.Weight = Weight;
786    Desc.MipLevels = MipLevels;
787    Desc.Italic = Italic;
788    Desc.CharSet = (BYTE)CharSet;
789    Desc.OutputPrecision = (BYTE)OutputPrecision;
790    Desc.Quality = (BYTE)Quality;
791    Desc.PitchAndFamily = (BYTE)PitchAndFamily;
792    StringCchCopy( Desc.FaceName, LF_FACESIZE, pFacename );
793
794    return CreateFontIndirect( pDevice, &Desc, ppFont );
795}
796
797
798//--------------------------------------------------------------------------------------
799HRESULT CDXUTResourceCache::CreateFontIndirect( LPDIRECT3DDEVICE9 pDevice, CONST D3DXFONT_DESC *pDesc, LPD3DXFONT *ppFont )
800{
801    // Search the cache for a matching entry.
802    for( int i = 0; i < m_FontCache.GetSize(); ++i )
803    {
804        DXUTCache_Font &Entry = m_FontCache[i];
805
806        if( Entry.Width == pDesc->Width &&
807            Entry.Height == pDesc->Height &&
808            Entry.Weight == pDesc->Weight &&
809            Entry.MipLevels == pDesc->MipLevels &&
810            Entry.Italic == pDesc->Italic &&
811            Entry.CharSet == pDesc->CharSet &&
812            Entry.OutputPrecision == pDesc->OutputPrecision &&
813            Entry.Quality == pDesc->Quality &&
814            Entry.PitchAndFamily == pDesc->PitchAndFamily &&
815            CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE,
816                           Entry.FaceName, -1,
817                           pDesc->FaceName, -1 ) == CSTR_EQUAL )
818        {
819            // A match is found.  Increment the reference and return the ID3DXFont object.
820            Entry.pFont->AddRef();
821            *ppFont = Entry.pFont;
822            return S_OK;
823        }
824    }
825
826    HRESULT hr;
827
828    // No matching entry.  Load the resource and create a new entry.
829    hr = D3DXCreateFontIndirect( pDevice, pDesc, ppFont );
830    if( FAILED( hr ) )
831        return hr;
832
833    DXUTCache_Font NewEntry;
834    (D3DXFONT_DESC &)NewEntry = *pDesc;
835    NewEntry.pFont = *ppFont;
836    NewEntry.pFont->AddRef();
837
838    m_FontCache.Add( NewEntry );
839    return S_OK;
840}
841
842
843//--------------------------------------------------------------------------------------
844HRESULT CDXUTResourceCache::CreateEffectFromFile( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, const D3DXMACRO *pDefines, LPD3DXINCLUDE pInclude, DWORD Flags, LPD3DXEFFECTPOOL pPool, LPD3DXEFFECT *ppEffect, LPD3DXBUFFER *ppCompilationErrors )
845{
846    // Search the cache for a matching entry.
847    for( int i = 0; i < m_EffectCache.GetSize(); ++i )
848    {
849        DXUTCache_Effect &Entry = m_EffectCache[i];
850
851        if( Entry.Location == DXUTCACHE_LOCATION_FILE &&
852            !lstrcmpW( Entry.wszSource, pSrcFile ) &&
853            Entry.dwFlags == Flags )
854        {
855            // A match is found.  Increment the ref coutn and return the ID3DXEffect object.
856            *ppEffect = Entry.pEffect;
857            (*ppEffect)->AddRef();
858            return S_OK;
859        }
860    }
861
862    HRESULT hr;
863
864    // No matching entry.  Load the resource and create a new entry.
865    hr = D3DXCreateEffectFromFile( pDevice, pSrcFile, pDefines, pInclude, Flags, pPool, ppEffect, ppCompilationErrors );
866    if( FAILED( hr ) )
867        return hr;
868
869    DXUTCache_Effect NewEntry;
870    NewEntry.Location = DXUTCACHE_LOCATION_FILE;
871    StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcFile );
872    NewEntry.dwFlags = Flags;
873    NewEntry.pEffect = *ppEffect;
874    NewEntry.pEffect->AddRef();
875
876    m_EffectCache.Add( NewEntry );
877    return S_OK;
878}
879
880
881//--------------------------------------------------------------------------------------
882HRESULT CDXUTResourceCache::CreateEffectFromResource( LPDIRECT3DDEVICE9 pDevice, HMODULE hSrcModule, LPCTSTR pSrcResource, const D3DXMACRO *pDefines, LPD3DXINCLUDE pInclude, DWORD Flags, LPD3DXEFFECTPOOL pPool, LPD3DXEFFECT *ppEffect, LPD3DXBUFFER *ppCompilationErrors )
883{
884    // Search the cache for a matching entry.
885    for( int i = 0; i < m_EffectCache.GetSize(); ++i )
886    {
887        DXUTCache_Effect &Entry = m_EffectCache[i];
888
889        if( Entry.Location == DXUTCACHE_LOCATION_RESOURCE &&
890            Entry.hSrcModule == hSrcModule &&
891            !lstrcmpW( Entry.wszSource, pSrcResource ) &&
892            Entry.dwFlags == Flags )
893        {
894            // A match is found.  Increment the ref coutn and return the ID3DXEffect object.
895            *ppEffect = Entry.pEffect;
896            (*ppEffect)->AddRef();
897            return S_OK;
898        }
899    }
900
901    HRESULT hr;
902
903    // No matching entry.  Load the resource and create a new entry.
904    hr = D3DXCreateEffectFromResource( pDevice, hSrcModule, pSrcResource, pDefines, pInclude, Flags,
905                                       pPool, ppEffect, ppCompilationErrors );
906    if( FAILED( hr ) )
907        return hr;
908
909    DXUTCache_Effect NewEntry;
910    NewEntry.Location = DXUTCACHE_LOCATION_RESOURCE;
911    NewEntry.hSrcModule = hSrcModule;
912    StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcResource );
913    NewEntry.dwFlags = Flags;
914    NewEntry.pEffect = *ppEffect;
915    NewEntry.pEffect->AddRef();
916
917    m_EffectCache.Add( NewEntry );
918    return S_OK;
919}
920
921
922//--------------------------------------------------------------------------------------
923// Device event callbacks
924//--------------------------------------------------------------------------------------
925
926
927//--------------------------------------------------------------------------------------
928HRESULT CDXUTResourceCache::OnCreateDevice( IDirect3DDevice9 *pd3dDevice )
929{
930    return S_OK;
931}
932
933
934//--------------------------------------------------------------------------------------
935HRESULT CDXUTResourceCache::OnResetDevice( IDirect3DDevice9 *pd3dDevice )
936{
937    // Call OnResetDevice on all effect and font objects
938    for( int i = 0; i < m_EffectCache.GetSize(); ++i )
939        m_EffectCache[i].pEffect->OnResetDevice();
940    for( int i = 0; i < m_FontCache.GetSize(); ++i )
941        m_FontCache[i].pFont->OnResetDevice();
942
943
944    return S_OK;
945}
946
947
948//--------------------------------------------------------------------------------------
949HRESULT CDXUTResourceCache::OnLostDevice()
950{
951    // Call OnLostDevice on all effect and font objects
952    for( int i = 0; i < m_EffectCache.GetSize(); ++i )
953        m_EffectCache[i].pEffect->OnLostDevice();
954    for( int i = 0; i < m_FontCache.GetSize(); ++i )
955        m_FontCache[i].pFont->OnLostDevice();
956
957    // Release all the default pool textures
958    for( int i = m_TextureCache.GetSize() - 1; i >= 0; --i )
959        if( m_TextureCache[i].Pool == D3DPOOL_DEFAULT )
960        {
961            SAFE_RELEASE( m_TextureCache[i].pTexture );
962            m_TextureCache.Remove( i );  // Remove the entry
963        }
964
965    return S_OK;
966}
967
968
969//--------------------------------------------------------------------------------------
970HRESULT CDXUTResourceCache::OnDestroyDevice()
971{
972    // Release all resources
973    for( int i = m_EffectCache.GetSize() - 1; i >= 0; --i )
974    {
975        SAFE_RELEASE( m_EffectCache[i].pEffect );
976        m_EffectCache.Remove( i );
977    }
978    for( int i = m_FontCache.GetSize() - 1; i >= 0; --i )
979    {
980        SAFE_RELEASE( m_FontCache[i].pFont );
981        m_FontCache.Remove( i );
982    }
983    for( int i = m_TextureCache.GetSize() - 1; i >= 0; --i )
984    {
985        SAFE_RELEASE( m_TextureCache[i].pTexture );
986        m_TextureCache.Remove( i );
987    }
988
989    return S_OK;
990}
991
992
993//--------------------------------------------------------------------------------------
994CD3DArcBall::CD3DArcBall()
995{
996    Reset();
997    m_vDownPt = D3DXVECTOR3(0,0,0);
998    m_vCurrentPt = D3DXVECTOR3(0,0,0);
999    m_Offset.x = m_Offset.y = 0;
1000
1001    RECT rc;
1002    GetClientRect( GetForegroundWindow(), &rc );
1003    SetWindow( rc.right, rc.bottom );
1004}
1005
1006
1007
1008
1009
1010//--------------------------------------------------------------------------------------
1011void CD3DArcBall::Reset()
1012{
1013    D3DXQuaternionIdentity( &m_qDown );
1014    D3DXQuaternionIdentity( &m_qNow );
1015    D3DXMatrixIdentity( &m_mRotation );
1016    D3DXMatrixIdentity( &m_mTranslation );
1017    D3DXMatrixIdentity( &m_mTranslationDelta );
1018    m_bDrag = FALSE;
1019    m_fRadiusTranslation = 1.0f;
1020    m_fRadius = 1.0f;
1021}
1022
1023
1024
1025
1026//--------------------------------------------------------------------------------------
1027D3DXVECTOR3 CD3DArcBall::ScreenToVector( float fScreenPtX, float fScreenPtY )
1028{
1029    // Scale to screen
1030    FLOAT x   = -(fScreenPtX - m_Offset.x - m_nWidth/2)  / (m_fRadius*m_nWidth/2);
1031    FLOAT y   =  (fScreenPtY - m_Offset.y - m_nHeight/2) / (m_fRadius*m_nHeight/2);
1032
1033    FLOAT z   = 0.0f;
1034    FLOAT mag = x*x + y*y;
1035
1036    if( mag > 1.0f )
1037    {
1038        FLOAT scale = 1.0f/sqrtf(mag);
1039        x *= scale;
1040        y *= scale;
1041    }
1042    else
1043        z = sqrtf( 1.0f - mag );
1044
1045    // Return vector
1046    return D3DXVECTOR3( x, y, z );
1047}
1048
1049
1050
1051
1052//--------------------------------------------------------------------------------------
1053D3DXQUATERNION CD3DArcBall::QuatFromBallPoints(const D3DXVECTOR3 &vFrom, const D3DXVECTOR3 &vTo)
1054{
1055    D3DXVECTOR3 vPart;
1056    float fDot = D3DXVec3Dot(&vFrom, &vTo);
1057    D3DXVec3Cross(&vPart, &vFrom, &vTo);
1058
1059    return D3DXQUATERNION(vPart.x, vPart.y, vPart.z, fDot);
1060}
1061
1062
1063
1064
1065//--------------------------------------------------------------------------------------
1066void CD3DArcBall::OnBegin( int nX, int nY )
1067{
1068    // Only enter the drag state if the click falls
1069    // inside the click rectangle.
1070    if( nX >= m_Offset.x &&
1071        nX < m_Offset.x + m_nWidth &&
1072        nY >= m_Offset.y &&
1073        nY < m_Offset.y + m_nHeight )
1074    {
1075        m_bDrag = true;
1076        m_qDown = m_qNow;
1077        m_vDownPt = ScreenToVector( (float)nX, (float)nY );
1078    }
1079}
1080
1081
1082
1083
1084//--------------------------------------------------------------------------------------
1085void CD3DArcBall::OnMove( int nX, int nY )
1086{
1087    if (m_bDrag)
1088    {
1089        m_vCurrentPt = ScreenToVector( (float)nX, (float)nY );
1090        m_qNow = m_qDown * QuatFromBallPoints( m_vDownPt, m_vCurrentPt );
1091    }
1092}
1093
1094
1095
1096
1097//--------------------------------------------------------------------------------------
1098void CD3DArcBall::OnEnd()
1099{
1100    m_bDrag = false;
1101}
1102
1103
1104
1105
1106//--------------------------------------------------------------------------------------
1107// Desc:
1108//--------------------------------------------------------------------------------------
1109LRESULT CD3DArcBall::HandleMessages( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1110{
1111    // Current mouse position
1112    int iMouseX = (short)LOWORD(lParam);
1113    int iMouseY = (short)HIWORD(lParam);
1114
1115    switch( uMsg )
1116    {
1117        case WM_LBUTTONDOWN:
1118        case WM_LBUTTONDBLCLK:
1119            SetCapture( hWnd );
1120            OnBegin( iMouseX, iMouseY );
1121            return TRUE;
1122
1123        case WM_LBUTTONUP:
1124            ReleaseCapture();
1125            OnEnd();
1126            return TRUE;
1127
1128        case WM_RBUTTONDOWN:
1129        case WM_RBUTTONDBLCLK:
1130        case WM_MBUTTONDOWN:
1131        case WM_MBUTTONDBLCLK:
1132            SetCapture( hWnd );
1133            // Store off the position of the cursor when the button is pressed
1134            m_ptLastMouse.x = iMouseX;
1135            m_ptLastMouse.y = iMouseY;
1136            return TRUE;
1137
1138        case WM_RBUTTONUP:
1139        case WM_MBUTTONUP:
1140            ReleaseCapture();
1141            return TRUE;
1142
1143        case WM_MOUSEMOVE:
1144            if( MK_LBUTTON&wParam )
1145            {
1146                OnMove( iMouseX, iMouseY );
1147            }
1148            else if( (MK_RBUTTON&wParam) || (MK_MBUTTON&wParam) )
1149            {
1150                // Normalize based on size of window and bounding sphere radius
1151                FLOAT fDeltaX = ( m_ptLastMouse.x-iMouseX ) * m_fRadiusTranslation / m_nWidth;
1152                FLOAT fDeltaY = ( m_ptLastMouse.y-iMouseY ) * m_fRadiusTranslation / m_nHeight;
1153
1154                if( wParam & MK_RBUTTON )
1155                {
1156                    D3DXMatrixTranslation( &m_mTranslationDelta, -2*fDeltaX, 2*fDeltaY, 0.0f );
1157                    D3DXMatrixMultiply( &m_mTranslation, &m_mTranslation, &m_mTranslationDelta );
1158                }
1159                else  // wParam & MK_MBUTTON
1160                {
1161                    D3DXMatrixTranslation( &m_mTranslationDelta, 0.0f, 0.0f, 5*fDeltaY );
1162                    D3DXMatrixMultiply( &m_mTranslation, &m_mTranslation, &m_mTranslationDelta );
1163                }
1164
1165                // Store mouse coordinate
1166                m_ptLastMouse.x = iMouseX;
1167                m_ptLastMouse.y = iMouseY;
1168            }
1169            return TRUE;
1170    }
1171
1172    return FALSE;
1173}
1174
1175
1176
1177
1178//--------------------------------------------------------------------------------------
1179// Constructor
1180//--------------------------------------------------------------------------------------
1181CBaseCamera::CBaseCamera()
1182{
1183    ZeroMemory( m_aKeys, sizeof(BYTE)*CAM_MAX_KEYS );
1184
1185    // Set attributes for the view matrix
1186    D3DXVECTOR3 vEyePt    = D3DXVECTOR3(0.0f,0.0f,0.0f);
1187    D3DXVECTOR3 vLookatPt = D3DXVECTOR3(0.0f,0.0f,1.0f);
1188
1189    // Setup the view matrix
1190    SetViewParams( &vEyePt, &vLookatPt );
1191
1192    // Setup the projection matrix
1193    SetProjParams( D3DX_PI/4, 1.0f, 1.0f, 1000.0f );
1194
1195    GetCursorPos( &m_ptLastMousePosition );
1196    m_bMouseLButtonDown = false;
1197    m_bMouseMButtonDown = false;
1198    m_bMouseRButtonDown = false;
1199    m_nCurrentButtonMask = 0;
1200    m_nMouseWheelDelta = 0;
1201
1202    m_fCameraYawAngle = 0.0f;
1203    m_fCameraPitchAngle = 0.0f;
1204
1205    SetRect( &m_rcDrag, LONG_MIN, LONG_MIN, LONG_MAX, LONG_MAX );
1206    m_vVelocity     = D3DXVECTOR3(0,0,0);
1207    m_bMovementDrag = false;
1208    m_vVelocityDrag = D3DXVECTOR3(0,0,0);
1209    m_fDragTimer    = 0.0f;
1210    m_fTotalDragTimeToZero = 0.25;
1211    m_vRotVelocity = D3DXVECTOR2(0,0);
1212
1213    m_fRotationScaler = 0.01f;           
1214    m_fMoveScaler = 5.0f;           
1215
1216    m_bInvertPitch = false;
1217    m_bEnableYAxisMovement = true;
1218    m_bEnablePositionMovement = true;
1219
1220    m_vMouseDelta   = D3DXVECTOR2(0,0);
1221    m_fFramesToSmoothMouseData = 2.0f;
1222
1223    m_bClipToBoundary = false;
1224    m_vMinBoundary = D3DXVECTOR3(-1,-1,-1);
1225    m_vMaxBoundary = D3DXVECTOR3(1,1,1);
1226
1227    m_bResetCursorAfterMove = false;
1228}
1229
1230
1231//--------------------------------------------------------------------------------------
1232// Client can call this to change the position and direction of camera
1233//--------------------------------------------------------------------------------------
1234VOID CBaseCamera::SetViewParams( D3DXVECTOR3* pvEyePt, D3DXVECTOR3* pvLookatPt )
1235{
1236    if( NULL == pvEyePt || NULL == pvLookatPt )
1237        return;
1238
1239    m_vDefaultEye = m_vEye = *pvEyePt;
1240    m_vDefaultLookAt = m_vLookAt = *pvLookatPt;
1241
1242    // Calc the view matrix
1243    D3DXVECTOR3 vUp(0,1,0);
1244    D3DXMatrixLookAtLH( &m_mView, pvEyePt, pvLookatPt, &vUp );
1245
1246    D3DXMATRIX mInvView;
1247    D3DXMatrixInverse( &mInvView, NULL, &m_mView );
1248
1249    // The axis basis vectors and camera position are stored inside the
1250    // position matrix in the 4 rows of the camera's world matrix.
1251    // To figure out the yaw/pitch of the camera, we just need the Z basis vector
1252    D3DXVECTOR3* pZBasis = (D3DXVECTOR3*) &mInvView._31;
1253
1254    m_fCameraYawAngle   = atan2f( pZBasis->x, pZBasis->z );
1255    float fLen = sqrtf(pZBasis->z*pZBasis->z + pZBasis->x*pZBasis->x);
1256    m_fCameraPitchAngle = -atan2f( pZBasis->y, fLen );
1257}
1258
1259
1260
1261
1262//--------------------------------------------------------------------------------------
1263// Calculates the projection matrix based on input params
1264//--------------------------------------------------------------------------------------
1265VOID CBaseCamera::SetProjParams( FLOAT fFOV, FLOAT fAspect, FLOAT fNearPlane,
1266                                   FLOAT fFarPlane )
1267{
1268    // Set attributes for the projection matrix
1269    m_fFOV        = fFOV;
1270    m_fAspect     = fAspect;
1271    m_fNearPlane  = fNearPlane;
1272    m_fFarPlane   = fFarPlane;
1273
1274    D3DXMatrixPerspectiveFovLH( &m_mProj, fFOV, fAspect, fNearPlane, fFarPlane );
1275}
1276
1277
1278
1279
1280//--------------------------------------------------------------------------------------
1281// Call this from your message proc so this class can handle window messages
1282//--------------------------------------------------------------------------------------
1283LRESULT CBaseCamera::HandleMessages( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1284{
1285    UNREFERENCED_PARAMETER( hWnd );
1286    UNREFERENCED_PARAMETER( lParam );
1287
1288    switch( uMsg )
1289    {
1290        case WM_KEYDOWN:
1291        {
1292            // Map this key to a D3DUtil_CameraKeys enum and update the
1293            // state of m_aKeys[] by adding the KEY_WAS_DOWN_MASK|KEY_IS_DOWN_MASK mask
1294            // only if the key is not down
1295            D3DUtil_CameraKeys mappedKey = MapKey( (UINT)wParam );
1296            if( mappedKey != CAM_UNKNOWN )
1297            {
1298                if( FALSE == IsKeyDown(m_aKeys[mappedKey]) )
1299                    m_aKeys[ mappedKey ] = KEY_WAS_DOWN_MASK | KEY_IS_DOWN_MASK;
1300            }
1301            break;
1302        }
1303
1304        case WM_KEYUP:
1305        {
1306            // Map this key to a D3DUtil_CameraKeys enum and update the
1307            // state of m_aKeys[] by removing the KEY_IS_DOWN_MASK mask.
1308            D3DUtil_CameraKeys mappedKey = MapKey( (UINT)wParam );
1309            if( mappedKey != CAM_UNKNOWN && (DWORD)mappedKey < 8 )
1310                m_aKeys[ mappedKey ] &= ~KEY_IS_DOWN_MASK;
1311            break;
1312        }
1313
1314        case WM_RBUTTONDOWN:
1315        case WM_MBUTTONDOWN:
1316        case WM_LBUTTONDOWN:
1317        case WM_RBUTTONDBLCLK:
1318        case WM_MBUTTONDBLCLK:
1319        case WM_LBUTTONDBLCLK:
1320        {
1321            // Compute the drag rectangle in screen coord.
1322            POINT ptCursor = { (short)LOWORD(lParam), (short)HIWORD(lParam) };
1323
1324            // Update member var state
1325            if( ( uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK ) && PtInRect( &m_rcDrag, ptCursor ) )
1326                { m_bMouseLButtonDown = true; m_nCurrentButtonMask |= MOUSE_LEFT_BUTTON; }
1327            if( ( uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONDBLCLK ) && PtInRect( &m_rcDrag, ptCursor ) )
1328                { m_bMouseMButtonDown = true; m_nCurrentButtonMask |= MOUSE_MIDDLE_BUTTON; }
1329            if( ( uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONDBLCLK ) && PtInRect( &m_rcDrag, ptCursor ) )
1330                { m_bMouseRButtonDown = true; m_nCurrentButtonMask |= MOUSE_RIGHT_BUTTON; }
1331
1332            // Capture the mouse, so if the mouse button is
1333            // released outside the window, we'll get the WM_LBUTTONUP message
1334            SetCapture(hWnd);
1335            GetCursorPos( &m_ptLastMousePosition );
1336            return TRUE;
1337        }
1338
1339        case WM_RBUTTONUP:
1340        case WM_MBUTTONUP:
1341        case WM_LBUTTONUP:   
1342        {
1343            // Update member var state
1344            if( uMsg == WM_LBUTTONUP ) { m_bMouseLButtonDown = false; m_nCurrentButtonMask &= ~MOUSE_LEFT_BUTTON; }
1345            if( uMsg == WM_MBUTTONUP ) { m_bMouseMButtonDown = false; m_nCurrentButtonMask &= ~MOUSE_MIDDLE_BUTTON; }
1346            if( uMsg == WM_RBUTTONUP ) { m_bMouseRButtonDown = false; m_nCurrentButtonMask &= ~MOUSE_RIGHT_BUTTON; }
1347
1348            // Release the capture if no mouse buttons down
1349            if( !m_bMouseLButtonDown  &&
1350                !m_bMouseRButtonDown &&
1351                !m_bMouseMButtonDown )
1352            {
1353                ReleaseCapture();
1354            }
1355            break;
1356        }
1357
1358        case WM_MOUSEWHEEL:
1359            // Update member var state
1360            m_nMouseWheelDelta = (short)HIWORD(wParam) / 120;
1361            break;
1362    }
1363
1364    return FALSE;
1365}
1366
1367
1368
1369
1370//--------------------------------------------------------------------------------------
1371// Figure out the mouse delta based on mouse movement
1372//--------------------------------------------------------------------------------------
1373void CBaseCamera::UpdateMouseDelta( float fElapsedTime )
1374{
1375    UNREFERENCED_PARAMETER( fElapsedTime );
1376
1377    POINT ptCurMouseDelta;
1378    POINT ptCurMousePos;
1379   
1380    // Get current position of mouse
1381    GetCursorPos( &ptCurMousePos );
1382
1383    // Calc how far it's moved since last frame
1384    ptCurMouseDelta.x = ptCurMousePos.x - m_ptLastMousePosition.x;
1385    ptCurMouseDelta.y = ptCurMousePos.y - m_ptLastMousePosition.y;
1386
1387    // Record current position for next time
1388    m_ptLastMousePosition = ptCurMousePos;
1389
1390    if( m_bResetCursorAfterMove )
1391    {
1392        // Set position of camera to center of desktop,
1393        // so it always has room to move.  This is very useful
1394        // if the cursor is hidden.  If this isn't done and cursor is hidden,
1395        // then invisible cursor will hit the edge of the screen
1396        // and the user can't tell what happened
1397        POINT ptCenter;
1398        RECT rcDesktop;
1399        GetWindowRect( GetDesktopWindow(), &rcDesktop );
1400        ptCenter.x = (rcDesktop.right - rcDesktop.left) / 2;
1401        ptCenter.y = (rcDesktop.bottom - rcDesktop.top) / 2;   
1402        SetCursorPos( ptCenter.x, ptCenter.y );
1403        m_ptLastMousePosition = ptCenter;
1404    }
1405
1406    // Smooth the relative mouse data over a few frames so it isn't
1407    // jerky when moving slowly at low frame rates.
1408    float fPercentOfNew =  1.0f / m_fFramesToSmoothMouseData;
1409    float fPercentOfOld =  1.0f - fPercentOfNew;
1410    m_vMouseDelta.x = m_vMouseDelta.x*fPercentOfOld + ptCurMouseDelta.x*fPercentOfNew;
1411    m_vMouseDelta.y = m_vMouseDelta.y*fPercentOfOld + ptCurMouseDelta.y*fPercentOfNew;
1412
1413    m_vRotVelocity = m_vMouseDelta * m_fRotationScaler;
1414}
1415
1416
1417
1418
1419//--------------------------------------------------------------------------------------
1420// Figure out the velocity based on keyboard input & drag if any
1421//--------------------------------------------------------------------------------------
1422void CBaseCamera::UpdateVelocity( float fElapsedTime )
1423{
1424    D3DXMATRIX mRotDelta;
1425    D3DXVECTOR3 vAccel = D3DXVECTOR3(0,0,0);
1426
1427    if( m_bEnablePositionMovement )
1428    {
1429        // Update acceleration vector based on keyboard state
1430        if( IsKeyDown(m_aKeys[CAM_MOVE_FORWARD]) )
1431            vAccel.z += 1.0f;
1432        if( IsKeyDown(m_aKeys[CAM_MOVE_BACKWARD]) )
1433            vAccel.z -= 1.0f;
1434        if( m_bEnableYAxisMovement )
1435        {
1436            if( IsKeyDown(m_aKeys[CAM_MOVE_UP]) )
1437                vAccel.y += 1.0f;
1438            if( IsKeyDown(m_aKeys[CAM_MOVE_DOWN]) )
1439                vAccel.y -= 1.0f;
1440        }
1441        if( IsKeyDown(m_aKeys[CAM_STRAFE_RIGHT]) )
1442            vAccel.x += 1.0f;
1443        if( IsKeyDown(m_aKeys[CAM_STRAFE_LEFT]) )
1444            vAccel.x -= 1.0f;
1445    }
1446
1447    // Normalize vector so if moving 2 dirs (left & forward),
1448    // the camera doesn't move faster than if moving in 1 dir
1449    D3DXVec3Normalize( &vAccel, &vAccel );
1450
1451    // Scale the acceleration vector
1452    vAccel *= m_fMoveScaler;
1453
1454    if( m_bMovementDrag )
1455    {
1456        // Is there any acceleration this frame?
1457        if( D3DXVec3LengthSq( &vAccel ) > 0 )
1458        {
1459            // If so, then this means the user has pressed a movement key\
1460            // so change the velocity immediately to acceleration
1461            // upon keyboard input.  This isn't normal physics
1462            // but it will give a quick response to keyboard input
1463            m_vVelocity = vAccel;
1464            m_fDragTimer = m_fTotalDragTimeToZero;
1465            m_vVelocityDrag = vAccel / m_fDragTimer;
1466        }
1467        else
1468        {
1469            // If no key being pressed, then slowly decrease velocity to 0
1470            if( m_fDragTimer > 0 )
1471            {
1472                // Drag until timer is <= 0
1473                m_vVelocity -= m_vVelocityDrag * fElapsedTime;
1474                m_fDragTimer -= fElapsedTime;
1475            }
1476            else
1477            {
1478                // Zero velocity
1479                m_vVelocity = D3DXVECTOR3(0,0,0);
1480            }
1481        }
1482    }
1483    else
1484    {
1485        // No drag, so immediately change the velocity
1486        m_vVelocity = vAccel;
1487    }
1488}
1489
1490
1491
1492
1493//--------------------------------------------------------------------------------------
1494// Clamps pV to lie inside m_vMinBoundary & m_vMaxBoundary
1495//--------------------------------------------------------------------------------------
1496void CBaseCamera::ConstrainToBoundary( D3DXVECTOR3* pV )
1497{
1498    // Constrain vector to a bounding box
1499    pV->x = max(pV->x, m_vMinBoundary.x);
1500    pV->y = max(pV->y, m_vMinBoundary.y);
1501    pV->z = max(pV->z, m_vMinBoundary.z);
1502
1503    pV->x = min(pV->x, m_vMaxBoundary.x);
1504    pV->y = min(pV->y, m_vMaxBoundary.y);
1505    pV->z = min(pV->z, m_vMaxBoundary.z);
1506}
1507
1508
1509
1510
1511//--------------------------------------------------------------------------------------
1512// Maps a windows virtual key to an enum
1513//--------------------------------------------------------------------------------------
1514D3DUtil_CameraKeys CBaseCamera::MapKey( UINT nKey )
1515{
1516    // This could be upgraded to a method that's user-definable but for
1517    // simplicity, we'll use a hardcoded mapping.
1518    switch( nKey )
1519    {
1520        case VK_CONTROL:  return CAM_CONTROLDOWN;
1521        case VK_LEFT:  return CAM_STRAFE_LEFT;
1522        case VK_RIGHT: return CAM_STRAFE_RIGHT;
1523        case VK_UP:    return CAM_MOVE_FORWARD;
1524        case VK_DOWN:  return CAM_MOVE_BACKWARD;
1525        case VK_PRIOR: return CAM_MOVE_UP;        // pgup
1526        case VK_NEXT:  return CAM_MOVE_DOWN;      // pgdn
1527
1528        case 'A':      return CAM_STRAFE_LEFT;
1529        case 'D':      return CAM_STRAFE_RIGHT;
1530        case 'W':      return CAM_MOVE_FORWARD;
1531        case 'S':      return CAM_MOVE_BACKWARD;
1532        case 'Q':      return CAM_MOVE_DOWN;
1533        case 'E':      return CAM_MOVE_UP;
1534
1535        case VK_NUMPAD4: return CAM_STRAFE_LEFT;
1536        case VK_NUMPAD6: return CAM_STRAFE_RIGHT;
1537        case VK_NUMPAD8: return CAM_MOVE_FORWARD;
1538        case VK_NUMPAD2: return CAM_MOVE_BACKWARD;
1539        case VK_NUMPAD9: return CAM_MOVE_UP;       
1540        case VK_NUMPAD3: return CAM_MOVE_DOWN;     
1541
1542        case VK_HOME:   return CAM_RESET;
1543    }
1544
1545    return CAM_UNKNOWN;
1546}
1547
1548
1549
1550
1551//--------------------------------------------------------------------------------------
1552// Reset the camera's position back to the default
1553//--------------------------------------------------------------------------------------
1554VOID CBaseCamera::Reset()
1555{
1556    SetViewParams( &m_vDefaultEye, &m_vDefaultLookAt );
1557}
1558
1559
1560
1561
1562//--------------------------------------------------------------------------------------
1563// Constructor
1564//--------------------------------------------------------------------------------------
1565CFirstPersonCamera::CFirstPersonCamera() :
1566    m_nActiveButtonMask( 0x07 )
1567{
1568}
1569
1570
1571
1572
1573//--------------------------------------------------------------------------------------
1574// Update the view matrix based on user input & elapsed time
1575//--------------------------------------------------------------------------------------
1576VOID CFirstPersonCamera::FrameMove( FLOAT fElapsedTime )
1577{
1578    if( DXUTGetGlobalTimer()->IsStopped() )
1579        fElapsedTime = 1.0f / DXUTGetFPS();
1580
1581    if( IsKeyDown(m_aKeys[CAM_RESET]) )
1582        Reset();
1583
1584    // Get the mouse movement (if any) if the mouse button are down
1585    if( m_nActiveButtonMask & m_nCurrentButtonMask )
1586        UpdateMouseDelta( fElapsedTime );
1587
1588    // Get amount of velocity based on the keyboard input and drag (if any)
1589    UpdateVelocity( fElapsedTime );
1590
1591    // Simple euler method to calculate position delta
1592    D3DXVECTOR3 vPosDelta = m_vVelocity * fElapsedTime;
1593
1594    // If rotating the camera
1595    if( m_nActiveButtonMask & m_nCurrentButtonMask )
1596    {
1597        // Update the pitch & yaw angle based on mouse movement
1598        float fYawDelta   = m_vRotVelocity.x;
1599        float fPitchDelta = m_vRotVelocity.y;
1600
1601        // Invert pitch if requested
1602        if( m_bInvertPitch )
1603            fPitchDelta = -fPitchDelta;
1604
1605        m_fCameraPitchAngle += fPitchDelta;
1606        m_fCameraYawAngle   += fYawDelta;
1607
1608        // Limit pitch to straight up or straight down
1609        m_fCameraPitchAngle = max( -D3DX_PI/2.0f,  m_fCameraPitchAngle );
1610        m_fCameraPitchAngle = min( +D3DX_PI/2.0f,  m_fCameraPitchAngle );
1611    }
1612
1613    // Make a rotation matrix based on the camera's yaw & pitch
1614    D3DXMATRIX mCameraRot;
1615    D3DXMatrixRotationYawPitchRoll( &mCameraRot, m_fCameraYawAngle, m_fCameraPitchAngle, 0 );
1616
1617    // Transform vectors based on camera's rotation matrix
1618    D3DXVECTOR3 vWorldUp, vWorldAhead;
1619    D3DXVECTOR3 vLocalUp    = D3DXVECTOR3(0,1,0);
1620    D3DXVECTOR3 vLocalAhead = D3DXVECTOR3(0,0,1);
1621    D3DXVec3TransformCoord( &vWorldUp, &vLocalUp, &mCameraRot );
1622    D3DXVec3TransformCoord( &vWorldAhead, &vLocalAhead, &mCameraRot );
1623
1624    // Transform the position delta by the camera's rotation
1625    D3DXVECTOR3 vPosDeltaWorld;
1626    if( !m_bEnableYAxisMovement )
1627    {
1628        // If restricting Y movement, do not include pitch
1629        // when transforming position delta vector.
1630        D3DXMatrixRotationYawPitchRoll( &mCameraRot, m_fCameraYawAngle, 0.0f, 0.0f );
1631    }
1632    D3DXVec3TransformCoord( &vPosDeltaWorld, &vPosDelta, &mCameraRot );
1633
1634    // Move the eye position
1635    m_vEye += vPosDeltaWorld;
1636    if( m_bClipToBoundary )
1637        ConstrainToBoundary( &m_vEye );
1638
1639    // Update the lookAt position based on the eye position
1640    m_vLookAt = m_vEye + vWorldAhead;
1641
1642    // Update the view matrix
1643    D3DXMatrixLookAtLH( &m_mView, &m_vEye, &m_vLookAt, &vWorldUp );
1644
1645    D3DXMatrixInverse( &m_mCameraWorld, NULL, &m_mView );
1646}
1647
1648
1649//--------------------------------------------------------------------------------------
1650// Enable or disable each of the mouse buttons for rotation drag.
1651//--------------------------------------------------------------------------------------
1652void CFirstPersonCamera::SetRotateButtons( bool bLeft, bool bMiddle, bool bRight )
1653{
1654    m_nActiveButtonMask = ( bLeft ? MOUSE_LEFT_BUTTON : 0 ) |
1655                          ( bMiddle ? MOUSE_MIDDLE_BUTTON : 0 ) |
1656                          ( bRight ? MOUSE_RIGHT_BUTTON : 0 );
1657}
1658
1659
1660//--------------------------------------------------------------------------------------
1661// Constructor
1662//--------------------------------------------------------------------------------------
1663CModelViewerCamera::CModelViewerCamera()
1664{
1665    D3DXMatrixIdentity( &m_mWorld );
1666    D3DXMatrixIdentity( &m_mModelRot );
1667    D3DXMatrixIdentity( &m_mModelLastRot );   
1668    D3DXMatrixIdentity( &m_mCameraRotLast );   
1669    m_vModelCenter = D3DXVECTOR3(0,0,0);
1670    m_fRadius    = 5.0f;
1671    m_fDefaultRadius = 5.0f;
1672    m_fMinRadius = 1.0f;
1673    m_fMaxRadius = FLT_MAX;
1674    m_bLimitPitch = false;
1675    m_bEnablePositionMovement = false;
1676    m_bAttachCameraToModel = false;
1677
1678    m_nRotateModelButtonMask  = MOUSE_LEFT_BUTTON;
1679    m_nZoomButtonMask         = MOUSE_WHEEL;
1680    m_nRotateCameraButtonMask = MOUSE_RIGHT_BUTTON;
1681}
1682
1683
1684
1685
1686//--------------------------------------------------------------------------------------
1687// Update the view matrix & the model's world matrix based
1688//       on user input & elapsed time
1689//--------------------------------------------------------------------------------------
1690VOID CModelViewerCamera::FrameMove( FLOAT fElapsedTime )
1691{
1692    if( IsKeyDown(m_aKeys[CAM_RESET]) )
1693        Reset();
1694
1695    // Get the mouse movement (if any) if the mouse button are down
1696    if( m_nCurrentButtonMask != 0 )
1697        UpdateMouseDelta( fElapsedTime );
1698
1699    // Get amount of velocity based on the keyboard input and drag (if any)
1700    UpdateVelocity( fElapsedTime );
1701
1702    // Simple euler method to calculate position delta
1703    D3DXVECTOR3 vPosDelta = m_vVelocity * fElapsedTime;
1704
1705    // Change the radius from the camera to the model based on wheel scrolling
1706    if( m_nMouseWheelDelta && m_nZoomButtonMask == MOUSE_WHEEL )
1707        m_fRadius -= m_nMouseWheelDelta * m_fRadius * 0.1f;
1708    m_fRadius = min( m_fMaxRadius, m_fRadius );
1709    m_fRadius = max( m_fMinRadius, m_fRadius );
1710    m_nMouseWheelDelta = 0;
1711
1712    // Get the inverse of the arcball's rotation matrix
1713    D3DXMATRIX mCameraRot;
1714    D3DXMatrixInverse( &mCameraRot, NULL, m_ViewArcBall.GetRotationMatrix() );
1715
1716    // Transform vectors based on camera's rotation matrix
1717    D3DXVECTOR3 vWorldUp, vWorldAhead;
1718    D3DXVECTOR3 vLocalUp    = D3DXVECTOR3(0,1,0);
1719    D3DXVECTOR3 vLocalAhead = D3DXVECTOR3(0,0,1);
1720    D3DXVec3TransformCoord( &vWorldUp, &vLocalUp, &mCameraRot );
1721    D3DXVec3TransformCoord( &vWorldAhead, &vLocalAhead, &mCameraRot );
1722
1723    // Transform the position delta by the camera's rotation
1724    D3DXVECTOR3 vPosDeltaWorld;
1725    D3DXVec3TransformCoord( &vPosDeltaWorld, &vPosDelta, &mCameraRot );
1726
1727    // Move the lookAt position
1728    m_vLookAt += vPosDeltaWorld;
1729    if( m_bClipToBoundary )
1730        ConstrainToBoundary( &m_vLookAt );
1731
1732    // Update the eye point based on a radius away from the lookAt position
1733    m_vEye = m_vLookAt - vWorldAhead * m_fRadius;
1734
1735    // Update the view matrix
1736    D3DXMatrixLookAtLH( &m_mView, &m_vEye, &m_vLookAt, &vWorldUp );
1737
1738    D3DXMATRIX mInvView;
1739    D3DXMatrixInverse( &mInvView, NULL, &m_mView );
1740    mInvView._41 = mInvView._42 = mInvView._43 = 0;
1741
1742    D3DXMATRIX mModelLastRotInv;
1743    D3DXMatrixInverse(&mModelLastRotInv, NULL, &m_mModelLastRot);
1744
1745    // Accumulate the delta of the arcball's rotation in view space.
1746    // Note that per-frame delta rotations could be problematic over long periods of time.
1747    D3DXMATRIX mModelRot;
1748    mModelRot = *m_WorldArcBall.GetRotationMatrix();
1749    m_mModelRot *= m_mView * mModelLastRotInv * mModelRot * mInvView;
1750
1751    if( m_ViewArcBall.IsBeingDragged() && m_bAttachCameraToModel && !IsKeyDown(m_aKeys[CAM_CONTROLDOWN]) )
1752    {
1753        // Attach camera to model by inverse of the model rotation
1754        D3DXMATRIX mCameraLastRotInv;
1755        D3DXMatrixInverse(&mCameraLastRotInv, NULL, &m_mCameraRotLast);
1756        D3DXMATRIX mCameraRotDelta = mCameraLastRotInv * mCameraRot; // local to world matrix
1757        m_mModelRot *= mCameraRotDelta;
1758    }
1759    m_mCameraRotLast = mCameraRot;
1760
1761    m_mModelLastRot = mModelRot;
1762
1763    // Since we're accumulating delta rotations, we need to orthonormalize
1764    // the matrix to prevent eventual matrix skew
1765    D3DXVECTOR3* pXBasis = (D3DXVECTOR3*) &m_mModelRot._11;
1766    D3DXVECTOR3* pYBasis = (D3DXVECTOR3*) &m_mModelRot._21;
1767    D3DXVECTOR3* pZBasis = (D3DXVECTOR3*) &m_mModelRot._31;
1768    D3DXVec3Normalize( pXBasis, pXBasis );
1769    D3DXVec3Cross( pYBasis, pZBasis, pXBasis );
1770    D3DXVec3Normalize( pYBasis, pYBasis );
1771    D3DXVec3Cross( pZBasis, pXBasis, pYBasis );
1772
1773    // Translate the rotation matrix to the same position as the lookAt position
1774    m_mModelRot._41 = m_vLookAt.x;
1775    m_mModelRot._42 = m_vLookAt.y;
1776    m_mModelRot._43 = m_vLookAt.z;
1777
1778    // Translate world matrix so its at the center of the model
1779    D3DXMATRIX mTrans;
1780    D3DXMatrixTranslation( &mTrans, -m_vModelCenter.x, -m_vModelCenter.y, -m_vModelCenter.z );
1781    m_mWorld = mTrans * m_mModelRot;
1782}
1783
1784
1785void CModelViewerCamera::SetDragRect( RECT &rc )
1786{
1787    CBaseCamera::SetDragRect( rc );
1788
1789    m_WorldArcBall.SetOffset( rc.left, rc.top );
1790    m_ViewArcBall.SetOffset( rc.left, rc.top );
1791    SetWindow( rc.right - rc.left, rc.bottom - rc.top );
1792}
1793
1794
1795//--------------------------------------------------------------------------------------
1796// Reset the camera's position back to the default
1797//--------------------------------------------------------------------------------------
1798VOID CModelViewerCamera::Reset()
1799{
1800    CBaseCamera::Reset();
1801
1802    D3DXMatrixIdentity( &m_mWorld );
1803    D3DXMatrixIdentity( &m_mModelRot );
1804    D3DXMatrixIdentity( &m_mModelLastRot );   
1805    D3DXMatrixIdentity( &m_mCameraRotLast );   
1806
1807    m_fRadius = m_fDefaultRadius;
1808    m_WorldArcBall.Reset();
1809    m_ViewArcBall.Reset();
1810}
1811
1812
1813//--------------------------------------------------------------------------------------
1814// Override for setting the view parameters
1815//--------------------------------------------------------------------------------------
1816void CModelViewerCamera::SetViewParams( D3DXVECTOR3* pvEyePt, D3DXVECTOR3* pvLookatPt )
1817{
1818    CBaseCamera::SetViewParams( pvEyePt, pvLookatPt );
1819
1820    // Propogate changes to the member arcball
1821    D3DXQUATERNION quat;
1822    D3DXMATRIXA16 mRotation;
1823    D3DXVECTOR3 vUp(0,1,0);
1824    D3DXMatrixLookAtLH( &mRotation, pvEyePt, pvLookatPt, &vUp );
1825    D3DXQuaternionRotationMatrix( &quat, &mRotation );
1826    m_ViewArcBall.SetQuatNow( quat );
1827
1828    // Set the radius according to the distance
1829    D3DXVECTOR3 vEyeToPoint;
1830    D3DXVec3Subtract( &vEyeToPoint, pvLookatPt, pvEyePt );
1831    SetRadius( D3DXVec3Length( &vEyeToPoint ) );
1832}
1833
1834
1835
1836//--------------------------------------------------------------------------------------
1837// Call this from your message proc so this class can handle window messages
1838//--------------------------------------------------------------------------------------
1839LRESULT CModelViewerCamera::HandleMessages( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
1840{
1841    CBaseCamera::HandleMessages( hWnd, uMsg, wParam, lParam );
1842
1843    if( ( (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK ) && m_nRotateModelButtonMask & MOUSE_LEFT_BUTTON) ||
1844        ( (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONDBLCLK ) && m_nRotateModelButtonMask & MOUSE_MIDDLE_BUTTON) ||
1845        ( (uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONDBLCLK ) && m_nRotateModelButtonMask & MOUSE_RIGHT_BUTTON) )
1846    {
1847        int iMouseX = (short)LOWORD(lParam);
1848        int iMouseY = (short)HIWORD(lParam);
1849        m_WorldArcBall.OnBegin( iMouseX, iMouseY );
1850    }
1851
1852    if( ( (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK ) && m_nRotateCameraButtonMask & MOUSE_LEFT_BUTTON) ||
1853        ( (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONDBLCLK ) && m_nRotateCameraButtonMask & MOUSE_MIDDLE_BUTTON) ||
1854        ( (uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONDBLCLK ) && m_nRotateCameraButtonMask & MOUSE_RIGHT_BUTTON) )
1855    {
1856        int iMouseX = (short)LOWORD(lParam);
1857        int iMouseY = (short)HIWORD(lParam);
1858        m_ViewArcBall.OnBegin( iMouseX, iMouseY );
1859    }
1860
1861    if( uMsg == WM_MOUSEMOVE )
1862    {
1863        int iMouseX = (short)LOWORD(lParam);
1864        int iMouseY = (short)HIWORD(lParam);
1865        m_WorldArcBall.OnMove( iMouseX, iMouseY );
1866        m_ViewArcBall.OnMove( iMouseX, iMouseY );
1867    }
1868
1869    if( (uMsg == WM_LBUTTONUP && m_nRotateModelButtonMask & MOUSE_LEFT_BUTTON) ||
1870        (uMsg == WM_MBUTTONUP && m_nRotateModelButtonMask & MOUSE_MIDDLE_BUTTON) ||
1871        (uMsg == WM_RBUTTONUP && m_nRotateModelButtonMask & MOUSE_RIGHT_BUTTON) )
1872    {
1873        m_WorldArcBall.OnEnd();
1874    }
1875
1876    if( (uMsg == WM_LBUTTONUP && m_nRotateCameraButtonMask & MOUSE_LEFT_BUTTON) ||
1877        (uMsg == WM_MBUTTONUP && m_nRotateCameraButtonMask & MOUSE_MIDDLE_BUTTON) ||
1878        (uMsg == WM_RBUTTONUP && m_nRotateCameraButtonMask & MOUSE_RIGHT_BUTTON) )
1879    {
1880        m_ViewArcBall.OnEnd();
1881    }
1882
1883    return FALSE;
1884}
1885
1886
1887
1888
1889//--------------------------------------------------------------------------------------
1890// Gives the D3D device a cursor with image and hotspot from hCursor.
1891//--------------------------------------------------------------------------------------
1892HRESULT DXUTSetDeviceCursor( IDirect3DDevice9* pd3dDevice, HCURSOR hCursor, bool bAddWatermark )
1893{
1894    HRESULT hr = E_FAIL;
1895    ICONINFO iconinfo;
1896    bool bBWCursor;
1897    LPDIRECT3DSURFACE9 pCursorSurface = NULL;
1898    HDC hdcColor = NULL;
1899    HDC hdcMask = NULL;
1900    HDC hdcScreen = NULL;
1901    BITMAP bm;
1902    DWORD dwWidth;
1903    DWORD dwHeightSrc;
1904    DWORD dwHeightDest;
1905    COLORREF crColor;
1906    COLORREF crMask;
1907    UINT x;
1908    UINT y;
1909    BITMAPINFO bmi;
1910    COLORREF* pcrArrayColor = NULL;
1911    COLORREF* pcrArrayMask = NULL;
1912    DWORD* pBitmap;
1913    HGDIOBJ hgdiobjOld;
1914
1915    ZeroMemory( &iconinfo, sizeof(iconinfo) );
1916    if( !GetIconInfo( hCursor, &iconinfo ) )
1917        goto End;
1918
1919    if (0 == GetObject((HGDIOBJ)iconinfo.hbmMask, sizeof(BITMAP), (LPVOID)&bm))
1920        goto End;
1921    dwWidth = bm.bmWidth;
1922    dwHeightSrc = bm.bmHeight;
1923
1924    if( iconinfo.hbmColor == NULL )
1925    {
1926        bBWCursor = TRUE;
1927        dwHeightDest = dwHeightSrc / 2;
1928    }
1929    else
1930    {
1931        bBWCursor = FALSE;
1932        dwHeightDest = dwHeightSrc;
1933    }
1934
1935    // Create a surface for the fullscreen cursor
1936    if( FAILED( hr = pd3dDevice->CreateOffscreenPlainSurface( dwWidth, dwHeightDest,
1937        D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pCursorSurface, NULL ) ) )
1938    {
1939        goto End;
1940    }
1941
1942    pcrArrayMask = new DWORD[dwWidth * dwHeightSrc];
1943
1944    ZeroMemory(&bmi, sizeof(bmi));
1945    bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
1946    bmi.bmiHeader.biWidth = dwWidth;
1947    bmi.bmiHeader.biHeight = dwHeightSrc;
1948    bmi.bmiHeader.biPlanes = 1;
1949    bmi.bmiHeader.biBitCount = 32;
1950    bmi.bmiHeader.biCompression = BI_RGB;
1951
1952    hdcScreen = GetDC( NULL );
1953    hdcMask = CreateCompatibleDC( hdcScreen );
1954    if( hdcMask == NULL )
1955    {
1956        hr = E_FAIL;
1957        goto End;
1958    }
1959    hgdiobjOld = SelectObject(hdcMask, iconinfo.hbmMask);
1960    GetDIBits(hdcMask, iconinfo.hbmMask, 0, dwHeightSrc,
1961        pcrArrayMask, &bmi, DIB_RGB_COLORS);
1962    SelectObject(hdcMask, hgdiobjOld);
1963
1964    if (!bBWCursor)
1965    {
1966        pcrArrayColor = new DWORD[dwWidth * dwHeightDest];
1967        hdcColor = CreateCompatibleDC( hdcScreen );
1968        if( hdcColor == NULL )
1969        {
1970            hr = E_FAIL;
1971            goto End;
1972        }
1973        SelectObject(hdcColor, iconinfo.hbmColor);
1974        GetDIBits(hdcColor, iconinfo.hbmColor, 0, dwHeightDest,
1975            pcrArrayColor, &bmi, DIB_RGB_COLORS);
1976    }
1977
1978    // Transfer cursor image into the surface
1979    D3DLOCKED_RECT lr;
1980    pCursorSurface->LockRect( &lr, NULL, 0 );
1981    pBitmap = (DWORD*)lr.pBits;
1982    for( y = 0; y < dwHeightDest; y++ )
1983    {
1984        for( x = 0; x < dwWidth; x++ )
1985        {
1986            if (bBWCursor)
1987            {
1988                crColor = pcrArrayMask[dwWidth*(dwHeightDest-1-y) + x];
1989                crMask = pcrArrayMask[dwWidth*(dwHeightSrc-1-y) + x];
1990            }
1991            else
1992            {
1993                crColor = pcrArrayColor[dwWidth*(dwHeightDest-1-y) + x];
1994                crMask = pcrArrayMask[dwWidth*(dwHeightDest-1-y) + x];
1995            }
1996            if (crMask == 0)
1997                pBitmap[dwWidth*y + x] = 0xff000000 | crColor;
1998            else
1999                pBitmap[dwWidth*y + x] = 0x00000000;
2000
2001            // It may be helpful to make the D3D cursor look slightly
2002            // different from the Windows cursor so you can distinguish
2003            // between the two when developing/testing code.  When
2004            // bAddWatermark is TRUE, the following code adds some
2005            // small grey "D3D" characters to the upper-left corner of
2006            // the D3D cursor image.
2007            if( bAddWatermark && x < 12 && y < 5 )
2008            {
2009                // 11.. 11.. 11.. .... CCC0
2010                // 1.1. ..1. 1.1. .... A2A0
2011                // 1.1. .1.. 1.1. .... A4A0
2012                // 1.1. ..1. 1.1. .... A2A0
2013                // 11.. 11.. 11.. .... CCC0
2014
2015                const WORD wMask[5] = { 0xccc0, 0xa2a0, 0xa4a0, 0xa2a0, 0xccc0 };
2016                if( wMask[y] & (1 << (15 - x)) )
2017                {
2018                    pBitmap[dwWidth*y + x] |= 0xff808080;
2019                }
2020            }
2021        }
2022    }
2023    pCursorSurface->UnlockRect();
2024
2025    // Set the device cursor
2026    if( FAILED( hr = pd3dDevice->SetCursorProperties( iconinfo.xHotspot,
2027        iconinfo.yHotspot, pCursorSurface ) ) )
2028    {
2029        goto End;
2030    }
2031
2032    hr = S_OK;
2033
2034End:
2035    if( iconinfo.hbmMask != NULL )
2036        DeleteObject( iconinfo.hbmMask );
2037    if( iconinfo.hbmColor != NULL )
2038        DeleteObject( iconinfo.hbmColor );
2039    if( hdcScreen != NULL )
2040        ReleaseDC( NULL, hdcScreen );
2041    if( hdcColor != NULL )
2042        DeleteDC( hdcColor );
2043    if( hdcMask != NULL )
2044        DeleteDC( hdcMask );
2045    SAFE_DELETE_ARRAY( pcrArrayColor );
2046    SAFE_DELETE_ARRAY( pcrArrayMask );
2047    SAFE_RELEASE( pCursorSurface );
2048    return hr;
2049}
2050
2051
2052//--------------------------------------------------------------------------------------
2053// Desc: Returns a view matrix for rendering to a face of a cubemap.
2054//--------------------------------------------------------------------------------------
2055D3DXMATRIX DXUTGetCubeMapViewMatrix( DWORD dwFace )
2056{
2057    D3DXVECTOR3 vEyePt   = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
2058    D3DXVECTOR3 vLookDir;
2059    D3DXVECTOR3 vUpDir;
2060
2061    switch( dwFace )
2062    {
2063        case D3DCUBEMAP_FACE_POSITIVE_X:
2064            vLookDir = D3DXVECTOR3( 1.0f, 0.0f, 0.0f );
2065            vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
2066            break;
2067        case D3DCUBEMAP_FACE_NEGATIVE_X:
2068            vLookDir = D3DXVECTOR3(-1.0f, 0.0f, 0.0f );
2069            vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
2070            break;
2071        case D3DCUBEMAP_FACE_POSITIVE_Y:
2072            vLookDir = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
2073            vUpDir   = D3DXVECTOR3( 0.0f, 0.0f,-1.0f );
2074            break;
2075        case D3DCUBEMAP_FACE_NEGATIVE_Y:
2076            vLookDir = D3DXVECTOR3( 0.0f,-1.0f, 0.0f );
2077            vUpDir   = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
2078            break;
2079        case D3DCUBEMAP_FACE_POSITIVE_Z:
2080            vLookDir = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
2081            vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
2082            break;
2083        case D3DCUBEMAP_FACE_NEGATIVE_Z:
2084            vLookDir = D3DXVECTOR3( 0.0f, 0.0f,-1.0f );
2085            vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
2086            break;
2087    }
2088
2089    // Set the view transform for this cubemap surface
2090    D3DXMATRIXA16 mView;
2091    D3DXMatrixLookAtLH( &mView, &vEyePt, &vLookDir, &vUpDir );
2092    return mView;
2093}
2094
2095
2096//--------------------------------------------------------------------------------------
2097// Returns the string for the given D3DFORMAT.
2098//--------------------------------------------------------------------------------------
2099LPCWSTR DXUTD3DFormatToString( D3DFORMAT format, bool bWithPrefix )
2100{
2101    WCHAR* pstr = NULL;
2102    switch( format )
2103    {
2104    case D3DFMT_UNKNOWN:         pstr = L"D3DFMT_UNKNOWN"; break;
2105    case D3DFMT_R8G8B8:          pstr = L"D3DFMT_R8G8B8"; break;
2106    case D3DFMT_A8R8G8B8:        pstr = L"D3DFMT_A8R8G8B8"; break;
2107    case D3DFMT_X8R8G8B8:        pstr = L"D3DFMT_X8R8G8B8"; break;
2108    case D3DFMT_R5G6B5:          pstr = L"D3DFMT_R5G6B5"; break;
2109    case D3DFMT_X1R5G5B5:        pstr = L"D3DFMT_X1R5G5B5"; break;
2110    case D3DFMT_A1R5G5B5:        pstr = L"D3DFMT_A1R5G5B5"; break;
2111    case D3DFMT_A4R4G4B4:        pstr = L"D3DFMT_A4R4G4B4"; break;
2112    case D3DFMT_R3G3B2:          pstr = L"D3DFMT_R3G3B2"; break;
2113    case D3DFMT_A8:              pstr = L"D3DFMT_A8"; break;
2114    case D3DFMT_A8R3G3B2:        pstr = L"D3DFMT_A8R3G3B2"; break;
2115    case D3DFMT_X4R4G4B4:        pstr = L"D3DFMT_X4R4G4B4"; break;
2116    case D3DFMT_A2B10G10R10:     pstr = L"D3DFMT_A2B10G10R10"; break;
2117    case D3DFMT_A8B8G8R8:        pstr = L"D3DFMT_A8B8G8R8"; break;
2118    case D3DFMT_X8B8G8R8:        pstr = L"D3DFMT_X8B8G8R8"; break;
2119    case D3DFMT_G16R16:          pstr = L"D3DFMT_G16R16"; break;
2120    case D3DFMT_A2R10G10B10:     pstr = L"D3DFMT_A2R10G10B10"; break;
2121    case D3DFMT_A16B16G16R16:    pstr = L"D3DFMT_A16B16G16R16"; break;
2122    case D3DFMT_A8P8:            pstr = L"D3DFMT_A8P8"; break;
2123    case D3DFMT_P8:              pstr = L"D3DFMT_P8"; break;
2124    case D3DFMT_L8:              pstr = L"D3DFMT_L8"; break;
2125    case D3DFMT_A8L8:            pstr = L"D3DFMT_A8L8"; break;
2126    case D3DFMT_A4L4:            pstr = L"D3DFMT_A4L4"; break;
2127    case D3DFMT_V8U8:            pstr = L"D3DFMT_V8U8"; break;
2128    case D3DFMT_L6V5U5:          pstr = L"D3DFMT_L6V5U5"; break;
2129    case D3DFMT_X8L8V8U8:        pstr = L"D3DFMT_X8L8V8U8"; break;
2130    case D3DFMT_Q8W8V8U8:        pstr = L"D3DFMT_Q8W8V8U8"; break;
2131    case D3DFMT_V16U16:          pstr = L"D3DFMT_V16U16"; break;
2132    case D3DFMT_A2W10V10U10:     pstr = L"D3DFMT_A2W10V10U10"; break;
2133    case D3DFMT_UYVY:            pstr = L"D3DFMT_UYVY"; break;
2134    case D3DFMT_YUY2:            pstr = L"D3DFMT_YUY2"; break;
2135    case D3DFMT_DXT1:            pstr = L"D3DFMT_DXT1"; break;
2136    case D3DFMT_DXT2:            pstr = L"D3DFMT_DXT2"; break;
2137    case D3DFMT_DXT3:            pstr = L"D3DFMT_DXT3"; break;
2138    case D3DFMT_DXT4:            pstr = L"D3DFMT_DXT4"; break;
2139    case D3DFMT_DXT5:            pstr = L"D3DFMT_DXT5"; break;
2140    case D3DFMT_D16_LOCKABLE:    pstr = L"D3DFMT_D16_LOCKABLE"; break;
2141    case D3DFMT_D32:             pstr = L"D3DFMT_D32"; break;
2142    case D3DFMT_D15S1:           pstr = L"D3DFMT_D15S1"; break;
2143    case D3DFMT_D24S8:           pstr = L"D3DFMT_D24S8"; break;
2144    case D3DFMT_D24X8:           pstr = L"D3DFMT_D24X8"; break;
2145    case D3DFMT_D24X4S4:         pstr = L"D3DFMT_D24X4S4"; break;
2146    case D3DFMT_D16:             pstr = L"D3DFMT_D16"; break;
2147    case D3DFMT_L16:             pstr = L"D3DFMT_L16"; break;
2148    case D3DFMT_VERTEXDATA:      pstr = L"D3DFMT_VERTEXDATA"; break;
2149    case D3DFMT_INDEX16:         pstr = L"D3DFMT_INDEX16"; break;
2150    case D3DFMT_INDEX32:         pstr = L"D3DFMT_INDEX32"; break;
2151    case D3DFMT_Q16W16V16U16:    pstr = L"D3DFMT_Q16W16V16U16"; break;
2152    case D3DFMT_MULTI2_ARGB8:    pstr = L"D3DFMT_MULTI2_ARGB8"; break;
2153    case D3DFMT_R16F:            pstr = L"D3DFMT_R16F"; break;
2154    case D3DFMT_G16R16F:         pstr = L"D3DFMT_G16R16F"; break;
2155    case D3DFMT_A16B16G16R16F:   pstr = L"D3DFMT_A16B16G16R16F"; break;
2156    case D3DFMT_R32F:            pstr = L"D3DFMT_R32F"; break;
2157    case D3DFMT_G32R32F:         pstr = L"D3DFMT_G32R32F"; break;
2158    case D3DFMT_A32B32G32R32F:   pstr = L"D3DFMT_A32B32G32R32F"; break;
2159    case D3DFMT_CxV8U8:          pstr = L"D3DFMT_CxV8U8"; break;
2160    default:                     pstr = L"Unknown format"; break;
2161    }
2162    if( bWithPrefix || wcsstr( pstr, L"D3DFMT_" )== NULL )
2163        return pstr;
2164    else
2165        return pstr + lstrlen( L"D3DFMT_" );
2166}
2167
2168
2169
2170//--------------------------------------------------------------------------------------
2171// Outputs to the debug stream a formatted Unicode string with a variable-argument list.
2172//--------------------------------------------------------------------------------------
2173VOID DXUTOutputDebugStringW( LPCWSTR strMsg, ... )
2174{
2175#if defined(DEBUG) | defined(_DEBUG)
2176    WCHAR strBuffer[512];
2177   
2178    va_list args;
2179    va_start(args, strMsg);
2180    StringCchVPrintfW( strBuffer, 512, strMsg, args );
2181    strBuffer[511] = L'\0';
2182    va_end(args);
2183
2184    OutputDebugString( strBuffer );
2185#else
2186    UNREFERENCED_PARAMETER(strMsg);
2187#endif
2188}
2189
2190
2191//--------------------------------------------------------------------------------------
2192// Outputs to the debug stream a formatted MBCS string with a variable-argument list.
2193//--------------------------------------------------------------------------------------
2194VOID DXUTOutputDebugStringA( LPCSTR strMsg, ... )
2195{
2196#if defined(DEBUG) | defined(_DEBUG)
2197    CHAR strBuffer[512];
2198   
2199    va_list args;
2200    va_start(args, strMsg);
2201    StringCchVPrintfA( strBuffer, 512, strMsg, args );
2202    strBuffer[511] = '\0';
2203    va_end(args);
2204
2205    OutputDebugStringA( strBuffer );
2206#else
2207    UNREFERENCED_PARAMETER(strMsg);
2208#endif
2209}
2210
2211
2212//--------------------------------------------------------------------------------------
2213CDXUTLineManager::CDXUTLineManager()
2214{
2215    m_pd3dDevice = NULL;
2216    m_pD3DXLine = NULL;
2217}
2218
2219
2220//--------------------------------------------------------------------------------------
2221CDXUTLineManager::~CDXUTLineManager()
2222{
2223    OnDeletedDevice();
2224}
2225
2226
2227//--------------------------------------------------------------------------------------
2228HRESULT CDXUTLineManager::OnCreatedDevice( IDirect3DDevice9* pd3dDevice )
2229{
2230    m_pd3dDevice = pd3dDevice;
2231
2232    HRESULT hr;
2233    hr = D3DXCreateLine( m_pd3dDevice, &m_pD3DXLine );
2234    if( FAILED(hr) )
2235        return hr;
2236
2237    return S_OK;
2238}
2239
2240
2241//--------------------------------------------------------------------------------------
2242HRESULT CDXUTLineManager::OnResetDevice()
2243{
2244    if( m_pD3DXLine )
2245        m_pD3DXLine->OnResetDevice();
2246
2247    return S_OK;
2248}
2249
2250
2251//--------------------------------------------------------------------------------------
2252HRESULT CDXUTLineManager::OnRender()
2253{
2254    HRESULT hr;
2255    if( NULL == m_pD3DXLine )
2256        return E_INVALIDARG;
2257
2258    bool bDrawingHasBegun = false;
2259    float fLastWidth = 0.0f;
2260    bool bLastAntiAlias = false;
2261   
2262    for( int i=0; i<m_LinesList.GetSize(); i++ )
2263    {
2264        LINE_NODE* pLineNode = m_LinesList.GetAt(i);
2265        if( pLineNode )
2266        {
2267            if( !bDrawingHasBegun ||
2268                fLastWidth != pLineNode->fWidth ||
2269                bLastAntiAlias != pLineNode->bAntiAlias )
2270            {
2271                if( bDrawingHasBegun )
2272                {
2273                    hr = m_pD3DXLine->End();
2274                    if( FAILED(hr) )
2275                        return hr;
2276                }
2277
2278                m_pD3DXLine->SetWidth( pLineNode->fWidth );
2279                m_pD3DXLine->SetAntialias( pLineNode->bAntiAlias );
2280
2281                fLastWidth = pLineNode->fWidth;
2282                bLastAntiAlias = pLineNode->bAntiAlias;
2283
2284                hr = m_pD3DXLine->Begin();
2285                if( FAILED(hr) )
2286                    return hr;
2287                bDrawingHasBegun = true;
2288            }
2289
2290            hr = m_pD3DXLine->Draw( pLineNode->pVertexList, pLineNode->dwVertexListCount, pLineNode->Color );
2291            if( FAILED(hr) )
2292                return hr;
2293        }
2294    }
2295
2296    if( bDrawingHasBegun )
2297    {
2298        hr = m_pD3DXLine->End();
2299        if( FAILED(hr) )
2300            return hr;
2301    }
2302
2303    return S_OK;
2304}
2305
2306
2307//--------------------------------------------------------------------------------------
2308HRESULT CDXUTLineManager::OnLostDevice()
2309{
2310    if( m_pD3DXLine )
2311        m_pD3DXLine->OnLostDevice();
2312
2313    return S_OK;
2314}
2315
2316
2317//--------------------------------------------------------------------------------------
2318HRESULT CDXUTLineManager::OnDeletedDevice()
2319{
2320    RemoveAllLines();
2321    SAFE_RELEASE( m_pD3DXLine );
2322
2323    return S_OK;
2324}
2325
2326
2327//--------------------------------------------------------------------------------------
2328HRESULT CDXUTLineManager::AddLine( int* pnLineID, D3DXVECTOR2* pVertexList, DWORD dwVertexListCount, D3DCOLOR Color, float fWidth, float fScaleRatio, bool bAntiAlias )
2329{
2330    if( pVertexList == NULL || dwVertexListCount == 0 )
2331        return E_INVALIDARG;
2332
2333    LINE_NODE* pLineNode = new LINE_NODE;
2334    if( pLineNode == NULL )
2335        return E_OUTOFMEMORY;
2336    ZeroMemory( pLineNode, sizeof(LINE_NODE) );
2337
2338    pLineNode->nLineID = m_LinesList.GetSize();
2339    pLineNode->Color = Color;
2340    pLineNode->fWidth = fWidth;
2341    pLineNode->bAntiAlias = bAntiAlias;
2342    pLineNode->dwVertexListCount = dwVertexListCount;
2343
2344    if( pnLineID )
2345        *pnLineID = pLineNode->nLineID;
2346
2347    pLineNode->pVertexList = new D3DXVECTOR2[dwVertexListCount];
2348    if( pLineNode->pVertexList == NULL )
2349    {
2350        delete pLineNode;
2351        return E_OUTOFMEMORY;
2352    }
2353    for( DWORD i=0; i<dwVertexListCount; i++ )
2354    {
2355        pLineNode->pVertexList[i] = pVertexList[i] * fScaleRatio;
2356    }
2357
2358    m_LinesList.Add( pLineNode );
2359
2360    return S_OK;
2361}
2362
2363
2364//--------------------------------------------------------------------------------------
2365HRESULT CDXUTLineManager::AddRect( int* pnLineID, RECT rc, D3DCOLOR Color, float fWidth, float fScaleRatio, bool bAntiAlias )
2366{
2367    if( fWidth > 2.0f )
2368    {
2369        D3DXVECTOR2 vertexList[8];
2370
2371        vertexList[0].x = (float)rc.left;
2372        vertexList[0].y = (float)rc.top - (fWidth/2.0f);
2373
2374        vertexList[1].x = (float)rc.left;
2375        vertexList[1].y = (float)rc.bottom + (fWidth/2.0f);
2376
2377        vertexList[2].x = (float)rc.left;
2378        vertexList[2].y = (float)rc.bottom - 0.5f;
2379
2380        vertexList[3].x = (float)rc.right;
2381        vertexList[3].y = (float)rc.bottom - 0.5f;
2382
2383        vertexList[4].x = (float)rc.right;
2384        vertexList[4].y = (float)rc.bottom + (fWidth/2.0f);
2385
2386        vertexList[5].x = (float)rc.right;
2387        vertexList[5].y = (float)rc.top - (fWidth/2.0f);
2388
2389        vertexList[6].x = (float)rc.right;
2390        vertexList[6].y = (float)rc.top;
2391
2392        vertexList[7].x = (float)rc.left;
2393        vertexList[7].y = (float)rc.top;
2394       
2395        return AddLine( pnLineID, vertexList, 8, Color, fWidth, fScaleRatio, bAntiAlias );
2396    }
2397    else
2398    {
2399        D3DXVECTOR2 vertexList[5];
2400        vertexList[0].x = (float)rc.left;
2401        vertexList[0].y = (float)rc.top;
2402
2403        vertexList[1].x = (float)rc.left;
2404        vertexList[1].y = (float)rc.bottom;
2405
2406        vertexList[2].x = (float)rc.right;
2407        vertexList[2].y = (float)rc.bottom;
2408
2409        vertexList[3].x = (float)rc.right;
2410        vertexList[3].y = (float)rc.top;
2411
2412        vertexList[4].x = (float)rc.left;
2413        vertexList[4].y = (float)rc.top;
2414       
2415        return AddLine( pnLineID, vertexList, 5, Color, fWidth, fScaleRatio, bAntiAlias );
2416    }
2417}
2418
2419
2420
2421//--------------------------------------------------------------------------------------
2422HRESULT CDXUTLineManager::RemoveLine( int nLineID )
2423{
2424    for( int i=0; i<m_LinesList.GetSize(); i++ )
2425    {
2426        LINE_NODE* pLineNode = m_LinesList.GetAt(i);
2427        if( pLineNode && pLineNode->nLineID == nLineID )
2428        {
2429            SAFE_DELETE_ARRAY( pLineNode->pVertexList );
2430            delete pLineNode;
2431            m_LinesList.SetAt(i, NULL);
2432        }
2433    }
2434
2435    return S_OK;
2436}
2437
2438
2439//--------------------------------------------------------------------------------------
2440HRESULT CDXUTLineManager::RemoveAllLines()
2441{
2442    for( int i=0; i<m_LinesList.GetSize(); i++ )
2443    {
2444        LINE_NODE* pLineNode = m_LinesList.GetAt(i);
2445        if( pLineNode )
2446        {
2447            SAFE_DELETE_ARRAY( pLineNode->pVertexList );
2448            delete pLineNode;
2449        }
2450    }
2451    m_LinesList.RemoveAll();
2452
2453    return S_OK;
2454}
2455
2456
2457//--------------------------------------------------------------------------------------
2458CDXUTTextHelper::CDXUTTextHelper( ID3DXFont* pFont, ID3DXSprite* pSprite, int nLineHeight )
2459{
2460    m_pFont = pFont;
2461    m_pSprite = pSprite;
2462    m_clr = D3DXCOLOR(1,1,1,1);
2463    m_pt.x = 0;
2464    m_pt.y = 0;
2465    m_nLineHeight = nLineHeight;
2466}
2467
2468
2469//--------------------------------------------------------------------------------------
2470HRESULT CDXUTTextHelper::DrawFormattedTextLine( const WCHAR* strMsg, ... )
2471{
2472    WCHAR strBuffer[512];
2473   
2474    va_list args;
2475    va_start(args, strMsg);
2476    StringCchVPrintf( strBuffer, 512, strMsg, args );
2477    strBuffer[511] = L'\0';
2478    va_end(args);
2479
2480    return DrawTextLine( strBuffer );
2481}
2482
2483
2484//--------------------------------------------------------------------------------------
2485HRESULT CDXUTTextHelper::DrawTextLine( const WCHAR* strMsg )
2486{
2487    if( NULL == m_pFont )
2488        return DXUT_ERR_MSGBOX( L"DrawTextLine", E_INVALIDARG );
2489
2490    HRESULT hr;
2491    RECT rc;
2492    SetRect( &rc, m_pt.x, m_pt.y, 0, 0 );
2493    hr = m_pFont->DrawText( m_pSprite, strMsg, -1, &rc, DT_NOCLIP, m_clr );
2494    if( FAILED(hr) )
2495        return DXTRACE_ERR_MSGBOX( L"DrawText", hr );
2496
2497    m_pt.y += m_nLineHeight;
2498
2499    return S_OK;
2500}
2501
2502
2503HRESULT CDXUTTextHelper::DrawFormattedTextLine( RECT &rc, DWORD dwFlags, const WCHAR* strMsg, ... )
2504{
2505    WCHAR strBuffer[512];
2506   
2507    va_list args;
2508    va_start(args, strMsg);
2509    StringCchVPrintf( strBuffer, 512, strMsg, args );
2510    strBuffer[511] = L'\0';
2511    va_end(args);
2512
2513    return DrawTextLine( rc, dwFlags, strBuffer );
2514}
2515
2516
2517HRESULT CDXUTTextHelper::DrawTextLine( RECT &rc, DWORD dwFlags, const WCHAR* strMsg )
2518{
2519    if( NULL == m_pFont )
2520        return DXUT_ERR_MSGBOX( L"DrawTextLine", E_INVALIDARG );
2521
2522    HRESULT hr;
2523    hr = m_pFont->DrawText( m_pSprite, strMsg, -1, &rc, dwFlags, m_clr );
2524    if( FAILED(hr) )
2525        return DXTRACE_ERR_MSGBOX( L"DrawText", hr );
2526
2527    m_pt.y += m_nLineHeight;
2528
2529    return S_OK;
2530}
2531
2532
2533//--------------------------------------------------------------------------------------
2534void CDXUTTextHelper::Begin()
2535{
2536    if( m_pSprite )
2537        m_pSprite->Begin( D3DXSPRITE_ALPHABLEND | D3DXSPRITE_SORT_TEXTURE );
2538}
2539void CDXUTTextHelper::End()
2540{
2541    if( m_pSprite )
2542        m_pSprite->End();
2543}
2544
2545
2546//--------------------------------------------------------------------------------------
2547IDirect3DDevice9* CDXUTDirectionWidget::s_pd3dDevice = NULL;
2548ID3DXEffect*      CDXUTDirectionWidget::s_pEffect = NULL;       
2549ID3DXMesh*        CDXUTDirectionWidget::s_pMesh = NULL;   
2550
2551
2552//--------------------------------------------------------------------------------------
2553CDXUTDirectionWidget::CDXUTDirectionWidget()
2554{
2555    m_fRadius = 1.0f;
2556    m_vDefaultDir = D3DXVECTOR3(0,1,0);
2557    m_vCurrentDir = m_vDefaultDir;
2558    m_nRotateMask = MOUSE_RIGHT_BUTTON;
2559
2560    D3DXMatrixIdentity( &m_mView );
2561    D3DXMatrixIdentity( &m_mRot );
2562    D3DXMatrixIdentity( &m_mRotSnapshot );
2563}
2564
2565
2566//--------------------------------------------------------------------------------------
2567HRESULT CDXUTDirectionWidget::StaticOnCreateDevice( IDirect3DDevice9* pd3dDevice )
2568{
2569    WCHAR str[MAX_PATH];
2570    HRESULT hr;
2571
2572    s_pd3dDevice = pd3dDevice;
2573   
2574    // Read the D3DX effect file
2575    V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"UI\\DXUTShared.fx" ) );
2576
2577    // If this fails, there should be debug output as to
2578    // why the .fx file failed to compile
2579    V_RETURN( D3DXCreateEffectFromFile( s_pd3dDevice, str, NULL, NULL, 0, NULL, &s_pEffect, NULL ) );
2580
2581    // Load the mesh with D3DX and get back a ID3DXMesh*.  For this
2582    // sample we'll ignore the X file's embedded materials since we know
2583    // exactly the model we're loading.  See the mesh samples such as
2584    // "OptimizedMesh" for a more generic mesh loading example.
2585    V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"UI\\arrow.x" ) );
2586
2587    V_RETURN( D3DXLoadMeshFromX( str, D3DXMESH_MANAGED, s_pd3dDevice, NULL,
2588                                 NULL, NULL, NULL, &s_pMesh) );
2589
2590    // Optimize the mesh for this graphics card's vertex cache
2591    // so when rendering the mesh's triangle list the vertices will
2592    // cache hit more often so it won't have to re-execute the vertex shader
2593    // on those vertices so it will improve perf.     
2594    DWORD* rgdwAdjacency = new DWORD[s_pMesh->GetNumFaces() * 3];
2595    if( rgdwAdjacency == NULL )
2596        return E_OUTOFMEMORY;
2597    V( s_pMesh->GenerateAdjacency(1e-6f,rgdwAdjacency) );
2598    V( s_pMesh->ConvertPointRepsToAdjacency(NULL, rgdwAdjacency) );
2599    V( s_pMesh->OptimizeInplace(D3DXMESHOPT_VERTEXCACHE, rgdwAdjacency, NULL, NULL, NULL) );
2600    delete []rgdwAdjacency;
2601
2602    return S_OK;
2603}
2604
2605
2606//--------------------------------------------------------------------------------------
2607HRESULT CDXUTDirectionWidget::OnResetDevice( const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
2608{
2609    m_ArcBall.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
2610    return S_OK;
2611}
2612
2613
2614//--------------------------------------------------------------------------------------
2615void CDXUTDirectionWidget::StaticOnLostDevice()
2616{
2617    if( s_pEffect )
2618        s_pEffect->OnLostDevice();
2619}
2620
2621
2622//--------------------------------------------------------------------------------------
2623void CDXUTDirectionWidget::StaticOnDestroyDevice()
2624{
2625    SAFE_RELEASE(s_pEffect);
2626    SAFE_RELEASE(s_pMesh);
2627}   
2628
2629
2630//--------------------------------------------------------------------------------------
2631LRESULT CDXUTDirectionWidget::HandleMessages( HWND hWnd, UINT uMsg,
2632                                              WPARAM wParam, LPARAM lParam )
2633{
2634    switch( uMsg )
2635    {
2636        case WM_LBUTTONDOWN:
2637        case WM_MBUTTONDOWN:
2638        case WM_RBUTTONDOWN:
2639        {
2640            if( ((m_nRotateMask & MOUSE_LEFT_BUTTON) != 0 && uMsg == WM_LBUTTONDOWN) ||
2641                ((m_nRotateMask & MOUSE_MIDDLE_BUTTON) != 0 && uMsg == WM_MBUTTONDOWN) ||
2642                ((m_nRotateMask & MOUSE_RIGHT_BUTTON) != 0 && uMsg == WM_RBUTTONDOWN) )
2643            {
2644                int iMouseX = (int)(short)LOWORD(lParam);
2645                int iMouseY = (int)(short)HIWORD(lParam);
2646                m_ArcBall.OnBegin( iMouseX, iMouseY );
2647                SetCapture(hWnd);
2648            }
2649            return TRUE;
2650        }
2651
2652        case WM_MOUSEMOVE:
2653        {
2654            if( m_ArcBall.IsBeingDragged() )
2655            {
2656                int iMouseX = (int)(short)LOWORD(lParam);
2657                int iMouseY = (int)(short)HIWORD(lParam);
2658                m_ArcBall.OnMove( iMouseX, iMouseY );
2659                UpdateLightDir();
2660            }
2661            return TRUE;
2662        }
2663
2664        case WM_LBUTTONUP:
2665        case WM_MBUTTONUP:
2666        case WM_RBUTTONUP:
2667        {
2668            if( ((m_nRotateMask & MOUSE_LEFT_BUTTON) != 0 && uMsg == WM_LBUTTONUP) ||
2669                ((m_nRotateMask & MOUSE_MIDDLE_BUTTON) != 0 && uMsg == WM_MBUTTONUP) ||
2670                ((m_nRotateMask & MOUSE_RIGHT_BUTTON) != 0 && uMsg == WM_RBUTTONUP) )
2671            {
2672                m_ArcBall.OnEnd();
2673                ReleaseCapture();
2674            }
2675
2676            UpdateLightDir();
2677            return TRUE;
2678        }
2679    }
2680
2681    return 0;
2682}
2683
2684
2685//--------------------------------------------------------------------------------------
2686HRESULT CDXUTDirectionWidget::OnRender( D3DXCOLOR color, const D3DXMATRIX* pmView,
2687                                        const D3DXMATRIX* pmProj, const D3DXVECTOR3* pEyePt )
2688{
2689    m_mView = *pmView;
2690
2691    // Render the light spheres so the user can visually see the light dir
2692    UINT iPass, cPasses;
2693    D3DXMATRIX mRotate;
2694    D3DXMATRIX mScale;
2695    D3DXMATRIX mTrans;
2696    D3DXMATRIXA16 mWorldViewProj;
2697    HRESULT hr;
2698
2699    V( s_pEffect->SetTechnique( "RenderWith1LightNoTexture" ) );
2700    V( s_pEffect->SetVector( "g_MaterialDiffuseColor", (D3DXVECTOR4*)&color ) );
2701
2702    D3DXVECTOR3 vEyePt;
2703    D3DXVec3Normalize( &vEyePt, pEyePt );
2704    V( s_pEffect->SetValue( "g_LightDir", &vEyePt, sizeof(D3DXVECTOR3) ) );
2705
2706    // Rotate arrow model to point towards origin
2707    D3DXMATRIX mRotateA, mRotateB;
2708    D3DXVECTOR3 vAt = D3DXVECTOR3(0,0,0);
2709    D3DXVECTOR3 vUp = D3DXVECTOR3(0,1,0);
2710    D3DXMatrixRotationX( &mRotateB, D3DX_PI );
2711    D3DXMatrixLookAtLH( &mRotateA, &m_vCurrentDir, &vAt, &vUp );
2712    D3DXMatrixInverse( &mRotateA, NULL, &mRotateA );
2713    mRotate = mRotateB * mRotateA;
2714
2715    D3DXVECTOR3 vL = m_vCurrentDir * m_fRadius * 1.0f;
2716    D3DXMatrixTranslation( &mTrans, vL.x, vL.y, vL.z );
2717    D3DXMatrixScaling( &mScale, m_fRadius*0.2f, m_fRadius*0.2f, m_fRadius*0.2f );
2718
2719    D3DXMATRIX mWorld = mRotate * mScale * mTrans;
2720    mWorldViewProj = mWorld * (m_mView) * (*pmProj);
2721
2722    V( s_pEffect->SetMatrix( "g_mWorldViewProjection", &mWorldViewProj ) );
2723    V( s_pEffect->SetMatrix( "g_mWorld", &mWorld ) );
2724
2725    for( int iSubset=0; iSubset<2; iSubset++ )
2726    {
2727        V( s_pEffect->Begin(&cPasses, 0) );
2728        for (iPass = 0; iPass < cPasses; iPass++)
2729        {
2730            V( s_pEffect->BeginPass(iPass) );
2731            V( s_pMesh->DrawSubset(iSubset) );
2732            V( s_pEffect->EndPass() );
2733        }
2734        V( s_pEffect->End() );
2735    }
2736
2737    return S_OK;
2738}
2739
2740
2741//--------------------------------------------------------------------------------------
2742HRESULT CDXUTDirectionWidget::UpdateLightDir()
2743{
2744    D3DXMATRIX mInvView;
2745    D3DXMatrixInverse(&mInvView, NULL, &m_mView);
2746    mInvView._41 = mInvView._42 = mInvView._43 = 0;
2747
2748    D3DXMATRIX mLastRotInv;
2749    D3DXMatrixInverse(&mLastRotInv, NULL, &m_mRotSnapshot);
2750
2751    D3DXMATRIX mRot = *m_ArcBall.GetRotationMatrix();
2752    m_mRotSnapshot = mRot;
2753
2754    // Accumulate the delta of the arcball's rotation in view space.
2755    // Note that per-frame delta rotations could be problematic over long periods of time.
2756    m_mRot *= m_mView * mLastRotInv * mRot * mInvView;
2757
2758    // Since we're accumulating delta rotations, we need to orthonormalize
2759    // the matrix to prevent eventual matrix skew
2760    D3DXVECTOR3* pXBasis = (D3DXVECTOR3*) &m_mRot._11;
2761    D3DXVECTOR3* pYBasis = (D3DXVECTOR3*) &m_mRot._21;
2762    D3DXVECTOR3* pZBasis = (D3DXVECTOR3*) &m_mRot._31;
2763    D3DXVec3Normalize( pXBasis, pXBasis );
2764    D3DXVec3Cross( pYBasis, pZBasis, pXBasis );
2765    D3DXVec3Normalize( pYBasis, pYBasis );
2766    D3DXVec3Cross( pZBasis, pXBasis, pYBasis );
2767
2768    // Transform the default direction vector by the light's rotation matrix
2769    D3DXVec3TransformNormal( &m_vCurrentDir, &m_vDefaultDir, &m_mRot );
2770
2771    return S_OK;
2772}
2773
2774//--------------------------------------------------------------------------------------
2775// Direct3D9 dynamic linking support -- calls top-level D3D9 APIs with graceful
2776// failure if APIs are not present.
2777//--------------------------------------------------------------------------------------
2778
2779// Function prototypes
2780typedef IDirect3D9* (WINAPI * LPDIRECT3DCREATE9) (UINT);
2781typedef INT         (WINAPI * LPD3DPERF_BEGINEVENT)(D3DCOLOR, LPCWSTR);
2782typedef INT         (WINAPI * LPD3DPERF_ENDEVENT)(void);
2783typedef VOID        (WINAPI * LPD3DPERF_SETMARKER)(D3DCOLOR, LPCWSTR);
2784typedef VOID        (WINAPI * LPD3DPERF_SETREGION)(D3DCOLOR, LPCWSTR);
2785typedef BOOL        (WINAPI * LPD3DPERF_QUERYREPEATFRAME)(void);
2786typedef VOID        (WINAPI * LPD3DPERF_SETOPTIONS)( DWORD dwOptions );
2787typedef DWORD       (WINAPI * LPD3DPERF_GETSTATUS)( void );
2788
2789// Module and function pointers
2790static HMODULE s_hModD3D9 = NULL;
2791static LPDIRECT3DCREATE9 s_DynamicDirect3DCreate9 = NULL;
2792static LPD3DPERF_BEGINEVENT s_DynamicD3DPERF_BeginEvent = NULL;
2793static LPD3DPERF_ENDEVENT s_DynamicD3DPERF_EndEvent = NULL;
2794static LPD3DPERF_SETMARKER s_DynamicD3DPERF_SetMarker = NULL;
2795static LPD3DPERF_SETREGION s_DynamicD3DPERF_SetRegion = NULL;
2796static LPD3DPERF_QUERYREPEATFRAME s_DynamicD3DPERF_QueryRepeatFrame = NULL;
2797static LPD3DPERF_SETOPTIONS s_DynamicD3DPERF_SetOptions = NULL;
2798static LPD3DPERF_GETSTATUS s_DynamicD3DPERF_GetStatus = NULL;
2799
2800// Ensure function pointers are initialized
2801static bool DXUT_EnsureD3DAPIs( void )
2802{
2803    // If module is non-NULL, this function has already been called.  Note
2804    // that this doesn't guarantee that all D3D9 procaddresses were found.
2805    if( s_hModD3D9 != NULL )
2806        return true;
2807
2808    // This may fail if DirectX 9 isn't installed
2809    WCHAR wszPath[MAX_PATH+1];
2810    if( !::GetSystemDirectory( wszPath, MAX_PATH+1 ) )
2811        return false;
2812    StringCchCat( wszPath, MAX_PATH, L"\\d3d9.dll" );
2813    s_hModD3D9 = LoadLibrary( wszPath );
2814    if( s_hModD3D9 == NULL )
2815        return false;
2816    s_DynamicDirect3DCreate9 = (LPDIRECT3DCREATE9)GetProcAddress( s_hModD3D9, "Direct3DCreate9" );
2817    s_DynamicD3DPERF_BeginEvent = (LPD3DPERF_BEGINEVENT)GetProcAddress( s_hModD3D9, "D3DPERF_BeginEvent" );
2818    s_DynamicD3DPERF_EndEvent = (LPD3DPERF_ENDEVENT)GetProcAddress( s_hModD3D9, "D3DPERF_EndEvent" );
2819    s_DynamicD3DPERF_SetMarker = (LPD3DPERF_SETMARKER)GetProcAddress( s_hModD3D9, "D3DPERF_SetMarker" );
2820    s_DynamicD3DPERF_SetRegion = (LPD3DPERF_SETREGION)GetProcAddress( s_hModD3D9, "D3DPERF_SetRegion" );
2821    s_DynamicD3DPERF_QueryRepeatFrame = (LPD3DPERF_QUERYREPEATFRAME)GetProcAddress( s_hModD3D9, "D3DPERF_QueryRepeatFrame" );
2822    s_DynamicD3DPERF_SetOptions = (LPD3DPERF_SETOPTIONS)GetProcAddress( s_hModD3D9, "D3DPERF_SetOptions" );
2823    s_DynamicD3DPERF_GetStatus = (LPD3DPERF_GETSTATUS)GetProcAddress( s_hModD3D9, "D3DPERF_GetStatus" );
2824    return true;
2825}
2826
2827IDirect3D9 * WINAPI DXUT_Dynamic_Direct3DCreate9(UINT SDKVersion)
2828{
2829    if( DXUT_EnsureD3DAPIs() && s_DynamicDirect3DCreate9 != NULL )
2830        return s_DynamicDirect3DCreate9( SDKVersion );
2831    else
2832        return NULL;
2833}
2834
2835int WINAPI DXUT_Dynamic_D3DPERF_BeginEvent( D3DCOLOR col, LPCWSTR wszName )
2836{
2837    if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_BeginEvent != NULL )
2838        return s_DynamicD3DPERF_BeginEvent( col, wszName );
2839    else
2840        return -1;
2841}
2842
2843int WINAPI DXUT_Dynamic_D3DPERF_EndEvent( void )
2844{
2845    if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_EndEvent != NULL )
2846        return s_DynamicD3DPERF_EndEvent();
2847    else
2848        return -1;
2849}
2850
2851void WINAPI DXUT_Dynamic_D3DPERF_SetMarker( D3DCOLOR col, LPCWSTR wszName )
2852{
2853    if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_SetMarker != NULL )
2854        s_DynamicD3DPERF_SetMarker( col, wszName );
2855}
2856
2857void WINAPI DXUT_Dynamic_D3DPERF_SetRegion( D3DCOLOR col, LPCWSTR wszName )
2858{
2859    if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_SetRegion != NULL )
2860        s_DynamicD3DPERF_SetRegion( col, wszName );
2861}
2862
2863BOOL WINAPI DXUT_Dynamic_D3DPERF_QueryRepeatFrame( void )
2864{
2865    if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_QueryRepeatFrame != NULL )
2866        return s_DynamicD3DPERF_QueryRepeatFrame();
2867    else
2868        return FALSE;
2869}
2870
2871void WINAPI DXUT_Dynamic_D3DPERF_SetOptions( DWORD dwOptions )
2872{
2873    if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_SetOptions != NULL )
2874        s_DynamicD3DPERF_SetOptions( dwOptions );
2875}
2876
2877DWORD WINAPI DXUT_Dynamic_D3DPERF_GetStatus( void )
2878{
2879    if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_GetStatus != NULL )
2880        return s_DynamicD3DPERF_GetStatus();
2881    else
2882        return 0;
2883}
Note: See TracBrowser for help on using the repository browser.