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

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