mirror of
https://github.com/dashr9230/SA-MP.git
synced 2025-01-04 00:23:22 +08:00
2876 lines
101 KiB
C++
2876 lines
101 KiB
C++
//--------------------------------------------------------------------------------------
|
|
// File: DXUTMisc.cpp
|
|
//
|
|
// Shortcut macros and functions for using DX objects
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved
|
|
//--------------------------------------------------------------------------------------
|
|
#include "dxstdafx.h"
|
|
#undef min // use __min instead
|
|
#undef max // use __max instead
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Global/Static Members
|
|
//--------------------------------------------------------------------------------------
|
|
// MATCH
|
|
CDXUTResourceCache& DXUTGetGlobalResourceCache()
|
|
{
|
|
// Using an accessor function gives control of the construction order
|
|
static CDXUTResourceCache cache;
|
|
return cache;
|
|
}
|
|
// MATCH
|
|
CDXUTTimer* DXUTGetGlobalTimer()
|
|
{
|
|
// Using an accessor function gives control of the construction order
|
|
static CDXUTTimer timer;
|
|
return &timer;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Internal functions forward declarations
|
|
//--------------------------------------------------------------------------------------
|
|
bool DXUTFindMediaSearchTypicalDirs( TCHAR* strSearchPath, int cchSearch, LPCTSTR strLeaf, TCHAR* strExePath, TCHAR* strExeName );
|
|
bool DXUTFindMediaSearchParentDirs( TCHAR* strSearchPath, int cchSearch, TCHAR* strStartAt, TCHAR* strLeafName );
|
|
INT_PTR CALLBACK DisplaySwitchToREFWarningProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Shared code for samples to ask user if they want to use a REF device or quit
|
|
//--------------------------------------------------------------------------------------
|
|
void DXUTDisplaySwitchingToREFWarning()
|
|
{
|
|
if( DXUTGetShowMsgBoxOnError() )
|
|
{
|
|
// Open the appropriate registry key
|
|
DWORD dwSkipWarning = 0;
|
|
HKEY hKey;
|
|
LONG lResult = RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\Microsoft\\DirectX 9.0 SDK", 0, KEY_READ, &hKey );
|
|
if( ERROR_SUCCESS == lResult )
|
|
{
|
|
DWORD dwType;
|
|
DWORD dwSize = sizeof(DWORD);
|
|
lResult = RegQueryValueEx( hKey, "Skip Warning On REF", NULL, &dwType, (BYTE*)&dwSkipWarning, &dwSize );
|
|
RegCloseKey( hKey );
|
|
}
|
|
|
|
if( dwSkipWarning == 0 )
|
|
{
|
|
// Compact code to create a custom dialog box without using a template in a resource file.
|
|
// If this dialog were in a .rc file, this would be a lot simpler but every sample calling this function would
|
|
// need a copy of the dialog in its own .rc file. Also MessageBox API could be used here instead, but
|
|
// the MessageBox API is simpler to call but it can't provide a "Don't show again" checkbox
|
|
typedef struct { DLGITEMTEMPLATE a; WORD b; WORD c; WORD d; WORD e; WORD f; } DXUT_DLG_ITEM;
|
|
typedef struct { DLGTEMPLATE a; WORD b; WORD c; TCHAR d[2]; WORD e; TCHAR f[14]; DXUT_DLG_ITEM i1; DXUT_DLG_ITEM i2; DXUT_DLG_ITEM i3; DXUT_DLG_ITEM i4; DXUT_DLG_ITEM i5; } DXUT_DLG_DATA;
|
|
|
|
DXUT_DLG_DATA dtp =
|
|
{
|
|
{WS_CAPTION|WS_POPUP|WS_VISIBLE|WS_SYSMENU|DS_ABSALIGN|DS_3DLOOK|DS_SETFONT|DS_MODALFRAME|DS_CENTER,0,5,0,0,269,82},0,0," ",8,"MS Sans Serif",
|
|
{{WS_CHILD|WS_VISIBLE|SS_ICON|SS_CENTERIMAGE,0,7,7,24,24,0x100},0xFFFF,0x0082,0,0,0}, // icon
|
|
{{WS_CHILD|WS_VISIBLE,0,40,7,230,25,0x101},0xFFFF,0x0082,0,0,0}, // static text
|
|
{{WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON,0,80,39,50,14,IDYES},0xFFFF,0x0080,0,0,0}, // Yes button
|
|
{{WS_CHILD|WS_VISIBLE,0,133,39,50,14,IDNO},0xFFFF,0x0080,0,0,0}, // No button
|
|
{{WS_CHILD|WS_VISIBLE|BS_CHECKBOX,0,7,59,70,16,IDIGNORE},0xFFFF,0x0080,0,0,0}, // checkbox
|
|
};
|
|
|
|
int nResult = (int) DialogBoxIndirect( DXUTGetHINSTANCE(), (DLGTEMPLATE*)&dtp, DXUTGetHWND(), DisplaySwitchToREFWarningProc );
|
|
|
|
if( (nResult & 0x80) == 0x80 ) // "Don't show again" checkbox was checked
|
|
{
|
|
lResult = RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\Microsoft\\DirectX 9.0 SDK", 0, KEY_WRITE, &hKey );
|
|
if( ERROR_SUCCESS == lResult )
|
|
{
|
|
dwSkipWarning = 1;
|
|
RegSetValueEx( hKey, "Skip Warning On REF", 0, REG_DWORD, (BYTE*)&dwSkipWarning, sizeof(DWORD) );
|
|
RegCloseKey( hKey );
|
|
}
|
|
}
|
|
|
|
// User choose not to continue
|
|
if( (nResult & 0x0F) == IDNO )
|
|
DXUTShutdown(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// MsgProc for DXUTDisplaySwitchingToREFWarning() dialog box
|
|
//--------------------------------------------------------------------------------------
|
|
INT_PTR CALLBACK DisplaySwitchToREFWarningProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
// Easier to set text here than in the DLGITEMTEMPLATE
|
|
SetWindowText( hDlg, DXUTGetWindowTitle() );
|
|
SendMessage( GetDlgItem(hDlg, 0x100), STM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIcon(0, IDI_QUESTION));
|
|
SetDlgItemText( hDlg, 0x101, "Switching to the Direct3D reference rasterizer, a software device\nthat implements the entire Direct3D feature set, but runs very slowly.\nDo you wish to continue?" );
|
|
SetDlgItemText( hDlg, IDYES, "&Yes" );
|
|
SetDlgItemText( hDlg, IDNO, "&No" );
|
|
SetDlgItemText( hDlg, IDIGNORE, "&Don't show again" );
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDIGNORE: CheckDlgButton( hDlg, IDIGNORE, (IsDlgButtonChecked( hDlg, IDIGNORE ) == BST_CHECKED) ? BST_UNCHECKED : BST_CHECKED ); EnableWindow( GetDlgItem( hDlg, IDNO ), (IsDlgButtonChecked( hDlg, IDIGNORE ) != BST_CHECKED) ); break;
|
|
case IDNO: EndDialog(hDlg, (IsDlgButtonChecked( hDlg, IDIGNORE ) == BST_CHECKED) ? IDNO|0x80 : IDNO|0x00 ); return TRUE;
|
|
case IDCANCEL:
|
|
case IDYES: EndDialog(hDlg, (IsDlgButtonChecked( hDlg, IDIGNORE ) == BST_CHECKED) ? IDYES|0x80 : IDYES|0x00 ); return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// MATCH
|
|
CDXUTTimer::CDXUTTimer()
|
|
{
|
|
m_bUsingQPF = false;
|
|
m_bTimerStopped = true;
|
|
m_llQPFTicksPerSec = 0;
|
|
|
|
m_llStopTime = 0;
|
|
m_llLastElapsedTime = 0;
|
|
m_llBaseTime = 0;
|
|
|
|
// Use QueryPerformanceFrequency() to get frequency of timer.
|
|
LARGE_INTEGER qwTicksPerSec;
|
|
m_bUsingQPF = (bool) (QueryPerformanceFrequency( &qwTicksPerSec ) != 0);
|
|
m_llQPFTicksPerSec = qwTicksPerSec.QuadPart;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// MATCH
|
|
void CDXUTTimer::Reset()
|
|
{
|
|
if( !m_bUsingQPF )
|
|
return;
|
|
|
|
// Get either the current time or the stop time
|
|
LARGE_INTEGER qwTime;
|
|
if( m_llStopTime != 0 )
|
|
qwTime.QuadPart = m_llStopTime;
|
|
else
|
|
QueryPerformanceCounter( &qwTime );
|
|
|
|
m_llBaseTime = qwTime.QuadPart;
|
|
m_llLastElapsedTime = qwTime.QuadPart;
|
|
m_llStopTime = 0;
|
|
m_bTimerStopped = FALSE;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// MATCH
|
|
void CDXUTTimer::Start()
|
|
{
|
|
if( !m_bUsingQPF )
|
|
return;
|
|
|
|
// Get the current time
|
|
LARGE_INTEGER qwTime;
|
|
QueryPerformanceCounter( &qwTime );
|
|
|
|
if( m_bTimerStopped )
|
|
m_llBaseTime += qwTime.QuadPart - m_llStopTime;
|
|
m_llStopTime = 0;
|
|
m_llLastElapsedTime = qwTime.QuadPart;
|
|
m_bTimerStopped = FALSE;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// MATCH
|
|
void CDXUTTimer::Stop()
|
|
{
|
|
if( !m_bUsingQPF )
|
|
return;
|
|
|
|
if( !m_bTimerStopped )
|
|
{
|
|
// Get either the current time or the stop time
|
|
LARGE_INTEGER qwTime;
|
|
if( m_llStopTime != 0 )
|
|
qwTime.QuadPart = m_llStopTime;
|
|
else
|
|
QueryPerformanceCounter( &qwTime );
|
|
|
|
m_llStopTime = qwTime.QuadPart;
|
|
m_llLastElapsedTime = qwTime.QuadPart;
|
|
m_bTimerStopped = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// MATCH
|
|
void CDXUTTimer::Advance()
|
|
{
|
|
if( !m_bUsingQPF )
|
|
return;
|
|
|
|
m_llStopTime += m_llQPFTicksPerSec/10;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// MATCH
|
|
double CDXUTTimer::GetAbsoluteTime()
|
|
{
|
|
if( !m_bUsingQPF )
|
|
return -1.0;
|
|
|
|
// Get either the current time or the stop time
|
|
LARGE_INTEGER qwTime;
|
|
if( m_llStopTime != 0 )
|
|
qwTime.QuadPart = m_llStopTime;
|
|
else
|
|
QueryPerformanceCounter( &qwTime );
|
|
|
|
double fTime = qwTime.QuadPart / (double) m_llQPFTicksPerSec;
|
|
|
|
return fTime;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// MATCH
|
|
double CDXUTTimer::GetTime()
|
|
{
|
|
if( !m_bUsingQPF )
|
|
return -1.0;
|
|
|
|
// Get either the current time or the stop time
|
|
LARGE_INTEGER qwTime;
|
|
if( m_llStopTime != 0 )
|
|
qwTime.QuadPart = m_llStopTime;
|
|
else
|
|
QueryPerformanceCounter( &qwTime );
|
|
|
|
double fAppTime = (double) ( qwTime.QuadPart - m_llBaseTime ) / (double) m_llQPFTicksPerSec;
|
|
|
|
return fAppTime;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// MATCH
|
|
double CDXUTTimer::GetElapsedTime()
|
|
{
|
|
if( !m_bUsingQPF )
|
|
return -1.0;
|
|
|
|
// Get either the current time or the stop time
|
|
LARGE_INTEGER qwTime;
|
|
if( m_llStopTime != 0 )
|
|
qwTime.QuadPart = m_llStopTime;
|
|
else
|
|
QueryPerformanceCounter( &qwTime );
|
|
|
|
double fElapsedTime = (double) ( qwTime.QuadPart - m_llLastElapsedTime ) / (double) m_llQPFTicksPerSec;
|
|
m_llLastElapsedTime = qwTime.QuadPart;
|
|
|
|
return fElapsedTime;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// MATCH
|
|
bool CDXUTTimer::IsStopped()
|
|
{
|
|
return m_bTimerStopped;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Returns pointer to static media search buffer
|
|
//--------------------------------------------------------------------------------------
|
|
// MATCH
|
|
TCHAR* DXUTMediaSearchPath()
|
|
{
|
|
static TCHAR s_strMediaSearchPath[MAX_PATH] = {0};
|
|
return s_strMediaSearchPath;
|
|
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// MATCH
|
|
LPCTSTR DXUTGetMediaSearchPath()
|
|
{
|
|
return DXUTMediaSearchPath();
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// MATCH
|
|
HRESULT DXUTSetMediaSearchPath( LPCTSTR strPath )
|
|
{
|
|
HRESULT hr;
|
|
|
|
TCHAR* s_strSearchPath = DXUTMediaSearchPath();
|
|
|
|
hr = StringCchCopy( s_strSearchPath, MAX_PATH, strPath );
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
// append slash if needed
|
|
size_t ch;
|
|
hr = StringCchLength( s_strSearchPath, MAX_PATH, &ch );
|
|
if( SUCCEEDED(hr) && s_strSearchPath[ch-1] != L'\\')
|
|
{
|
|
hr = StringCchCat( s_strSearchPath, MAX_PATH, "\\" );
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Tries to find the location of a SDK media file
|
|
// cchDest is the size in TCHARs of strDestPath. Be careful not to
|
|
// pass in sizeof(strDest) on UNICODE builds.
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT DXUTFindDXSDKMediaFileCch( TCHAR* strDestPath, int cchDest, LPCTSTR strFilename )
|
|
{
|
|
bool bFound;
|
|
TCHAR strSearchFor[MAX_PATH];
|
|
|
|
if( NULL==strFilename || strFilename[0] == 0 || NULL==strDestPath || cchDest < 10 )
|
|
return E_INVALIDARG;
|
|
|
|
// Get the exe name, and exe path
|
|
TCHAR strExePath[MAX_PATH] = {0};
|
|
TCHAR strExeName[MAX_PATH] = {0};
|
|
TCHAR* strLastSlash = NULL;
|
|
GetModuleFileName( NULL, strExePath, MAX_PATH );
|
|
strExePath[MAX_PATH-1]=0;
|
|
strLastSlash = strrchr( strExePath, TEXT('\\') );
|
|
if( strLastSlash )
|
|
{
|
|
StringCchCopy( strExeName, MAX_PATH, &strLastSlash[1] );
|
|
|
|
// Chop the exe name from the exe path
|
|
*strLastSlash = 0;
|
|
|
|
// Chop the .exe from the exe name
|
|
strLastSlash = strrchr( strExeName, TEXT('.') );
|
|
if( strLastSlash )
|
|
*strLastSlash = 0;
|
|
}
|
|
|
|
// Typical directories:
|
|
// .\
|
|
// ..\
|
|
// ..\..\
|
|
// %EXE_DIR%\
|
|
// %EXE_DIR%\..\
|
|
// %EXE_DIR%\..\..\
|
|
// %EXE_DIR%\..\%EXE_NAME%
|
|
// %EXE_DIR%\..\..\%EXE_NAME%
|
|
|
|
// Typical directory search
|
|
bFound = DXUTFindMediaSearchTypicalDirs( strDestPath, cchDest, strFilename, strExePath, strExeName );
|
|
if( bFound )
|
|
return S_OK;
|
|
|
|
// Typical directory search again, but also look in a subdir called "\media\"
|
|
StringCchPrintf( strSearchFor, MAX_PATH, "media\\%s", strFilename );
|
|
bFound = DXUTFindMediaSearchTypicalDirs( strDestPath, cchDest, strSearchFor, strExePath, strExeName );
|
|
if( bFound )
|
|
return S_OK;
|
|
|
|
TCHAR strLeafName[MAX_PATH] = {0};
|
|
|
|
// Search all parent directories starting at .\ and using strFilename as the leaf name
|
|
StringCchCopy( strLeafName, MAX_PATH, strFilename );
|
|
bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, ".", strLeafName );
|
|
if( bFound )
|
|
return S_OK;
|
|
|
|
// Search all parent directories starting at the exe's dir and using strFilename as the leaf name
|
|
bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, strExePath, strLeafName );
|
|
if( bFound )
|
|
return S_OK;
|
|
|
|
// Search all parent directories starting at .\ and using "media\strFilename" as the leaf name
|
|
StringCchPrintf( strLeafName, MAX_PATH, "media\\%s", strFilename );
|
|
bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, ".", strLeafName );
|
|
if( bFound )
|
|
return S_OK;
|
|
|
|
// Search all parent directories starting at the exe's dir and using "media\strFilename" as the leaf name
|
|
bFound = DXUTFindMediaSearchParentDirs( strDestPath, cchDest, strExePath, strLeafName );
|
|
if( bFound )
|
|
return S_OK;
|
|
|
|
// On failure, return the file as the path but also return an error code
|
|
StringCchCopy( strDestPath, cchDest, strFilename );
|
|
|
|
return DXUTERR_MEDIANOTFOUND;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Search a set of typical directories
|
|
//--------------------------------------------------------------------------------------
|
|
// MATCH
|
|
bool DXUTFindMediaSearchTypicalDirs( TCHAR* strSearchPath, int cchSearch, LPCTSTR strLeaf,
|
|
TCHAR* strExePath, TCHAR* strExeName )
|
|
{
|
|
// Typical directories:
|
|
// .\
|
|
// ..\
|
|
// ..\..\
|
|
// %EXE_DIR%\
|
|
// %EXE_DIR%\..\
|
|
// %EXE_DIR%\..\..\
|
|
// %EXE_DIR%\..\%EXE_NAME%
|
|
// %EXE_DIR%\..\..\%EXE_NAME%
|
|
// DXSDK media path
|
|
|
|
// Search in .\
|
|
StringCchCopy( strSearchPath, cchSearch, strLeaf );
|
|
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
|
|
return true;
|
|
|
|
// Search in ..\
|
|
StringCchPrintf( strSearchPath, cchSearch, "..\\%s", strLeaf );
|
|
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
|
|
return true;
|
|
|
|
// Search in ..\..\
|
|
StringCchPrintf( strSearchPath, cchSearch, "..\\..\\%s", strLeaf );
|
|
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
|
|
return true;
|
|
|
|
// Search in ..\..\
|
|
StringCchPrintf( strSearchPath, cchSearch, "..\\..\\%s", strLeaf );
|
|
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
|
|
return true;
|
|
|
|
// Search in the %EXE_DIR%\
|
|
StringCchPrintf( strSearchPath, cchSearch, "%s\\%s", strExePath, strLeaf );
|
|
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
|
|
return true;
|
|
|
|
// Search in the %EXE_DIR%\..\
|
|
StringCchPrintf( strSearchPath, cchSearch, "%s\\..\\%s", strExePath, strLeaf );
|
|
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
|
|
return true;
|
|
|
|
// Search in the %EXE_DIR%\..\..\
|
|
StringCchPrintf( strSearchPath, cchSearch, "%s\\..\\..\\%s", strExePath, strLeaf );
|
|
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
|
|
return true;
|
|
|
|
// Search in "%EXE_DIR%\..\%EXE_NAME%\". This matches the DirectX SDK layout
|
|
StringCchPrintf( strSearchPath, cchSearch, "%s\\..\\%s\\%s", strExePath, strExeName, strLeaf );
|
|
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
|
|
return true;
|
|
|
|
// Search in "%EXE_DIR%\..\..\%EXE_NAME%\". This matches the DirectX SDK layout
|
|
StringCchPrintf( strSearchPath, cchSearch, "%s\\..\\..\\%s\\%s", strExePath, strExeName, strLeaf );
|
|
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
|
|
return true;
|
|
|
|
// Search in media search dir
|
|
TCHAR* s_strSearchPath = DXUTMediaSearchPath();
|
|
if( s_strSearchPath[0] != 0 )
|
|
{
|
|
StringCchPrintf( strSearchPath, cchSearch, "%s%s", s_strSearchPath, strLeaf );
|
|
if( GetFileAttributes( strSearchPath ) != 0xFFFFFFFF )
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Search parent directories starting at strStartAt, and appending strLeafName
|
|
// at each parent directory. It stops at the root directory.
|
|
//--------------------------------------------------------------------------------------
|
|
// MATCH
|
|
bool DXUTFindMediaSearchParentDirs( TCHAR* strSearchPath, int cchSearch, TCHAR* strStartAt, TCHAR* strLeafName )
|
|
{
|
|
TCHAR strFullPath[MAX_PATH] = {0};
|
|
TCHAR strFullFileName[MAX_PATH] = {0};
|
|
TCHAR strSearch[MAX_PATH] = {0};
|
|
TCHAR* strFilePart = NULL;
|
|
|
|
GetFullPathName( strStartAt, MAX_PATH, strFullPath, &strFilePart );
|
|
if( strFilePart == NULL )
|
|
return false;
|
|
|
|
while( strFilePart != NULL && *strFilePart != '\0' )
|
|
{
|
|
StringCchPrintf( strFullFileName, MAX_PATH, "%s\\%s", strFullPath, strLeafName );
|
|
if( GetFileAttributes( strFullFileName ) != 0xFFFFFFFF )
|
|
{
|
|
StringCchCopy( strSearchPath, cchSearch, strFullFileName );
|
|
return true;
|
|
}
|
|
|
|
StringCchPrintf( strSearch, MAX_PATH, "%s\\..", strFullPath );
|
|
GetFullPathName( strSearch, MAX_PATH, strFullPath, &strFilePart );
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// CDXUTResourceCache
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
//MATCH
|
|
CDXUTResourceCache::~CDXUTResourceCache()
|
|
{
|
|
OnDestroyDevice();
|
|
|
|
m_TextureCache.RemoveAll();
|
|
m_EffectCache.RemoveAll();
|
|
m_FontCache.RemoveAll();
|
|
}
|
|
|
|
|
|
HRESULT CDXUTResourceCache::CreateTextureFromFile( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, LPDIRECT3DTEXTURE9 *ppTexture )
|
|
{
|
|
return CreateTextureFromFileEx( pDevice, pSrcFile, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
|
|
0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT,
|
|
0, NULL, NULL, ppTexture );
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT 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 )
|
|
{
|
|
// Search the cache for a matching entry.
|
|
for( int i = 0; i < m_TextureCache.GetSize(); ++i )
|
|
{
|
|
DXUTCache_Texture &Entry = m_TextureCache[i];
|
|
if( Entry.Location == DXUTCACHE_LOCATION_FILE &&
|
|
!lstrcmpA( Entry.wszSource, pSrcFile ) &&
|
|
Entry.Width == Width &&
|
|
Entry.Height == Height &&
|
|
Entry.MipLevels == MipLevels &&
|
|
Entry.Usage == Usage &&
|
|
Entry.Format == Format &&
|
|
Entry.Pool == Pool &&
|
|
Entry.Type == D3DRTYPE_TEXTURE )
|
|
{
|
|
// A match is found. Obtain the IDirect3DTexture9 interface and return that.
|
|
return Entry.pTexture->QueryInterface( IID_IDirect3DTexture9, (LPVOID*)ppTexture );
|
|
}
|
|
}
|
|
|
|
HRESULT hr;
|
|
|
|
// No matching entry. Load the resource and create a new entry.
|
|
hr = D3DXCreateTextureFromFileEx( pDevice, pSrcFile, Width, Height, MipLevels, Usage, Format,
|
|
Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppTexture );
|
|
if( FAILED( hr ) )
|
|
return hr;
|
|
|
|
DXUTCache_Texture NewEntry;
|
|
NewEntry.Location = DXUTCACHE_LOCATION_FILE;
|
|
StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcFile );
|
|
NewEntry.Width = Width;
|
|
NewEntry.Height = Height;
|
|
NewEntry.MipLevels = MipLevels;
|
|
NewEntry.Usage = Usage;
|
|
NewEntry.Format = Format;
|
|
NewEntry.Pool = Pool;
|
|
NewEntry.Type = D3DRTYPE_TEXTURE;
|
|
(*ppTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
|
|
|
|
m_TextureCache.Add( NewEntry );
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTResourceCache::CreateTextureFromResource( LPDIRECT3DDEVICE9 pDevice, HMODULE hSrcModule, LPCTSTR pSrcResource, LPDIRECT3DTEXTURE9 *ppTexture )
|
|
{
|
|
return CreateTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, D3DX_DEFAULT, D3DX_DEFAULT,
|
|
D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT,
|
|
D3DX_DEFAULT, 0, NULL, NULL, ppTexture );
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT 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 )
|
|
{
|
|
// Search the cache for a matching entry.
|
|
for( int i = 0; i < m_TextureCache.GetSize(); ++i )
|
|
{
|
|
DXUTCache_Texture &Entry = m_TextureCache[i];
|
|
if( Entry.Location == DXUTCACHE_LOCATION_RESOURCE &&
|
|
Entry.hSrcModule == hSrcModule &&
|
|
!lstrcmpA( Entry.wszSource, pSrcResource ) &&
|
|
Entry.Width == Width &&
|
|
Entry.Height == Height &&
|
|
Entry.MipLevels == MipLevels &&
|
|
Entry.Usage == Usage &&
|
|
Entry.Format == Format &&
|
|
Entry.Pool == Pool &&
|
|
Entry.Type == D3DRTYPE_TEXTURE )
|
|
{
|
|
// A match is found. Obtain the IDirect3DTexture9 interface and return that.
|
|
return Entry.pTexture->QueryInterface( IID_IDirect3DTexture9, (LPVOID*)ppTexture );
|
|
}
|
|
}
|
|
|
|
HRESULT hr;
|
|
|
|
// No matching entry. Load the resource and create a new entry.
|
|
hr = D3DXCreateTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, Width, Height, MipLevels, Usage,
|
|
Format, Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppTexture );
|
|
if( FAILED( hr ) )
|
|
return hr;
|
|
|
|
DXUTCache_Texture NewEntry;
|
|
NewEntry.Location = DXUTCACHE_LOCATION_RESOURCE;
|
|
NewEntry.hSrcModule = hSrcModule;
|
|
StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcResource );
|
|
NewEntry.Width = Width;
|
|
NewEntry.Height = Height;
|
|
NewEntry.MipLevels = MipLevels;
|
|
NewEntry.Usage = Usage;
|
|
NewEntry.Format = Format;
|
|
NewEntry.Pool = Pool;
|
|
NewEntry.Type = D3DRTYPE_TEXTURE;
|
|
(*ppTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
|
|
|
|
m_TextureCache.Add( NewEntry );
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTResourceCache::CreateCubeTextureFromFile( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, LPDIRECT3DCUBETEXTURE9 *ppCubeTexture )
|
|
{
|
|
return CreateCubeTextureFromFileEx( pDevice, pSrcFile, D3DX_DEFAULT, D3DX_DEFAULT, 0,
|
|
D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT,
|
|
0, NULL, NULL, ppCubeTexture );
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT 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 )
|
|
{
|
|
// Search the cache for a matching entry.
|
|
for( int i = 0; i < m_TextureCache.GetSize(); ++i )
|
|
{
|
|
DXUTCache_Texture &Entry = m_TextureCache[i];
|
|
if( Entry.Location == DXUTCACHE_LOCATION_FILE &&
|
|
!lstrcmpA( Entry.wszSource, pSrcFile ) &&
|
|
Entry.Width == Size &&
|
|
Entry.MipLevels == MipLevels &&
|
|
Entry.Usage == Usage &&
|
|
Entry.Format == Format &&
|
|
Entry.Pool == Pool &&
|
|
Entry.Type == D3DRTYPE_CUBETEXTURE )
|
|
{
|
|
// A match is found. Obtain the IDirect3DCubeTexture9 interface and return that.
|
|
return Entry.pTexture->QueryInterface( IID_IDirect3DCubeTexture9, (LPVOID*)ppCubeTexture );
|
|
}
|
|
}
|
|
|
|
HRESULT hr;
|
|
|
|
// No matching entry. Load the resource and create a new entry.
|
|
hr = D3DXCreateCubeTextureFromFileEx( pDevice, pSrcFile, Size, MipLevels, Usage, Format, Pool, Filter,
|
|
MipFilter, ColorKey, pSrcInfo, pPalette, ppCubeTexture );
|
|
if( FAILED( hr ) )
|
|
return hr;
|
|
|
|
DXUTCache_Texture NewEntry;
|
|
NewEntry.Location = DXUTCACHE_LOCATION_FILE;
|
|
StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcFile );
|
|
NewEntry.Width = Size;
|
|
NewEntry.MipLevels = MipLevels;
|
|
NewEntry.Usage = Usage;
|
|
NewEntry.Format = Format;
|
|
NewEntry.Pool = Pool;
|
|
NewEntry.Type = D3DRTYPE_CUBETEXTURE;
|
|
(*ppCubeTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
|
|
|
|
m_TextureCache.Add( NewEntry );
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTResourceCache::CreateCubeTextureFromResource( LPDIRECT3DDEVICE9 pDevice, HMODULE hSrcModule, LPCTSTR pSrcResource, LPDIRECT3DCUBETEXTURE9 *ppCubeTexture )
|
|
{
|
|
return CreateCubeTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, D3DX_DEFAULT, D3DX_DEFAULT,
|
|
0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT,
|
|
0, NULL, NULL, ppCubeTexture );
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT 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 )
|
|
{
|
|
// Search the cache for a matching entry.
|
|
for( int i = 0; i < m_TextureCache.GetSize(); ++i )
|
|
{
|
|
DXUTCache_Texture &Entry = m_TextureCache[i];
|
|
if( Entry.Location == DXUTCACHE_LOCATION_RESOURCE &&
|
|
Entry.hSrcModule == hSrcModule &&
|
|
!lstrcmpA( Entry.wszSource, pSrcResource ) &&
|
|
Entry.Width == Size &&
|
|
Entry.MipLevels == MipLevels &&
|
|
Entry.Usage == Usage &&
|
|
Entry.Format == Format &&
|
|
Entry.Pool == Pool &&
|
|
Entry.Type == D3DRTYPE_CUBETEXTURE )
|
|
{
|
|
// A match is found. Obtain the IDirect3DCubeTexture9 interface and return that.
|
|
return Entry.pTexture->QueryInterface( IID_IDirect3DCubeTexture9, (LPVOID*)ppCubeTexture );
|
|
}
|
|
}
|
|
|
|
HRESULT hr;
|
|
|
|
// No matching entry. Load the resource and create a new entry.
|
|
hr = D3DXCreateCubeTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, Size, MipLevels, Usage, Format,
|
|
Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppCubeTexture );
|
|
if( FAILED( hr ) )
|
|
return hr;
|
|
|
|
DXUTCache_Texture NewEntry;
|
|
NewEntry.Location = DXUTCACHE_LOCATION_RESOURCE;
|
|
NewEntry.hSrcModule = hSrcModule;
|
|
StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcResource );
|
|
NewEntry.Width = Size;
|
|
NewEntry.MipLevels = MipLevels;
|
|
NewEntry.Usage = Usage;
|
|
NewEntry.Format = Format;
|
|
NewEntry.Pool = Pool;
|
|
NewEntry.Type = D3DRTYPE_CUBETEXTURE;
|
|
(*ppCubeTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
|
|
|
|
m_TextureCache.Add( NewEntry );
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTResourceCache::CreateVolumeTextureFromFile( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, LPDIRECT3DVOLUMETEXTURE9 *ppVolumeTexture )
|
|
{
|
|
return CreateVolumeTextureFromFileEx( pDevice, pSrcFile, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
|
|
0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT,
|
|
0, NULL, NULL, ppVolumeTexture );
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT 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 )
|
|
{
|
|
// Search the cache for a matching entry.
|
|
for( int i = 0; i < m_TextureCache.GetSize(); ++i )
|
|
{
|
|
DXUTCache_Texture &Entry = m_TextureCache[i];
|
|
if( Entry.Location == DXUTCACHE_LOCATION_FILE &&
|
|
!lstrcmpA( Entry.wszSource, pSrcFile ) &&
|
|
Entry.Width == Width &&
|
|
Entry.Height == Height &&
|
|
Entry.Depth == Depth &&
|
|
Entry.MipLevels == MipLevels &&
|
|
Entry.Usage == Usage &&
|
|
Entry.Format == Format &&
|
|
Entry.Pool == Pool &&
|
|
Entry.Type == D3DRTYPE_VOLUMETEXTURE )
|
|
{
|
|
// A match is found. Obtain the IDirect3DVolumeTexture9 interface and return that.
|
|
return Entry.pTexture->QueryInterface( IID_IDirect3DVolumeTexture9, (LPVOID*)ppTexture );
|
|
}
|
|
}
|
|
|
|
HRESULT hr;
|
|
|
|
// No matching entry. Load the resource and create a new entry.
|
|
hr = D3DXCreateVolumeTextureFromFileEx( pDevice, pSrcFile, Width, Height, Depth, MipLevels, Usage, Format,
|
|
Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppTexture );
|
|
if( FAILED( hr ) )
|
|
return hr;
|
|
|
|
DXUTCache_Texture NewEntry;
|
|
NewEntry.Location = DXUTCACHE_LOCATION_FILE;
|
|
StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcFile );
|
|
NewEntry.Width = Width;
|
|
NewEntry.Height = Height;
|
|
NewEntry.Depth = Depth;
|
|
NewEntry.MipLevels = MipLevels;
|
|
NewEntry.Usage = Usage;
|
|
NewEntry.Format = Format;
|
|
NewEntry.Pool = Pool;
|
|
NewEntry.Type = D3DRTYPE_VOLUMETEXTURE;
|
|
(*ppTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
|
|
|
|
m_TextureCache.Add( NewEntry );
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTResourceCache::CreateVolumeTextureFromResource( LPDIRECT3DDEVICE9 pDevice, HMODULE hSrcModule, LPCTSTR pSrcResource, LPDIRECT3DVOLUMETEXTURE9 *ppVolumeTexture )
|
|
{
|
|
return CreateVolumeTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, D3DX_DEFAULT, D3DX_DEFAULT,
|
|
D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
|
|
D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, ppVolumeTexture );
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT 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 )
|
|
{
|
|
// Search the cache for a matching entry.
|
|
for( int i = 0; i < m_TextureCache.GetSize(); ++i )
|
|
{
|
|
DXUTCache_Texture &Entry = m_TextureCache[i];
|
|
if( Entry.Location == DXUTCACHE_LOCATION_RESOURCE &&
|
|
Entry.hSrcModule == hSrcModule &&
|
|
!lstrcmpA( Entry.wszSource, pSrcResource ) &&
|
|
Entry.Width == Width &&
|
|
Entry.Height == Height &&
|
|
Entry.Depth == Depth &&
|
|
Entry.MipLevels == MipLevels &&
|
|
Entry.Usage == Usage &&
|
|
Entry.Format == Format &&
|
|
Entry.Pool == Pool &&
|
|
Entry.Type == D3DRTYPE_VOLUMETEXTURE )
|
|
{
|
|
// A match is found. Obtain the IDirect3DVolumeTexture9 interface and return that.
|
|
return Entry.pTexture->QueryInterface( IID_IDirect3DVolumeTexture9, (LPVOID*)ppVolumeTexture );
|
|
}
|
|
}
|
|
|
|
HRESULT hr;
|
|
|
|
// No matching entry. Load the resource and create a new entry.
|
|
hr = D3DXCreateVolumeTextureFromResourceEx( pDevice, hSrcModule, pSrcResource, Width, Height, Depth, MipLevels, Usage,
|
|
Format, Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppVolumeTexture );
|
|
if( FAILED( hr ) )
|
|
return hr;
|
|
|
|
DXUTCache_Texture NewEntry;
|
|
NewEntry.Location = DXUTCACHE_LOCATION_RESOURCE;
|
|
NewEntry.hSrcModule = hSrcModule;
|
|
StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcResource );
|
|
NewEntry.Width = Width;
|
|
NewEntry.Height = Height;
|
|
NewEntry.Depth = Depth;
|
|
NewEntry.MipLevels = MipLevels;
|
|
NewEntry.Usage = Usage;
|
|
NewEntry.Format = Format;
|
|
NewEntry.Pool = Pool;
|
|
NewEntry.Type = D3DRTYPE_VOLUMETEXTURE;
|
|
(*ppVolumeTexture)->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&NewEntry.pTexture );
|
|
|
|
m_TextureCache.Add( NewEntry );
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT 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 )
|
|
{
|
|
D3DXFONT_DESC Desc;
|
|
|
|
Desc.Height = Height;
|
|
Desc.Width = Width;
|
|
Desc.Weight = Weight;
|
|
Desc.MipLevels = MipLevels;
|
|
Desc.Italic = Italic;
|
|
Desc.CharSet = (BYTE)CharSet;
|
|
Desc.OutputPrecision = (BYTE)OutputPrecision;
|
|
Desc.Quality = (BYTE)Quality;
|
|
Desc.PitchAndFamily = (BYTE)PitchAndFamily;
|
|
StringCchCopy( Desc.FaceName, LF_FACESIZE, pFacename );
|
|
|
|
return CreateFontIndirect( pDevice, &Desc, ppFont );
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTResourceCache::CreateFontIndirect( LPDIRECT3DDEVICE9 pDevice, CONST D3DXFONT_DESC *pDesc, LPD3DXFONT *ppFont )
|
|
{
|
|
// Search the cache for a matching entry.
|
|
for( int i = 0; i < m_FontCache.GetSize(); ++i )
|
|
{
|
|
DXUTCache_Font &Entry = m_FontCache[i];
|
|
|
|
if( Entry.Width == pDesc->Width &&
|
|
Entry.Height == pDesc->Height &&
|
|
Entry.Weight == pDesc->Weight &&
|
|
Entry.MipLevels == pDesc->MipLevels &&
|
|
Entry.Italic == pDesc->Italic &&
|
|
Entry.CharSet == pDesc->CharSet &&
|
|
Entry.OutputPrecision == pDesc->OutputPrecision &&
|
|
Entry.Quality == pDesc->Quality &&
|
|
Entry.PitchAndFamily == pDesc->PitchAndFamily &&
|
|
CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE,
|
|
Entry.FaceName, -1,
|
|
pDesc->FaceName, -1 ) == CSTR_EQUAL )
|
|
{
|
|
// A match is found. Increment the reference and return the ID3DXFont object.
|
|
Entry.pFont->AddRef();
|
|
*ppFont = Entry.pFont;
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
HRESULT hr;
|
|
|
|
// No matching entry. Load the resource and create a new entry.
|
|
hr = D3DXCreateFontIndirect( pDevice, pDesc, ppFont );
|
|
if( FAILED( hr ) )
|
|
return hr;
|
|
|
|
DXUTCache_Font NewEntry;
|
|
(D3DXFONT_DESC &)NewEntry = *pDesc;
|
|
NewEntry.pFont = *ppFont;
|
|
NewEntry.pFont->AddRef();
|
|
|
|
m_FontCache.Add( NewEntry );
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTResourceCache::CreateEffectFromFile( LPDIRECT3DDEVICE9 pDevice, LPCTSTR pSrcFile, const D3DXMACRO *pDefines, LPD3DXINCLUDE pInclude, DWORD Flags, LPD3DXEFFECTPOOL pPool, LPD3DXEFFECT *ppEffect, LPD3DXBUFFER *ppCompilationErrors )
|
|
{
|
|
// Search the cache for a matching entry.
|
|
for( int i = 0; i < m_EffectCache.GetSize(); ++i )
|
|
{
|
|
DXUTCache_Effect &Entry = m_EffectCache[i];
|
|
|
|
if( Entry.Location == DXUTCACHE_LOCATION_FILE &&
|
|
!lstrcmpA( Entry.wszSource, pSrcFile ) &&
|
|
Entry.dwFlags == Flags )
|
|
{
|
|
// A match is found. Increment the ref coutn and return the ID3DXEffect object.
|
|
*ppEffect = Entry.pEffect;
|
|
(*ppEffect)->AddRef();
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
HRESULT hr;
|
|
|
|
// No matching entry. Load the resource and create a new entry.
|
|
hr = D3DXCreateEffectFromFile( pDevice, pSrcFile, pDefines, pInclude, Flags, pPool, ppEffect, ppCompilationErrors );
|
|
if( FAILED( hr ) )
|
|
return hr;
|
|
|
|
DXUTCache_Effect NewEntry;
|
|
NewEntry.Location = DXUTCACHE_LOCATION_FILE;
|
|
StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcFile );
|
|
NewEntry.dwFlags = Flags;
|
|
NewEntry.pEffect = *ppEffect;
|
|
NewEntry.pEffect->AddRef();
|
|
|
|
m_EffectCache.Add( NewEntry );
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTResourceCache::CreateEffectFromResource( LPDIRECT3DDEVICE9 pDevice, HMODULE hSrcModule, LPCTSTR pSrcResource, const D3DXMACRO *pDefines, LPD3DXINCLUDE pInclude, DWORD Flags, LPD3DXEFFECTPOOL pPool, LPD3DXEFFECT *ppEffect, LPD3DXBUFFER *ppCompilationErrors )
|
|
{
|
|
// Search the cache for a matching entry.
|
|
for( int i = 0; i < m_EffectCache.GetSize(); ++i )
|
|
{
|
|
DXUTCache_Effect &Entry = m_EffectCache[i];
|
|
|
|
if( Entry.Location == DXUTCACHE_LOCATION_RESOURCE &&
|
|
Entry.hSrcModule == hSrcModule &&
|
|
!lstrcmpA( Entry.wszSource, pSrcResource ) &&
|
|
Entry.dwFlags == Flags )
|
|
{
|
|
// A match is found. Increment the ref coutn and return the ID3DXEffect object.
|
|
*ppEffect = Entry.pEffect;
|
|
(*ppEffect)->AddRef();
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
HRESULT hr;
|
|
|
|
// No matching entry. Load the resource and create a new entry.
|
|
hr = D3DXCreateEffectFromResource( pDevice, hSrcModule, pSrcResource, pDefines, pInclude, Flags,
|
|
pPool, ppEffect, ppCompilationErrors );
|
|
if( FAILED( hr ) )
|
|
return hr;
|
|
|
|
DXUTCache_Effect NewEntry;
|
|
NewEntry.Location = DXUTCACHE_LOCATION_RESOURCE;
|
|
NewEntry.hSrcModule = hSrcModule;
|
|
StringCchCopy( NewEntry.wszSource, MAX_PATH, pSrcResource );
|
|
NewEntry.dwFlags = Flags;
|
|
NewEntry.pEffect = *ppEffect;
|
|
NewEntry.pEffect->AddRef();
|
|
|
|
m_EffectCache.Add( NewEntry );
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Device event callbacks
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTResourceCache::OnCreateDevice( IDirect3DDevice9 *pd3dDevice )
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// MATCH
|
|
HRESULT CDXUTResourceCache::OnResetDevice( IDirect3DDevice9 *pd3dDevice )
|
|
{
|
|
// Call OnResetDevice on all effect and font objects
|
|
for( int i = 0; i < m_EffectCache.GetSize(); ++i )
|
|
m_EffectCache[i].pEffect->OnResetDevice();
|
|
for( int i = 0; i < m_FontCache.GetSize(); ++i )
|
|
m_FontCache[i].pFont->OnResetDevice();
|
|
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// MATCH
|
|
HRESULT CDXUTResourceCache::OnLostDevice()
|
|
{
|
|
// Call OnLostDevice on all effect and font objects
|
|
for( int i = 0; i < m_EffectCache.GetSize(); ++i )
|
|
m_EffectCache[i].pEffect->OnLostDevice();
|
|
for( int i = 0; i < m_FontCache.GetSize(); ++i )
|
|
m_FontCache[i].pFont->OnLostDevice();
|
|
|
|
// Release all the default pool textures
|
|
for( int i = m_TextureCache.GetSize() - 1; i >= 0; --i )
|
|
if( m_TextureCache[i].Pool == D3DPOOL_DEFAULT )
|
|
{
|
|
SAFE_RELEASE( m_TextureCache[i].pTexture );
|
|
m_TextureCache.Remove( i ); // Remove the entry
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// MATCH
|
|
HRESULT CDXUTResourceCache::OnDestroyDevice()
|
|
{
|
|
// Release all resources
|
|
for( int i = m_EffectCache.GetSize() - 1; i >= 0; --i )
|
|
{
|
|
SAFE_RELEASE( m_EffectCache[i].pEffect );
|
|
m_EffectCache.Remove( i );
|
|
}
|
|
for( int i = m_FontCache.GetSize() - 1; i >= 0; --i )
|
|
{
|
|
SAFE_RELEASE( m_FontCache[i].pFont );
|
|
m_FontCache.Remove( i );
|
|
}
|
|
for( int i = m_TextureCache.GetSize() - 1; i >= 0; --i )
|
|
{
|
|
SAFE_RELEASE( m_TextureCache[i].pTexture );
|
|
m_TextureCache.Remove( i );
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
CD3DArcBall::CD3DArcBall()
|
|
{
|
|
Reset();
|
|
m_vDownPt = D3DXVECTOR3(0,0,0);
|
|
m_vCurrentPt = D3DXVECTOR3(0,0,0);
|
|
m_Offset.x = m_Offset.y = 0;
|
|
|
|
RECT rc;
|
|
GetClientRect( GetForegroundWindow(), &rc );
|
|
SetWindow( rc.right, rc.bottom );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
void CD3DArcBall::Reset()
|
|
{
|
|
D3DXQuaternionIdentity( &m_qDown );
|
|
D3DXQuaternionIdentity( &m_qNow );
|
|
D3DXMatrixIdentity( &m_mRotation );
|
|
D3DXMatrixIdentity( &m_mTranslation );
|
|
D3DXMatrixIdentity( &m_mTranslationDelta );
|
|
m_bDrag = FALSE;
|
|
m_fRadiusTranslation = 1.0f;
|
|
m_fRadius = 1.0f;
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
D3DXVECTOR3 CD3DArcBall::ScreenToVector( float fScreenPtX, float fScreenPtY )
|
|
{
|
|
// Scale to screen
|
|
FLOAT x = -(fScreenPtX - m_Offset.x - m_nWidth/2) / (m_fRadius*m_nWidth/2);
|
|
FLOAT y = (fScreenPtY - m_Offset.y - m_nHeight/2) / (m_fRadius*m_nHeight/2);
|
|
|
|
FLOAT z = 0.0f;
|
|
FLOAT mag = x*x + y*y;
|
|
|
|
if( mag > 1.0f )
|
|
{
|
|
FLOAT scale = 1.0f/sqrtf(mag);
|
|
x *= scale;
|
|
y *= scale;
|
|
}
|
|
else
|
|
z = sqrtf( 1.0f - mag );
|
|
|
|
// Return vector
|
|
return D3DXVECTOR3( x, y, z );
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
D3DXQUATERNION CD3DArcBall::QuatFromBallPoints(const D3DXVECTOR3 &vFrom, const D3DXVECTOR3 &vTo)
|
|
{
|
|
D3DXVECTOR3 vPart;
|
|
float fDot = D3DXVec3Dot(&vFrom, &vTo);
|
|
D3DXVec3Cross(&vPart, &vFrom, &vTo);
|
|
|
|
return D3DXQUATERNION(vPart.x, vPart.y, vPart.z, fDot);
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
void CD3DArcBall::OnBegin( int nX, int nY )
|
|
{
|
|
// Only enter the drag state if the click falls
|
|
// inside the click rectangle.
|
|
if( nX >= m_Offset.x &&
|
|
nX < m_Offset.x + m_nWidth &&
|
|
nY >= m_Offset.y &&
|
|
nY < m_Offset.y + m_nHeight )
|
|
{
|
|
m_bDrag = true;
|
|
m_qDown = m_qNow;
|
|
m_vDownPt = ScreenToVector( (float)nX, (float)nY );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
void CD3DArcBall::OnMove( int nX, int nY )
|
|
{
|
|
if (m_bDrag)
|
|
{
|
|
m_vCurrentPt = ScreenToVector( (float)nX, (float)nY );
|
|
m_qNow = m_qDown * QuatFromBallPoints( m_vDownPt, m_vCurrentPt );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
void CD3DArcBall::OnEnd()
|
|
{
|
|
m_bDrag = false;
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Desc:
|
|
//--------------------------------------------------------------------------------------
|
|
LRESULT CD3DArcBall::HandleMessages( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
// Current mouse position
|
|
int iMouseX = (short)LOWORD(lParam);
|
|
int iMouseY = (short)HIWORD(lParam);
|
|
|
|
switch( uMsg )
|
|
{
|
|
case WM_LBUTTONDOWN:
|
|
case WM_LBUTTONDBLCLK:
|
|
SetCapture( hWnd );
|
|
OnBegin( iMouseX, iMouseY );
|
|
return TRUE;
|
|
|
|
case WM_LBUTTONUP:
|
|
ReleaseCapture();
|
|
OnEnd();
|
|
return TRUE;
|
|
|
|
case WM_RBUTTONDOWN:
|
|
case WM_RBUTTONDBLCLK:
|
|
case WM_MBUTTONDOWN:
|
|
case WM_MBUTTONDBLCLK:
|
|
SetCapture( hWnd );
|
|
// Store off the position of the cursor when the button is pressed
|
|
m_ptLastMouse.x = iMouseX;
|
|
m_ptLastMouse.y = iMouseY;
|
|
return TRUE;
|
|
|
|
case WM_RBUTTONUP:
|
|
case WM_MBUTTONUP:
|
|
ReleaseCapture();
|
|
return TRUE;
|
|
|
|
case WM_MOUSEMOVE:
|
|
if( MK_LBUTTON&wParam )
|
|
{
|
|
OnMove( iMouseX, iMouseY );
|
|
}
|
|
else if( (MK_RBUTTON&wParam) || (MK_MBUTTON&wParam) )
|
|
{
|
|
// Normalize based on size of window and bounding sphere radius
|
|
FLOAT fDeltaX = ( m_ptLastMouse.x-iMouseX ) * m_fRadiusTranslation / m_nWidth;
|
|
FLOAT fDeltaY = ( m_ptLastMouse.y-iMouseY ) * m_fRadiusTranslation / m_nHeight;
|
|
|
|
if( wParam & MK_RBUTTON )
|
|
{
|
|
D3DXMatrixTranslation( &m_mTranslationDelta, -2*fDeltaX, 2*fDeltaY, 0.0f );
|
|
D3DXMatrixMultiply( &m_mTranslation, &m_mTranslation, &m_mTranslationDelta );
|
|
}
|
|
else // wParam & MK_MBUTTON
|
|
{
|
|
D3DXMatrixTranslation( &m_mTranslationDelta, 0.0f, 0.0f, 5*fDeltaY );
|
|
D3DXMatrixMultiply( &m_mTranslation, &m_mTranslation, &m_mTranslationDelta );
|
|
}
|
|
|
|
// Store mouse coordinate
|
|
m_ptLastMouse.x = iMouseX;
|
|
m_ptLastMouse.y = iMouseY;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Constructor
|
|
//--------------------------------------------------------------------------------------
|
|
CBaseCamera::CBaseCamera()
|
|
{
|
|
ZeroMemory( m_aKeys, sizeof(BYTE)*CAM_MAX_KEYS );
|
|
|
|
// Set attributes for the view matrix
|
|
D3DXVECTOR3 vEyePt = D3DXVECTOR3(0.0f,0.0f,0.0f);
|
|
D3DXVECTOR3 vLookatPt = D3DXVECTOR3(0.0f,0.0f,1.0f);
|
|
|
|
// Setup the view matrix
|
|
SetViewParams( &vEyePt, &vLookatPt );
|
|
|
|
// Setup the projection matrix
|
|
SetProjParams( D3DX_PI/4, 1.0f, 1.0f, 1000.0f );
|
|
|
|
GetCursorPos( &m_ptLastMousePosition );
|
|
m_bMouseLButtonDown = false;
|
|
m_bMouseMButtonDown = false;
|
|
m_bMouseRButtonDown = false;
|
|
m_nCurrentButtonMask = 0;
|
|
m_nMouseWheelDelta = 0;
|
|
|
|
m_fCameraYawAngle = 0.0f;
|
|
m_fCameraPitchAngle = 0.0f;
|
|
|
|
SetRect( &m_rcDrag, LONG_MIN, LONG_MIN, LONG_MAX, LONG_MAX );
|
|
m_vVelocity = D3DXVECTOR3(0,0,0);
|
|
m_bMovementDrag = false;
|
|
m_vVelocityDrag = D3DXVECTOR3(0,0,0);
|
|
m_fDragTimer = 0.0f;
|
|
m_fTotalDragTimeToZero = 0.25;
|
|
m_vRotVelocity = D3DXVECTOR2(0,0);
|
|
|
|
m_fRotationScaler = 0.01f;
|
|
m_fMoveScaler = 5.0f;
|
|
|
|
m_bInvertPitch = false;
|
|
m_bEnableYAxisMovement = true;
|
|
m_bEnablePositionMovement = true;
|
|
|
|
m_vMouseDelta = D3DXVECTOR2(0,0);
|
|
m_fFramesToSmoothMouseData = 2.0f;
|
|
|
|
m_bClipToBoundary = false;
|
|
m_vMinBoundary = D3DXVECTOR3(-1,-1,-1);
|
|
m_vMaxBoundary = D3DXVECTOR3(1,1,1);
|
|
|
|
m_bResetCursorAfterMove = false;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Client can call this to change the position and direction of camera
|
|
//--------------------------------------------------------------------------------------
|
|
VOID CBaseCamera::SetViewParams( D3DXVECTOR3* pvEyePt, D3DXVECTOR3* pvLookatPt )
|
|
{
|
|
if( NULL == pvEyePt || NULL == pvLookatPt )
|
|
return;
|
|
|
|
m_vDefaultEye = m_vEye = *pvEyePt;
|
|
m_vDefaultLookAt = m_vLookAt = *pvLookatPt;
|
|
|
|
// Calc the view matrix
|
|
D3DXVECTOR3 vUp(0,1,0);
|
|
D3DXMatrixLookAtLH( &m_mView, pvEyePt, pvLookatPt, &vUp );
|
|
|
|
D3DXMATRIX mInvView;
|
|
D3DXMatrixInverse( &mInvView, NULL, &m_mView );
|
|
|
|
// The axis basis vectors and camera position are stored inside the
|
|
// position matrix in the 4 rows of the camera's world matrix.
|
|
// To figure out the yaw/pitch of the camera, we just need the Z basis vector
|
|
D3DXVECTOR3* pZBasis = (D3DXVECTOR3*) &mInvView._31;
|
|
|
|
m_fCameraYawAngle = atan2f( pZBasis->x, pZBasis->z );
|
|
float fLen = sqrtf(pZBasis->z*pZBasis->z + pZBasis->x*pZBasis->x);
|
|
m_fCameraPitchAngle = -atan2f( pZBasis->y, fLen );
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Calculates the projection matrix based on input params
|
|
//--------------------------------------------------------------------------------------
|
|
VOID CBaseCamera::SetProjParams( FLOAT fFOV, FLOAT fAspect, FLOAT fNearPlane,
|
|
FLOAT fFarPlane )
|
|
{
|
|
// Set attributes for the projection matrix
|
|
m_fFOV = fFOV;
|
|
m_fAspect = fAspect;
|
|
m_fNearPlane = fNearPlane;
|
|
m_fFarPlane = fFarPlane;
|
|
|
|
D3DXMatrixPerspectiveFovLH( &m_mProj, fFOV, fAspect, fNearPlane, fFarPlane );
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Call this from your message proc so this class can handle window messages
|
|
//--------------------------------------------------------------------------------------
|
|
LRESULT CBaseCamera::HandleMessages( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
UNREFERENCED_PARAMETER( hWnd );
|
|
UNREFERENCED_PARAMETER( lParam );
|
|
|
|
switch( uMsg )
|
|
{
|
|
case WM_KEYDOWN:
|
|
{
|
|
// Map this key to a D3DUtil_CameraKeys enum and update the
|
|
// state of m_aKeys[] by adding the KEY_WAS_DOWN_MASK|KEY_IS_DOWN_MASK mask
|
|
// only if the key is not down
|
|
D3DUtil_CameraKeys mappedKey = MapKey( (UINT)wParam );
|
|
if( mappedKey != CAM_UNKNOWN )
|
|
{
|
|
if( FALSE == IsKeyDown(m_aKeys[mappedKey]) )
|
|
m_aKeys[ mappedKey ] = KEY_WAS_DOWN_MASK | KEY_IS_DOWN_MASK;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_KEYUP:
|
|
{
|
|
// Map this key to a D3DUtil_CameraKeys enum and update the
|
|
// state of m_aKeys[] by removing the KEY_IS_DOWN_MASK mask.
|
|
D3DUtil_CameraKeys mappedKey = MapKey( (UINT)wParam );
|
|
if( mappedKey != CAM_UNKNOWN && (DWORD)mappedKey < 8 )
|
|
m_aKeys[ mappedKey ] &= ~KEY_IS_DOWN_MASK;
|
|
break;
|
|
}
|
|
|
|
case WM_RBUTTONDOWN:
|
|
case WM_MBUTTONDOWN:
|
|
case WM_LBUTTONDOWN:
|
|
case WM_RBUTTONDBLCLK:
|
|
case WM_MBUTTONDBLCLK:
|
|
case WM_LBUTTONDBLCLK:
|
|
{
|
|
// Compute the drag rectangle in screen coord.
|
|
POINT ptCursor = { (short)LOWORD(lParam), (short)HIWORD(lParam) };
|
|
|
|
// Update member var state
|
|
if( ( uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK ) && PtInRect( &m_rcDrag, ptCursor ) )
|
|
{ m_bMouseLButtonDown = true; m_nCurrentButtonMask |= MOUSE_LEFT_BUTTON; }
|
|
if( ( uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONDBLCLK ) && PtInRect( &m_rcDrag, ptCursor ) )
|
|
{ m_bMouseMButtonDown = true; m_nCurrentButtonMask |= MOUSE_MIDDLE_BUTTON; }
|
|
if( ( uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONDBLCLK ) && PtInRect( &m_rcDrag, ptCursor ) )
|
|
{ m_bMouseRButtonDown = true; m_nCurrentButtonMask |= MOUSE_RIGHT_BUTTON; }
|
|
|
|
// Capture the mouse, so if the mouse button is
|
|
// released outside the window, we'll get the WM_LBUTTONUP message
|
|
SetCapture(hWnd);
|
|
GetCursorPos( &m_ptLastMousePosition );
|
|
return TRUE;
|
|
}
|
|
|
|
case WM_RBUTTONUP:
|
|
case WM_MBUTTONUP:
|
|
case WM_LBUTTONUP:
|
|
{
|
|
// Update member var state
|
|
if( uMsg == WM_LBUTTONUP ) { m_bMouseLButtonDown = false; m_nCurrentButtonMask &= ~MOUSE_LEFT_BUTTON; }
|
|
if( uMsg == WM_MBUTTONUP ) { m_bMouseMButtonDown = false; m_nCurrentButtonMask &= ~MOUSE_MIDDLE_BUTTON; }
|
|
if( uMsg == WM_RBUTTONUP ) { m_bMouseRButtonDown = false; m_nCurrentButtonMask &= ~MOUSE_RIGHT_BUTTON; }
|
|
|
|
// Release the capture if no mouse buttons down
|
|
if( !m_bMouseLButtonDown &&
|
|
!m_bMouseRButtonDown &&
|
|
!m_bMouseMButtonDown )
|
|
{
|
|
ReleaseCapture();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_MOUSEWHEEL:
|
|
// Update member var state
|
|
m_nMouseWheelDelta = (short)HIWORD(wParam) / 120;
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Figure out the mouse delta based on mouse movement
|
|
//--------------------------------------------------------------------------------------
|
|
void CBaseCamera::UpdateMouseDelta( float fElapsedTime )
|
|
{
|
|
UNREFERENCED_PARAMETER( fElapsedTime );
|
|
|
|
POINT ptCurMouseDelta;
|
|
POINT ptCurMousePos;
|
|
|
|
// Get current position of mouse
|
|
GetCursorPos( &ptCurMousePos );
|
|
|
|
// Calc how far it's moved since last frame
|
|
ptCurMouseDelta.x = ptCurMousePos.x - m_ptLastMousePosition.x;
|
|
ptCurMouseDelta.y = ptCurMousePos.y - m_ptLastMousePosition.y;
|
|
|
|
// Record current position for next time
|
|
m_ptLastMousePosition = ptCurMousePos;
|
|
|
|
if( m_bResetCursorAfterMove )
|
|
{
|
|
// Set position of camera to center of desktop,
|
|
// so it always has room to move. This is very useful
|
|
// if the cursor is hidden. If this isn't done and cursor is hidden,
|
|
// then invisible cursor will hit the edge of the screen
|
|
// and the user can't tell what happened
|
|
POINT ptCenter;
|
|
RECT rcDesktop;
|
|
GetWindowRect( GetDesktopWindow(), &rcDesktop );
|
|
ptCenter.x = (rcDesktop.right - rcDesktop.left) / 2;
|
|
ptCenter.y = (rcDesktop.bottom - rcDesktop.top) / 2;
|
|
SetCursorPos( ptCenter.x, ptCenter.y );
|
|
m_ptLastMousePosition = ptCenter;
|
|
}
|
|
|
|
// Smooth the relative mouse data over a few frames so it isn't
|
|
// jerky when moving slowly at low frame rates.
|
|
float fPercentOfNew = 1.0f / m_fFramesToSmoothMouseData;
|
|
float fPercentOfOld = 1.0f - fPercentOfNew;
|
|
m_vMouseDelta.x = m_vMouseDelta.x*fPercentOfOld + ptCurMouseDelta.x*fPercentOfNew;
|
|
m_vMouseDelta.y = m_vMouseDelta.y*fPercentOfOld + ptCurMouseDelta.y*fPercentOfNew;
|
|
|
|
m_vRotVelocity = m_vMouseDelta * m_fRotationScaler;
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Figure out the velocity based on keyboard input & drag if any
|
|
//--------------------------------------------------------------------------------------
|
|
void CBaseCamera::UpdateVelocity( float fElapsedTime )
|
|
{
|
|
D3DXMATRIX mRotDelta;
|
|
D3DXVECTOR3 vAccel = D3DXVECTOR3(0,0,0);
|
|
|
|
if( m_bEnablePositionMovement )
|
|
{
|
|
// Update acceleration vector based on keyboard state
|
|
if( IsKeyDown(m_aKeys[CAM_MOVE_FORWARD]) )
|
|
vAccel.z += 1.0f;
|
|
if( IsKeyDown(m_aKeys[CAM_MOVE_BACKWARD]) )
|
|
vAccel.z -= 1.0f;
|
|
if( m_bEnableYAxisMovement )
|
|
{
|
|
if( IsKeyDown(m_aKeys[CAM_MOVE_UP]) )
|
|
vAccel.y += 1.0f;
|
|
if( IsKeyDown(m_aKeys[CAM_MOVE_DOWN]) )
|
|
vAccel.y -= 1.0f;
|
|
}
|
|
if( IsKeyDown(m_aKeys[CAM_STRAFE_RIGHT]) )
|
|
vAccel.x += 1.0f;
|
|
if( IsKeyDown(m_aKeys[CAM_STRAFE_LEFT]) )
|
|
vAccel.x -= 1.0f;
|
|
}
|
|
|
|
// Normalize vector so if moving 2 dirs (left & forward),
|
|
// the camera doesn't move faster than if moving in 1 dir
|
|
D3DXVec3Normalize( &vAccel, &vAccel );
|
|
|
|
// Scale the acceleration vector
|
|
vAccel *= m_fMoveScaler;
|
|
|
|
if( m_bMovementDrag )
|
|
{
|
|
// Is there any acceleration this frame?
|
|
if( D3DXVec3LengthSq( &vAccel ) > 0 )
|
|
{
|
|
// If so, then this means the user has pressed a movement key\
|
|
// so change the velocity immediately to acceleration
|
|
// upon keyboard input. This isn't normal physics
|
|
// but it will give a quick response to keyboard input
|
|
m_vVelocity = vAccel;
|
|
m_fDragTimer = m_fTotalDragTimeToZero;
|
|
m_vVelocityDrag = vAccel / m_fDragTimer;
|
|
}
|
|
else
|
|
{
|
|
// If no key being pressed, then slowly decrease velocity to 0
|
|
if( m_fDragTimer > 0 )
|
|
{
|
|
// Drag until timer is <= 0
|
|
m_vVelocity -= m_vVelocityDrag * fElapsedTime;
|
|
m_fDragTimer -= fElapsedTime;
|
|
}
|
|
else
|
|
{
|
|
// Zero velocity
|
|
m_vVelocity = D3DXVECTOR3(0,0,0);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No drag, so immediately change the velocity
|
|
m_vVelocity = vAccel;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Clamps pV to lie inside m_vMinBoundary & m_vMaxBoundary
|
|
//--------------------------------------------------------------------------------------
|
|
void CBaseCamera::ConstrainToBoundary( D3DXVECTOR3* pV )
|
|
{
|
|
// Constrain vector to a bounding box
|
|
pV->x = __max(pV->x, m_vMinBoundary.x);
|
|
pV->y = __max(pV->y, m_vMinBoundary.y);
|
|
pV->z = __max(pV->z, m_vMinBoundary.z);
|
|
|
|
pV->x = __min(pV->x, m_vMaxBoundary.x);
|
|
pV->y = __min(pV->y, m_vMaxBoundary.y);
|
|
pV->z = __min(pV->z, m_vMaxBoundary.z);
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Maps a windows virtual key to an enum
|
|
//--------------------------------------------------------------------------------------
|
|
D3DUtil_CameraKeys CBaseCamera::MapKey( UINT nKey )
|
|
{
|
|
// This could be upgraded to a method that's user-definable but for
|
|
// simplicity, we'll use a hardcoded mapping.
|
|
switch( nKey )
|
|
{
|
|
case VK_CONTROL: return CAM_CONTROLDOWN;
|
|
case VK_LEFT: return CAM_STRAFE_LEFT;
|
|
case VK_RIGHT: return CAM_STRAFE_RIGHT;
|
|
case VK_UP: return CAM_MOVE_FORWARD;
|
|
case VK_DOWN: return CAM_MOVE_BACKWARD;
|
|
case VK_PRIOR: return CAM_MOVE_UP; // pgup
|
|
case VK_NEXT: return CAM_MOVE_DOWN; // pgdn
|
|
|
|
case 'A': return CAM_STRAFE_LEFT;
|
|
case 'D': return CAM_STRAFE_RIGHT;
|
|
case 'W': return CAM_MOVE_FORWARD;
|
|
case 'S': return CAM_MOVE_BACKWARD;
|
|
case 'Q': return CAM_MOVE_DOWN;
|
|
case 'E': return CAM_MOVE_UP;
|
|
|
|
case VK_NUMPAD4: return CAM_STRAFE_LEFT;
|
|
case VK_NUMPAD6: return CAM_STRAFE_RIGHT;
|
|
case VK_NUMPAD8: return CAM_MOVE_FORWARD;
|
|
case VK_NUMPAD2: return CAM_MOVE_BACKWARD;
|
|
case VK_NUMPAD9: return CAM_MOVE_UP;
|
|
case VK_NUMPAD3: return CAM_MOVE_DOWN;
|
|
|
|
case VK_HOME: return CAM_RESET;
|
|
}
|
|
|
|
return CAM_UNKNOWN;
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Reset the camera's position back to the default
|
|
//--------------------------------------------------------------------------------------
|
|
VOID CBaseCamera::Reset()
|
|
{
|
|
SetViewParams( &m_vDefaultEye, &m_vDefaultLookAt );
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Constructor
|
|
//--------------------------------------------------------------------------------------
|
|
CFirstPersonCamera::CFirstPersonCamera() :
|
|
m_nActiveButtonMask( 0x07 )
|
|
{
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Update the view matrix based on user input & elapsed time
|
|
//--------------------------------------------------------------------------------------
|
|
VOID CFirstPersonCamera::FrameMove( FLOAT fElapsedTime )
|
|
{
|
|
if( DXUTGetGlobalTimer()->IsStopped() )
|
|
fElapsedTime = 1.0f / DXUTGetFPS();
|
|
|
|
if( IsKeyDown(m_aKeys[CAM_RESET]) )
|
|
Reset();
|
|
|
|
// Get the mouse movement (if any) if the mouse button are down
|
|
if( m_nActiveButtonMask & m_nCurrentButtonMask )
|
|
UpdateMouseDelta( fElapsedTime );
|
|
|
|
// Get amount of velocity based on the keyboard input and drag (if any)
|
|
UpdateVelocity( fElapsedTime );
|
|
|
|
// Simple euler method to calculate position delta
|
|
D3DXVECTOR3 vPosDelta = m_vVelocity * fElapsedTime;
|
|
|
|
// If rotating the camera
|
|
if( m_nActiveButtonMask & m_nCurrentButtonMask )
|
|
{
|
|
// Update the pitch & yaw angle based on mouse movement
|
|
float fYawDelta = m_vRotVelocity.x;
|
|
float fPitchDelta = m_vRotVelocity.y;
|
|
|
|
// Invert pitch if requested
|
|
if( m_bInvertPitch )
|
|
fPitchDelta = -fPitchDelta;
|
|
|
|
m_fCameraPitchAngle += fPitchDelta;
|
|
m_fCameraYawAngle += fYawDelta;
|
|
|
|
// Limit pitch to straight up or straight down
|
|
m_fCameraPitchAngle = __max( -D3DX_PI/2.0f, m_fCameraPitchAngle );
|
|
m_fCameraPitchAngle = __min( +D3DX_PI/2.0f, m_fCameraPitchAngle );
|
|
}
|
|
|
|
// Make a rotation matrix based on the camera's yaw & pitch
|
|
D3DXMATRIX mCameraRot;
|
|
D3DXMatrixRotationYawPitchRoll( &mCameraRot, m_fCameraYawAngle, m_fCameraPitchAngle, 0 );
|
|
|
|
// Transform vectors based on camera's rotation matrix
|
|
D3DXVECTOR3 vWorldUp, vWorldAhead;
|
|
D3DXVECTOR3 vLocalUp = D3DXVECTOR3(0,1,0);
|
|
D3DXVECTOR3 vLocalAhead = D3DXVECTOR3(0,0,1);
|
|
D3DXVec3TransformCoord( &vWorldUp, &vLocalUp, &mCameraRot );
|
|
D3DXVec3TransformCoord( &vWorldAhead, &vLocalAhead, &mCameraRot );
|
|
|
|
// Transform the position delta by the camera's rotation
|
|
D3DXVECTOR3 vPosDeltaWorld;
|
|
if( !m_bEnableYAxisMovement )
|
|
{
|
|
// If restricting Y movement, do not include pitch
|
|
// when transforming position delta vector.
|
|
D3DXMatrixRotationYawPitchRoll( &mCameraRot, m_fCameraYawAngle, 0.0f, 0.0f );
|
|
}
|
|
D3DXVec3TransformCoord( &vPosDeltaWorld, &vPosDelta, &mCameraRot );
|
|
|
|
// Move the eye position
|
|
m_vEye += vPosDeltaWorld;
|
|
if( m_bClipToBoundary )
|
|
ConstrainToBoundary( &m_vEye );
|
|
|
|
// Update the lookAt position based on the eye position
|
|
m_vLookAt = m_vEye + vWorldAhead;
|
|
|
|
// Update the view matrix
|
|
D3DXMatrixLookAtLH( &m_mView, &m_vEye, &m_vLookAt, &vWorldUp );
|
|
|
|
D3DXMatrixInverse( &m_mCameraWorld, NULL, &m_mView );
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Enable or disable each of the mouse buttons for rotation drag.
|
|
//--------------------------------------------------------------------------------------
|
|
void CFirstPersonCamera::SetRotateButtons( bool bLeft, bool bMiddle, bool bRight )
|
|
{
|
|
m_nActiveButtonMask = ( bLeft ? MOUSE_LEFT_BUTTON : 0 ) |
|
|
( bMiddle ? MOUSE_MIDDLE_BUTTON : 0 ) |
|
|
( bRight ? MOUSE_RIGHT_BUTTON : 0 );
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Constructor
|
|
//--------------------------------------------------------------------------------------
|
|
CModelViewerCamera::CModelViewerCamera()
|
|
{
|
|
D3DXMatrixIdentity( &m_mWorld );
|
|
D3DXMatrixIdentity( &m_mModelRot );
|
|
D3DXMatrixIdentity( &m_mModelLastRot );
|
|
D3DXMatrixIdentity( &m_mCameraRotLast );
|
|
m_vModelCenter = D3DXVECTOR3(0,0,0);
|
|
m_fRadius = 5.0f;
|
|
m_fDefaultRadius = 5.0f;
|
|
m_fMinRadius = 1.0f;
|
|
m_fMaxRadius = FLT_MAX;
|
|
m_bLimitPitch = false;
|
|
m_bEnablePositionMovement = false;
|
|
m_bAttachCameraToModel = false;
|
|
|
|
m_nRotateModelButtonMask = MOUSE_LEFT_BUTTON;
|
|
m_nZoomButtonMask = MOUSE_WHEEL;
|
|
m_nRotateCameraButtonMask = MOUSE_RIGHT_BUTTON;
|
|
m_bDragSinceLastUpdate = true;
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Update the view matrix & the model's world matrix based
|
|
// on user input & elapsed time
|
|
//--------------------------------------------------------------------------------------
|
|
VOID CModelViewerCamera::FrameMove( FLOAT fElapsedTime )
|
|
{
|
|
if( IsKeyDown(m_aKeys[CAM_RESET]) )
|
|
Reset();
|
|
|
|
// If no dragged has happend since last time FrameMove is called,
|
|
// no need to handle again.
|
|
if( !m_bDragSinceLastUpdate )
|
|
return;
|
|
m_bDragSinceLastUpdate = false;
|
|
|
|
// If no mouse button is held down,
|
|
// Get the mouse movement (if any) if the mouse button are down
|
|
if( m_nCurrentButtonMask != 0 )
|
|
UpdateMouseDelta( fElapsedTime );
|
|
|
|
// Get amount of velocity based on the keyboard input and drag (if any)
|
|
UpdateVelocity( fElapsedTime );
|
|
|
|
// Simple euler method to calculate position delta
|
|
D3DXVECTOR3 vPosDelta = m_vVelocity * fElapsedTime;
|
|
|
|
// Change the radius from the camera to the model based on wheel scrolling
|
|
if( m_nMouseWheelDelta && m_nZoomButtonMask == MOUSE_WHEEL )
|
|
m_fRadius -= m_nMouseWheelDelta * m_fRadius * 0.1f;
|
|
m_fRadius = __min( m_fMaxRadius, m_fRadius );
|
|
m_fRadius = __max( m_fMinRadius, m_fRadius );
|
|
m_nMouseWheelDelta = 0;
|
|
|
|
// Get the inverse of the arcball's rotation matrix
|
|
D3DXMATRIX mCameraRot;
|
|
D3DXMatrixInverse( &mCameraRot, NULL, m_ViewArcBall.GetRotationMatrix() );
|
|
|
|
// Transform vectors based on camera's rotation matrix
|
|
D3DXVECTOR3 vWorldUp, vWorldAhead;
|
|
D3DXVECTOR3 vLocalUp = D3DXVECTOR3(0,1,0);
|
|
D3DXVECTOR3 vLocalAhead = D3DXVECTOR3(0,0,1);
|
|
D3DXVec3TransformCoord( &vWorldUp, &vLocalUp, &mCameraRot );
|
|
D3DXVec3TransformCoord( &vWorldAhead, &vLocalAhead, &mCameraRot );
|
|
|
|
// Transform the position delta by the camera's rotation
|
|
D3DXVECTOR3 vPosDeltaWorld;
|
|
D3DXVec3TransformCoord( &vPosDeltaWorld, &vPosDelta, &mCameraRot );
|
|
|
|
// Move the lookAt position
|
|
m_vLookAt += vPosDeltaWorld;
|
|
if( m_bClipToBoundary )
|
|
ConstrainToBoundary( &m_vLookAt );
|
|
|
|
// Update the eye point based on a radius away from the lookAt position
|
|
m_vEye = m_vLookAt - vWorldAhead * m_fRadius;
|
|
|
|
// Update the view matrix
|
|
D3DXMatrixLookAtLH( &m_mView, &m_vEye, &m_vLookAt, &vWorldUp );
|
|
|
|
D3DXMATRIX mInvView;
|
|
D3DXMatrixInverse( &mInvView, NULL, &m_mView );
|
|
mInvView._41 = mInvView._42 = mInvView._43 = 0;
|
|
|
|
D3DXMATRIX mModelLastRotInv;
|
|
D3DXMatrixInverse(&mModelLastRotInv, NULL, &m_mModelLastRot);
|
|
|
|
// Accumulate the delta of the arcball's rotation in view space.
|
|
// Note that per-frame delta rotations could be problematic over long periods of time.
|
|
D3DXMATRIX mModelRot;
|
|
mModelRot = *m_WorldArcBall.GetRotationMatrix();
|
|
m_mModelRot *= m_mView * mModelLastRotInv * mModelRot * mInvView;
|
|
|
|
if( m_ViewArcBall.IsBeingDragged() && m_bAttachCameraToModel && !IsKeyDown(m_aKeys[CAM_CONTROLDOWN]) )
|
|
{
|
|
// Attach camera to model by inverse of the model rotation
|
|
D3DXMATRIX mCameraLastRotInv;
|
|
D3DXMatrixInverse(&mCameraLastRotInv, NULL, &m_mCameraRotLast);
|
|
D3DXMATRIX mCameraRotDelta = mCameraLastRotInv * mCameraRot; // local to world matrix
|
|
m_mModelRot *= mCameraRotDelta;
|
|
}
|
|
m_mCameraRotLast = mCameraRot;
|
|
|
|
m_mModelLastRot = mModelRot;
|
|
|
|
// Since we're accumulating delta rotations, we need to orthonormalize
|
|
// the matrix to prevent eventual matrix skew
|
|
D3DXVECTOR3* pXBasis = (D3DXVECTOR3*) &m_mModelRot._11;
|
|
D3DXVECTOR3* pYBasis = (D3DXVECTOR3*) &m_mModelRot._21;
|
|
D3DXVECTOR3* pZBasis = (D3DXVECTOR3*) &m_mModelRot._31;
|
|
D3DXVec3Normalize( pXBasis, pXBasis );
|
|
D3DXVec3Cross( pYBasis, pZBasis, pXBasis );
|
|
D3DXVec3Normalize( pYBasis, pYBasis );
|
|
D3DXVec3Cross( pZBasis, pXBasis, pYBasis );
|
|
|
|
// Translate the rotation matrix to the same position as the lookAt position
|
|
m_mModelRot._41 = m_vLookAt.x;
|
|
m_mModelRot._42 = m_vLookAt.y;
|
|
m_mModelRot._43 = m_vLookAt.z;
|
|
|
|
// Translate world matrix so its at the center of the model
|
|
D3DXMATRIX mTrans;
|
|
D3DXMatrixTranslation( &mTrans, -m_vModelCenter.x, -m_vModelCenter.y, -m_vModelCenter.z );
|
|
m_mWorld = mTrans * m_mModelRot;
|
|
}
|
|
|
|
|
|
void CModelViewerCamera::SetDragRect( RECT &rc )
|
|
{
|
|
CBaseCamera::SetDragRect( rc );
|
|
|
|
m_WorldArcBall.SetOffset( rc.left, rc.top );
|
|
m_ViewArcBall.SetOffset( rc.left, rc.top );
|
|
SetWindow( rc.right - rc.left, rc.bottom - rc.top );
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Reset the camera's position back to the default
|
|
//--------------------------------------------------------------------------------------
|
|
VOID CModelViewerCamera::Reset()
|
|
{
|
|
CBaseCamera::Reset();
|
|
|
|
D3DXMatrixIdentity( &m_mWorld );
|
|
D3DXMatrixIdentity( &m_mModelRot );
|
|
D3DXMatrixIdentity( &m_mModelLastRot );
|
|
D3DXMatrixIdentity( &m_mCameraRotLast );
|
|
|
|
m_fRadius = m_fDefaultRadius;
|
|
m_WorldArcBall.Reset();
|
|
m_ViewArcBall.Reset();
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Override for setting the view parameters
|
|
//--------------------------------------------------------------------------------------
|
|
void CModelViewerCamera::SetViewParams( D3DXVECTOR3* pvEyePt, D3DXVECTOR3* pvLookatPt )
|
|
{
|
|
CBaseCamera::SetViewParams( pvEyePt, pvLookatPt );
|
|
|
|
// Propogate changes to the member arcball
|
|
D3DXQUATERNION quat;
|
|
D3DXMATRIXA16 mRotation;
|
|
D3DXVECTOR3 vUp(0,1,0);
|
|
D3DXMatrixLookAtLH( &mRotation, pvEyePt, pvLookatPt, &vUp );
|
|
D3DXQuaternionRotationMatrix( &quat, &mRotation );
|
|
m_ViewArcBall.SetQuatNow( quat );
|
|
|
|
// Set the radius according to the distance
|
|
D3DXVECTOR3 vEyeToPoint;
|
|
D3DXVec3Subtract( &vEyeToPoint, pvLookatPt, pvEyePt );
|
|
SetRadius( D3DXVec3Length( &vEyeToPoint ) );
|
|
|
|
// View information changed. FrameMove should be called.
|
|
m_bDragSinceLastUpdate = true;
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Call this from your message proc so this class can handle window messages
|
|
//--------------------------------------------------------------------------------------
|
|
LRESULT CModelViewerCamera::HandleMessages( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
CBaseCamera::HandleMessages( hWnd, uMsg, wParam, lParam );
|
|
|
|
if( ( (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK ) && m_nRotateModelButtonMask & MOUSE_LEFT_BUTTON) ||
|
|
( (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONDBLCLK ) && m_nRotateModelButtonMask & MOUSE_MIDDLE_BUTTON) ||
|
|
( (uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONDBLCLK ) && m_nRotateModelButtonMask & MOUSE_RIGHT_BUTTON) )
|
|
{
|
|
int iMouseX = (short)LOWORD(lParam);
|
|
int iMouseY = (short)HIWORD(lParam);
|
|
m_WorldArcBall.OnBegin( iMouseX, iMouseY );
|
|
}
|
|
|
|
if( ( (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK ) && m_nRotateCameraButtonMask & MOUSE_LEFT_BUTTON) ||
|
|
( (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONDBLCLK ) && m_nRotateCameraButtonMask & MOUSE_MIDDLE_BUTTON) ||
|
|
( (uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONDBLCLK ) && m_nRotateCameraButtonMask & MOUSE_RIGHT_BUTTON) )
|
|
{
|
|
int iMouseX = (short)LOWORD(lParam);
|
|
int iMouseY = (short)HIWORD(lParam);
|
|
m_ViewArcBall.OnBegin( iMouseX, iMouseY );
|
|
}
|
|
|
|
if( uMsg == WM_MOUSEMOVE )
|
|
{
|
|
int iMouseX = (short)LOWORD(lParam);
|
|
int iMouseY = (short)HIWORD(lParam);
|
|
m_WorldArcBall.OnMove( iMouseX, iMouseY );
|
|
m_ViewArcBall.OnMove( iMouseX, iMouseY );
|
|
}
|
|
|
|
if( (uMsg == WM_LBUTTONUP && m_nRotateModelButtonMask & MOUSE_LEFT_BUTTON) ||
|
|
(uMsg == WM_MBUTTONUP && m_nRotateModelButtonMask & MOUSE_MIDDLE_BUTTON) ||
|
|
(uMsg == WM_RBUTTONUP && m_nRotateModelButtonMask & MOUSE_RIGHT_BUTTON) )
|
|
{
|
|
m_WorldArcBall.OnEnd();
|
|
}
|
|
|
|
if( (uMsg == WM_LBUTTONUP && m_nRotateCameraButtonMask & MOUSE_LEFT_BUTTON) ||
|
|
(uMsg == WM_MBUTTONUP && m_nRotateCameraButtonMask & MOUSE_MIDDLE_BUTTON) ||
|
|
(uMsg == WM_RBUTTONUP && m_nRotateCameraButtonMask & MOUSE_RIGHT_BUTTON) )
|
|
{
|
|
m_ViewArcBall.OnEnd();
|
|
}
|
|
|
|
if( uMsg == WM_LBUTTONDOWN ||
|
|
uMsg == WM_LBUTTONDBLCLK ||
|
|
uMsg == WM_MBUTTONDOWN ||
|
|
uMsg == WM_MBUTTONDBLCLK ||
|
|
uMsg == WM_RBUTTONDOWN ||
|
|
uMsg == WM_RBUTTONDBLCLK ||
|
|
uMsg == WM_LBUTTONUP ||
|
|
uMsg == WM_MBUTTONUP ||
|
|
uMsg == WM_RBUTTONUP ||
|
|
uMsg == WM_MOUSEWHEEL ||
|
|
uMsg == WM_MOUSEMOVE )
|
|
{
|
|
m_bDragSinceLastUpdate = true;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Desc: Returns a view matrix for rendering to a face of a cubemap.
|
|
//--------------------------------------------------------------------------------------
|
|
D3DXMATRIX DXUTGetCubeMapViewMatrix( DWORD dwFace )
|
|
{
|
|
D3DXVECTOR3 vEyePt = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
|
|
D3DXVECTOR3 vLookDir;
|
|
D3DXVECTOR3 vUpDir;
|
|
|
|
switch( dwFace )
|
|
{
|
|
case D3DCUBEMAP_FACE_POSITIVE_X:
|
|
vLookDir = D3DXVECTOR3( 1.0f, 0.0f, 0.0f );
|
|
vUpDir = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
|
|
break;
|
|
case D3DCUBEMAP_FACE_NEGATIVE_X:
|
|
vLookDir = D3DXVECTOR3(-1.0f, 0.0f, 0.0f );
|
|
vUpDir = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
|
|
break;
|
|
case D3DCUBEMAP_FACE_POSITIVE_Y:
|
|
vLookDir = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
|
|
vUpDir = D3DXVECTOR3( 0.0f, 0.0f,-1.0f );
|
|
break;
|
|
case D3DCUBEMAP_FACE_NEGATIVE_Y:
|
|
vLookDir = D3DXVECTOR3( 0.0f,-1.0f, 0.0f );
|
|
vUpDir = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
|
|
break;
|
|
case D3DCUBEMAP_FACE_POSITIVE_Z:
|
|
vLookDir = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
|
|
vUpDir = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
|
|
break;
|
|
case D3DCUBEMAP_FACE_NEGATIVE_Z:
|
|
vLookDir = D3DXVECTOR3( 0.0f, 0.0f,-1.0f );
|
|
vUpDir = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
|
|
break;
|
|
}
|
|
|
|
// Set the view transform for this cubemap surface
|
|
D3DXMATRIXA16 mView;
|
|
D3DXMatrixLookAtLH( &mView, &vEyePt, &vLookDir, &vUpDir );
|
|
return mView;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Returns the string for the given D3DFORMAT.
|
|
//--------------------------------------------------------------------------------------
|
|
LPCTSTR DXUTD3DFormatToString( D3DFORMAT format, bool bWithPrefix )
|
|
{
|
|
TCHAR* pstr = NULL;
|
|
switch( format )
|
|
{
|
|
case D3DFMT_UNKNOWN: pstr = "D3DFMT_UNKNOWN"; break;
|
|
case D3DFMT_R8G8B8: pstr = "D3DFMT_R8G8B8"; break;
|
|
case D3DFMT_A8R8G8B8: pstr = "D3DFMT_A8R8G8B8"; break;
|
|
case D3DFMT_X8R8G8B8: pstr = "D3DFMT_X8R8G8B8"; break;
|
|
case D3DFMT_R5G6B5: pstr = "D3DFMT_R5G6B5"; break;
|
|
case D3DFMT_X1R5G5B5: pstr = "D3DFMT_X1R5G5B5"; break;
|
|
case D3DFMT_A1R5G5B5: pstr = "D3DFMT_A1R5G5B5"; break;
|
|
case D3DFMT_A4R4G4B4: pstr = "D3DFMT_A4R4G4B4"; break;
|
|
case D3DFMT_R3G3B2: pstr = "D3DFMT_R3G3B2"; break;
|
|
case D3DFMT_A8: pstr = "D3DFMT_A8"; break;
|
|
case D3DFMT_A8R3G3B2: pstr = "D3DFMT_A8R3G3B2"; break;
|
|
case D3DFMT_X4R4G4B4: pstr = "D3DFMT_X4R4G4B4"; break;
|
|
case D3DFMT_A2B10G10R10: pstr = "D3DFMT_A2B10G10R10"; break;
|
|
case D3DFMT_A8B8G8R8: pstr = "D3DFMT_A8B8G8R8"; break;
|
|
case D3DFMT_X8B8G8R8: pstr = "D3DFMT_X8B8G8R8"; break;
|
|
case D3DFMT_G16R16: pstr = "D3DFMT_G16R16"; break;
|
|
case D3DFMT_A2R10G10B10: pstr = "D3DFMT_A2R10G10B10"; break;
|
|
case D3DFMT_A16B16G16R16: pstr = "D3DFMT_A16B16G16R16"; break;
|
|
case D3DFMT_A8P8: pstr = "D3DFMT_A8P8"; break;
|
|
case D3DFMT_P8: pstr = "D3DFMT_P8"; break;
|
|
case D3DFMT_L8: pstr = "D3DFMT_L8"; break;
|
|
case D3DFMT_A8L8: pstr = "D3DFMT_A8L8"; break;
|
|
case D3DFMT_A4L4: pstr = "D3DFMT_A4L4"; break;
|
|
case D3DFMT_V8U8: pstr = "D3DFMT_V8U8"; break;
|
|
case D3DFMT_L6V5U5: pstr = "D3DFMT_L6V5U5"; break;
|
|
case D3DFMT_X8L8V8U8: pstr = "D3DFMT_X8L8V8U8"; break;
|
|
case D3DFMT_Q8W8V8U8: pstr = "D3DFMT_Q8W8V8U8"; break;
|
|
case D3DFMT_V16U16: pstr = "D3DFMT_V16U16"; break;
|
|
case D3DFMT_A2W10V10U10: pstr = "D3DFMT_A2W10V10U10"; break;
|
|
case D3DFMT_UYVY: pstr = "D3DFMT_UYVY"; break;
|
|
case D3DFMT_YUY2: pstr = "D3DFMT_YUY2"; break;
|
|
case D3DFMT_DXT1: pstr = "D3DFMT_DXT1"; break;
|
|
case D3DFMT_DXT2: pstr = "D3DFMT_DXT2"; break;
|
|
case D3DFMT_DXT3: pstr = "D3DFMT_DXT3"; break;
|
|
case D3DFMT_DXT4: pstr = "D3DFMT_DXT4"; break;
|
|
case D3DFMT_DXT5: pstr = "D3DFMT_DXT5"; break;
|
|
case D3DFMT_D16_LOCKABLE: pstr = "D3DFMT_D16_LOCKABLE"; break;
|
|
case D3DFMT_D32: pstr = "D3DFMT_D32"; break;
|
|
case D3DFMT_D15S1: pstr = "D3DFMT_D15S1"; break;
|
|
case D3DFMT_D24S8: pstr = "D3DFMT_D24S8"; break;
|
|
case D3DFMT_D24X8: pstr = "D3DFMT_D24X8"; break;
|
|
case D3DFMT_D24X4S4: pstr = "D3DFMT_D24X4S4"; break;
|
|
case D3DFMT_D16: pstr = "D3DFMT_D16"; break;
|
|
case D3DFMT_L16: pstr = "D3DFMT_L16"; break;
|
|
case D3DFMT_VERTEXDATA: pstr = "D3DFMT_VERTEXDATA"; break;
|
|
case D3DFMT_INDEX16: pstr = "D3DFMT_INDEX16"; break;
|
|
case D3DFMT_INDEX32: pstr = "D3DFMT_INDEX32"; break;
|
|
case D3DFMT_Q16W16V16U16: pstr = "D3DFMT_Q16W16V16U16"; break;
|
|
case D3DFMT_MULTI2_ARGB8: pstr = "D3DFMT_MULTI2_ARGB8"; break;
|
|
case D3DFMT_R16F: pstr = "D3DFMT_R16F"; break;
|
|
case D3DFMT_G16R16F: pstr = "D3DFMT_G16R16F"; break;
|
|
case D3DFMT_A16B16G16R16F: pstr = "D3DFMT_A16B16G16R16F"; break;
|
|
case D3DFMT_R32F: pstr = "D3DFMT_R32F"; break;
|
|
case D3DFMT_G32R32F: pstr = "D3DFMT_G32R32F"; break;
|
|
case D3DFMT_A32B32G32R32F: pstr = "D3DFMT_A32B32G32R32F"; break;
|
|
case D3DFMT_CxV8U8: pstr = "D3DFMT_CxV8U8"; break;
|
|
default: pstr = "Unknown format"; break;
|
|
}
|
|
if( bWithPrefix || strstr( pstr, "D3DFMT_" )== NULL )
|
|
return pstr;
|
|
else
|
|
return pstr + lstrlen( "D3DFMT_" );
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Outputs to the debug stream a formatted Unicode string with a variable-argument list.
|
|
//--------------------------------------------------------------------------------------
|
|
VOID DXUTOutputDebugStringW( LPCTSTR strMsg, ... )
|
|
{
|
|
#if defined(DEBUG) | defined(_DEBUG)
|
|
TCHAR strBuffer[512];
|
|
|
|
va_list args;
|
|
va_start(args, strMsg);
|
|
StringCchVPrintfA( strBuffer, 512, strMsg, args );
|
|
strBuffer[511] = L'\0';
|
|
va_end(args);
|
|
|
|
OutputDebugString( strBuffer );
|
|
#else
|
|
UNREFERENCED_PARAMETER(strMsg);
|
|
#endif
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Outputs to the debug stream a formatted MBCS string with a variable-argument list.
|
|
//--------------------------------------------------------------------------------------
|
|
VOID DXUTOutputDebugStringA( LPCSTR strMsg, ... )
|
|
{
|
|
#if defined(DEBUG) | defined(_DEBUG)
|
|
CHAR strBuffer[512];
|
|
|
|
va_list args;
|
|
va_start(args, strMsg);
|
|
StringCchVPrintfA( strBuffer, 512, strMsg, args );
|
|
strBuffer[511] = '\0';
|
|
va_end(args);
|
|
|
|
OutputDebugStringA( strBuffer );
|
|
#else
|
|
UNREFERENCED_PARAMETER(strMsg);
|
|
#endif
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
CDXUTLineManager::CDXUTLineManager()
|
|
{
|
|
m_pd3dDevice = NULL;
|
|
m_pD3DXLine = NULL;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
CDXUTLineManager::~CDXUTLineManager()
|
|
{
|
|
OnDeletedDevice();
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTLineManager::OnCreatedDevice( IDirect3DDevice9* pd3dDevice )
|
|
{
|
|
m_pd3dDevice = pd3dDevice;
|
|
|
|
HRESULT hr;
|
|
hr = D3DXCreateLine( m_pd3dDevice, &m_pD3DXLine );
|
|
if( FAILED(hr) )
|
|
return hr;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTLineManager::OnResetDevice()
|
|
{
|
|
if( m_pD3DXLine )
|
|
m_pD3DXLine->OnResetDevice();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTLineManager::OnRender()
|
|
{
|
|
HRESULT hr;
|
|
if( NULL == m_pD3DXLine )
|
|
return E_INVALIDARG;
|
|
|
|
bool bDrawingHasBegun = false;
|
|
float fLastWidth = 0.0f;
|
|
bool bLastAntiAlias = false;
|
|
|
|
for( int i=0; i<m_LinesList.GetSize(); i++ )
|
|
{
|
|
LINE_NODE* pLineNode = m_LinesList.GetAt(i);
|
|
if( pLineNode )
|
|
{
|
|
if( !bDrawingHasBegun ||
|
|
fLastWidth != pLineNode->fWidth ||
|
|
bLastAntiAlias != pLineNode->bAntiAlias )
|
|
{
|
|
if( bDrawingHasBegun )
|
|
{
|
|
hr = m_pD3DXLine->End();
|
|
if( FAILED(hr) )
|
|
return hr;
|
|
}
|
|
|
|
m_pD3DXLine->SetWidth( pLineNode->fWidth );
|
|
m_pD3DXLine->SetAntialias( pLineNode->bAntiAlias );
|
|
|
|
fLastWidth = pLineNode->fWidth;
|
|
bLastAntiAlias = pLineNode->bAntiAlias;
|
|
|
|
hr = m_pD3DXLine->Begin();
|
|
if( FAILED(hr) )
|
|
return hr;
|
|
bDrawingHasBegun = true;
|
|
}
|
|
|
|
hr = m_pD3DXLine->Draw( pLineNode->pVertexList, pLineNode->dwVertexListCount, pLineNode->Color );
|
|
if( FAILED(hr) )
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
if( bDrawingHasBegun )
|
|
{
|
|
hr = m_pD3DXLine->End();
|
|
if( FAILED(hr) )
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTLineManager::OnLostDevice()
|
|
{
|
|
if( m_pD3DXLine )
|
|
m_pD3DXLine->OnLostDevice();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTLineManager::OnDeletedDevice()
|
|
{
|
|
RemoveAllLines();
|
|
SAFE_RELEASE( m_pD3DXLine );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTLineManager::AddLine( int* pnLineID, D3DXVECTOR2* pVertexList, DWORD dwVertexListCount, D3DCOLOR Color, float fWidth, float fScaleRatio, bool bAntiAlias )
|
|
{
|
|
if( pVertexList == NULL || dwVertexListCount == 0 )
|
|
return E_INVALIDARG;
|
|
|
|
LINE_NODE* pLineNode = new LINE_NODE;
|
|
if( pLineNode == NULL )
|
|
return E_OUTOFMEMORY;
|
|
ZeroMemory( pLineNode, sizeof(LINE_NODE) );
|
|
|
|
pLineNode->nLineID = m_LinesList.GetSize();
|
|
pLineNode->Color = Color;
|
|
pLineNode->fWidth = fWidth;
|
|
pLineNode->bAntiAlias = bAntiAlias;
|
|
pLineNode->dwVertexListCount = dwVertexListCount;
|
|
|
|
if( pnLineID )
|
|
*pnLineID = pLineNode->nLineID;
|
|
|
|
pLineNode->pVertexList = new D3DXVECTOR2[dwVertexListCount];
|
|
if( pLineNode->pVertexList == NULL )
|
|
{
|
|
delete pLineNode;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
for( DWORD i=0; i<dwVertexListCount; i++ )
|
|
{
|
|
pLineNode->pVertexList[i] = pVertexList[i] * fScaleRatio;
|
|
}
|
|
|
|
m_LinesList.Add( pLineNode );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTLineManager::AddRect( int* pnLineID, RECT rc, D3DCOLOR Color, float fWidth, float fScaleRatio, bool bAntiAlias )
|
|
{
|
|
if( fWidth > 2.0f )
|
|
{
|
|
D3DXVECTOR2 vertexList[8];
|
|
|
|
vertexList[0].x = (float)rc.left;
|
|
vertexList[0].y = (float)rc.top - (fWidth/2.0f);
|
|
|
|
vertexList[1].x = (float)rc.left;
|
|
vertexList[1].y = (float)rc.bottom + (fWidth/2.0f);
|
|
|
|
vertexList[2].x = (float)rc.left;
|
|
vertexList[2].y = (float)rc.bottom - 0.5f;
|
|
|
|
vertexList[3].x = (float)rc.right;
|
|
vertexList[3].y = (float)rc.bottom - 0.5f;
|
|
|
|
vertexList[4].x = (float)rc.right;
|
|
vertexList[4].y = (float)rc.bottom + (fWidth/2.0f);
|
|
|
|
vertexList[5].x = (float)rc.right;
|
|
vertexList[5].y = (float)rc.top - (fWidth/2.0f);
|
|
|
|
vertexList[6].x = (float)rc.right;
|
|
vertexList[6].y = (float)rc.top;
|
|
|
|
vertexList[7].x = (float)rc.left;
|
|
vertexList[7].y = (float)rc.top;
|
|
|
|
return AddLine( pnLineID, vertexList, 8, Color, fWidth, fScaleRatio, bAntiAlias );
|
|
}
|
|
else
|
|
{
|
|
D3DXVECTOR2 vertexList[5];
|
|
vertexList[0].x = (float)rc.left;
|
|
vertexList[0].y = (float)rc.top;
|
|
|
|
vertexList[1].x = (float)rc.left;
|
|
vertexList[1].y = (float)rc.bottom;
|
|
|
|
vertexList[2].x = (float)rc.right;
|
|
vertexList[2].y = (float)rc.bottom;
|
|
|
|
vertexList[3].x = (float)rc.right;
|
|
vertexList[3].y = (float)rc.top;
|
|
|
|
vertexList[4].x = (float)rc.left;
|
|
vertexList[4].y = (float)rc.top;
|
|
|
|
return AddLine( pnLineID, vertexList, 5, Color, fWidth, fScaleRatio, bAntiAlias );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTLineManager::RemoveLine( int nLineID )
|
|
{
|
|
for( int i=0; i<m_LinesList.GetSize(); i++ )
|
|
{
|
|
LINE_NODE* pLineNode = m_LinesList.GetAt(i);
|
|
if( pLineNode && pLineNode->nLineID == nLineID )
|
|
{
|
|
SAFE_DELETE_ARRAY( pLineNode->pVertexList );
|
|
delete pLineNode;
|
|
m_LinesList.SetAt(i, NULL);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTLineManager::RemoveAllLines()
|
|
{
|
|
for( int i=0; i<m_LinesList.GetSize(); i++ )
|
|
{
|
|
LINE_NODE* pLineNode = m_LinesList.GetAt(i);
|
|
if( pLineNode )
|
|
{
|
|
SAFE_DELETE_ARRAY( pLineNode->pVertexList );
|
|
delete pLineNode;
|
|
}
|
|
}
|
|
m_LinesList.RemoveAll();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
CDXUTTextHelper::CDXUTTextHelper( ID3DXFont* pFont, ID3DXSprite* pSprite, int nLineHeight )
|
|
{
|
|
m_pFont = pFont;
|
|
m_pSprite = pSprite;
|
|
m_clr = D3DXCOLOR(1,1,1,1);
|
|
m_pt.x = 0;
|
|
m_pt.y = 0;
|
|
m_nLineHeight = nLineHeight;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTTextHelper::DrawFormattedTextLine( const TCHAR* strMsg, ... )
|
|
{
|
|
TCHAR strBuffer[512];
|
|
|
|
va_list args;
|
|
va_start(args, strMsg);
|
|
StringCchVPrintf( strBuffer, 512, strMsg, args );
|
|
strBuffer[511] = L'\0';
|
|
va_end(args);
|
|
|
|
return DrawTextLine( strBuffer );
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTTextHelper::DrawTextLine( const TCHAR* strMsg )
|
|
{
|
|
if( NULL == m_pFont )
|
|
return DXUT_ERR_MSGBOX( "DrawTextLine", E_INVALIDARG );
|
|
|
|
HRESULT hr;
|
|
RECT rc;
|
|
SetRect( &rc, m_pt.x, m_pt.y, 0, 0 );
|
|
hr = m_pFont->DrawText( m_pSprite, strMsg, -1, &rc, DT_NOCLIP, m_clr );
|
|
if( FAILED(hr) )
|
|
return DXTRACE_ERR_MSGBOX( "DrawText", hr );
|
|
|
|
m_pt.y += m_nLineHeight;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CDXUTTextHelper::DrawFormattedTextLine( RECT &rc, DWORD dwFlags, const TCHAR* strMsg, ... )
|
|
{
|
|
TCHAR strBuffer[512];
|
|
|
|
va_list args;
|
|
va_start(args, strMsg);
|
|
StringCchVPrintf( strBuffer, 512, strMsg, args );
|
|
strBuffer[511] = L'\0';
|
|
va_end(args);
|
|
|
|
return DrawTextLine( rc, dwFlags, strBuffer );
|
|
}
|
|
|
|
|
|
HRESULT CDXUTTextHelper::DrawTextLine( RECT &rc, DWORD dwFlags, const TCHAR* strMsg )
|
|
{
|
|
if( NULL == m_pFont )
|
|
return DXUT_ERR_MSGBOX( "DrawTextLine", E_INVALIDARG );
|
|
|
|
HRESULT hr;
|
|
hr = m_pFont->DrawText( m_pSprite, strMsg, -1, &rc, dwFlags, m_clr );
|
|
if( FAILED(hr) )
|
|
return DXTRACE_ERR_MSGBOX( "DrawText", hr );
|
|
|
|
m_pt.y += m_nLineHeight;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
void CDXUTTextHelper::Begin()
|
|
{
|
|
if( m_pSprite )
|
|
m_pSprite->Begin( D3DXSPRITE_ALPHABLEND | D3DXSPRITE_SORT_TEXTURE );
|
|
}
|
|
void CDXUTTextHelper::End()
|
|
{
|
|
if( m_pSprite )
|
|
m_pSprite->End();
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
IDirect3DDevice9* CDXUTDirectionWidget::s_pd3dDevice = NULL;
|
|
ID3DXEffect* CDXUTDirectionWidget::s_pEffect = NULL;
|
|
ID3DXMesh* CDXUTDirectionWidget::s_pMesh = NULL;
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
CDXUTDirectionWidget::CDXUTDirectionWidget()
|
|
{
|
|
m_fRadius = 1.0f;
|
|
m_vDefaultDir = D3DXVECTOR3(0,1,0);
|
|
m_vCurrentDir = m_vDefaultDir;
|
|
m_nRotateMask = MOUSE_RIGHT_BUTTON;
|
|
|
|
D3DXMatrixIdentity( &m_mView );
|
|
D3DXMatrixIdentity( &m_mRot );
|
|
D3DXMatrixIdentity( &m_mRotSnapshot );
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTDirectionWidget::StaticOnCreateDevice( IDirect3DDevice9* pd3dDevice )
|
|
{
|
|
TCHAR str[MAX_PATH];
|
|
HRESULT hr;
|
|
|
|
s_pd3dDevice = pd3dDevice;
|
|
|
|
// Read the D3DX effect file
|
|
DXUTFindDXSDKMediaFileCch( str, MAX_PATH, "UI\\DXUTShared.fx" );
|
|
|
|
// If this fails, there should be debug output as to
|
|
// why the .fx file failed to compile
|
|
D3DXCreateEffectFromFileA( s_pd3dDevice, str, NULL, NULL, D3DXFX_NOT_CLONEABLE, NULL, &s_pEffect, NULL );
|
|
|
|
// Load the mesh with D3DX and get back a ID3DXMesh*. For this
|
|
// sample we'll ignore the X file's embedded materials since we know
|
|
// exactly the model we're loading. See the mesh samples such as
|
|
// "OptimizedMesh" for a more generic mesh loading example.
|
|
DXUTFindDXSDKMediaFileCch( str, MAX_PATH, "UI\\arrow.x" );
|
|
|
|
D3DXLoadMeshFromX( str, D3DXMESH_MANAGED, s_pd3dDevice, NULL,
|
|
NULL, NULL, NULL, &s_pMesh);
|
|
|
|
// Optimize the mesh for this graphics card's vertex cache
|
|
// so when rendering the mesh's triangle list the vertices will
|
|
// cache hit more often so it won't have to re-execute the vertex shader
|
|
// on those vertices so it will improve perf.
|
|
DWORD* rgdwAdjacency = new DWORD[s_pMesh->GetNumFaces() * 3];
|
|
if( rgdwAdjacency == NULL )
|
|
return E_OUTOFMEMORY;
|
|
s_pMesh->GenerateAdjacency(1e-6f,rgdwAdjacency);
|
|
s_pMesh->OptimizeInplace(D3DXMESHOPT_VERTEXCACHE, rgdwAdjacency, NULL, NULL, NULL);
|
|
delete []rgdwAdjacency;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTDirectionWidget::OnResetDevice( const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
|
|
{
|
|
m_ArcBall.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
void CDXUTDirectionWidget::StaticOnLostDevice()
|
|
{
|
|
if( s_pEffect )
|
|
s_pEffect->OnLostDevice();
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
void CDXUTDirectionWidget::StaticOnDestroyDevice()
|
|
{
|
|
SAFE_RELEASE(s_pEffect);
|
|
SAFE_RELEASE(s_pMesh);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
LRESULT CDXUTDirectionWidget::HandleMessages( HWND hWnd, UINT uMsg,
|
|
WPARAM wParam, LPARAM lParam )
|
|
{
|
|
switch( uMsg )
|
|
{
|
|
case WM_LBUTTONDOWN:
|
|
case WM_MBUTTONDOWN:
|
|
case WM_RBUTTONDOWN:
|
|
{
|
|
if( ((m_nRotateMask & MOUSE_LEFT_BUTTON) != 0 && uMsg == WM_LBUTTONDOWN) ||
|
|
((m_nRotateMask & MOUSE_MIDDLE_BUTTON) != 0 && uMsg == WM_MBUTTONDOWN) ||
|
|
((m_nRotateMask & MOUSE_RIGHT_BUTTON) != 0 && uMsg == WM_RBUTTONDOWN) )
|
|
{
|
|
int iMouseX = (int)(short)LOWORD(lParam);
|
|
int iMouseY = (int)(short)HIWORD(lParam);
|
|
m_ArcBall.OnBegin( iMouseX, iMouseY );
|
|
SetCapture(hWnd);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
case WM_MOUSEMOVE:
|
|
{
|
|
if( m_ArcBall.IsBeingDragged() )
|
|
{
|
|
int iMouseX = (int)(short)LOWORD(lParam);
|
|
int iMouseY = (int)(short)HIWORD(lParam);
|
|
m_ArcBall.OnMove( iMouseX, iMouseY );
|
|
UpdateLightDir();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
case WM_LBUTTONUP:
|
|
case WM_MBUTTONUP:
|
|
case WM_RBUTTONUP:
|
|
{
|
|
if( ((m_nRotateMask & MOUSE_LEFT_BUTTON) != 0 && uMsg == WM_LBUTTONUP) ||
|
|
((m_nRotateMask & MOUSE_MIDDLE_BUTTON) != 0 && uMsg == WM_MBUTTONUP) ||
|
|
((m_nRotateMask & MOUSE_RIGHT_BUTTON) != 0 && uMsg == WM_RBUTTONUP) )
|
|
{
|
|
m_ArcBall.OnEnd();
|
|
ReleaseCapture();
|
|
}
|
|
|
|
UpdateLightDir();
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTDirectionWidget::OnRender( D3DXCOLOR color, const D3DXMATRIX* pmView,
|
|
const D3DXMATRIX* pmProj, const D3DXVECTOR3* pEyePt )
|
|
{
|
|
m_mView = *pmView;
|
|
|
|
// Render the light spheres so the user can visually see the light dir
|
|
UINT iPass, cPasses;
|
|
D3DXMATRIX mRotate;
|
|
D3DXMATRIX mScale;
|
|
D3DXMATRIX mTrans;
|
|
D3DXMATRIXA16 mWorldViewProj;
|
|
HRESULT hr;
|
|
|
|
s_pEffect->SetTechnique( "RenderWith1LightNoTexture" );
|
|
s_pEffect->SetVector( "g_MaterialDiffuseColor", (D3DXVECTOR4*)&color);
|
|
|
|
D3DXVECTOR3 vEyePt;
|
|
D3DXVec3Normalize( &vEyePt, pEyePt );
|
|
V( s_pEffect->SetValue( "g_LightDir", &vEyePt, sizeof(D3DXVECTOR3) ) );
|
|
|
|
// Rotate arrow model to point towards origin
|
|
D3DXMATRIX mRotateA, mRotateB;
|
|
D3DXVECTOR3 vAt = D3DXVECTOR3(0,0,0);
|
|
D3DXVECTOR3 vUp = D3DXVECTOR3(0,1,0);
|
|
D3DXMatrixRotationX( &mRotateB, D3DX_PI );
|
|
D3DXMatrixLookAtLH( &mRotateA, &m_vCurrentDir, &vAt, &vUp );
|
|
D3DXMatrixInverse( &mRotateA, NULL, &mRotateA );
|
|
mRotate = mRotateB * mRotateA;
|
|
|
|
D3DXVECTOR3 vL = m_vCurrentDir * m_fRadius * 1.0f;
|
|
D3DXMatrixTranslation( &mTrans, vL.x, vL.y, vL.z );
|
|
D3DXMatrixScaling( &mScale, m_fRadius*0.2f, m_fRadius*0.2f, m_fRadius*0.2f );
|
|
|
|
D3DXMATRIX mWorld = mRotate * mScale * mTrans;
|
|
mWorldViewProj = mWorld * (m_mView) * (*pmProj);
|
|
|
|
V( s_pEffect->SetMatrix( "g_mWorldViewProjection", &mWorldViewProj ) );
|
|
V( s_pEffect->SetMatrix( "g_mWorld", &mWorld ) );
|
|
|
|
for( int iSubset=0; iSubset<2; iSubset++ )
|
|
{
|
|
V( s_pEffect->Begin(&cPasses, 0) );
|
|
for (iPass = 0; iPass < cPasses; iPass++)
|
|
{
|
|
V( s_pEffect->BeginPass(iPass) );
|
|
V( s_pMesh->DrawSubset(iSubset) );
|
|
V( s_pEffect->EndPass() );
|
|
}
|
|
V( s_pEffect->End() );
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT CDXUTDirectionWidget::UpdateLightDir()
|
|
{
|
|
D3DXMATRIX mInvView;
|
|
D3DXMatrixInverse(&mInvView, NULL, &m_mView);
|
|
mInvView._41 = mInvView._42 = mInvView._43 = 0;
|
|
|
|
D3DXMATRIX mLastRotInv;
|
|
D3DXMatrixInverse(&mLastRotInv, NULL, &m_mRotSnapshot);
|
|
|
|
D3DXMATRIX mRot = *m_ArcBall.GetRotationMatrix();
|
|
m_mRotSnapshot = mRot;
|
|
|
|
// Accumulate the delta of the arcball's rotation in view space.
|
|
// Note that per-frame delta rotations could be problematic over long periods of time.
|
|
m_mRot *= m_mView * mLastRotInv * mRot * mInvView;
|
|
|
|
// Since we're accumulating delta rotations, we need to orthonormalize
|
|
// the matrix to prevent eventual matrix skew
|
|
D3DXVECTOR3* pXBasis = (D3DXVECTOR3*) &m_mRot._11;
|
|
D3DXVECTOR3* pYBasis = (D3DXVECTOR3*) &m_mRot._21;
|
|
D3DXVECTOR3* pZBasis = (D3DXVECTOR3*) &m_mRot._31;
|
|
D3DXVec3Normalize( pXBasis, pXBasis );
|
|
D3DXVec3Cross( pYBasis, pZBasis, pXBasis );
|
|
D3DXVec3Normalize( pYBasis, pYBasis );
|
|
D3DXVec3Cross( pZBasis, pXBasis, pYBasis );
|
|
|
|
// Transform the default direction vector by the light's rotation matrix
|
|
D3DXVec3TransformNormal( &m_vCurrentDir, &m_vDefaultDir, &m_mRot );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Direct3D9 dynamic linking support -- calls top-level D3D9 APIs with graceful
|
|
// failure if APIs are not present.
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
// Function prototypes
|
|
typedef IDirect3D9* (WINAPI * LPDIRECT3DCREATE9) (UINT);
|
|
typedef INT (WINAPI * LPD3DPERF_BEGINEVENT)(D3DCOLOR, LPCTSTR);
|
|
typedef INT (WINAPI * LPD3DPERF_ENDEVENT)(void);
|
|
typedef VOID (WINAPI * LPD3DPERF_SETMARKER)(D3DCOLOR, LPCTSTR);
|
|
typedef VOID (WINAPI * LPD3DPERF_SETREGION)(D3DCOLOR, LPCTSTR);
|
|
typedef BOOL (WINAPI * LPD3DPERF_QUERYREPEATFRAME)(void);
|
|
typedef VOID (WINAPI * LPD3DPERF_SETOPTIONS)( DWORD dwOptions );
|
|
typedef DWORD (WINAPI * LPD3DPERF_GETSTATUS)( void );
|
|
|
|
// Module and function pointers
|
|
static HMODULE s_hModD3D9 = NULL;
|
|
static LPDIRECT3DCREATE9 s_DynamicDirect3DCreate9 = NULL;
|
|
static LPD3DPERF_BEGINEVENT s_DynamicD3DPERF_BeginEvent = NULL;
|
|
static LPD3DPERF_ENDEVENT s_DynamicD3DPERF_EndEvent = NULL;
|
|
static LPD3DPERF_SETMARKER s_DynamicD3DPERF_SetMarker = NULL;
|
|
static LPD3DPERF_SETREGION s_DynamicD3DPERF_SetRegion = NULL;
|
|
static LPD3DPERF_QUERYREPEATFRAME s_DynamicD3DPERF_QueryRepeatFrame = NULL;
|
|
static LPD3DPERF_SETOPTIONS s_DynamicD3DPERF_SetOptions = NULL;
|
|
static LPD3DPERF_GETSTATUS s_DynamicD3DPERF_GetStatus = NULL;
|
|
|
|
// Ensure function pointers are initialized
|
|
// MATCH
|
|
static bool DXUT_EnsureD3DAPIs( void )
|
|
{
|
|
// If module is non-NULL, this function has already been called. Note
|
|
// that this doesn't guarantee that all D3D9 procaddresses were found.
|
|
if( s_hModD3D9 != NULL )
|
|
return true;
|
|
|
|
// This may fail if DirectX 9 isn't installed
|
|
TCHAR wszPath[MAX_PATH+1];
|
|
if( !::GetSystemDirectory( wszPath, MAX_PATH+1 ) )
|
|
return false;
|
|
StringCchCat( wszPath, MAX_PATH, "\\d3d9.dll" );
|
|
s_hModD3D9 = LoadLibrary( wszPath );
|
|
if( s_hModD3D9 == NULL )
|
|
return false;
|
|
s_DynamicDirect3DCreate9 = (LPDIRECT3DCREATE9)GetProcAddress( s_hModD3D9, "Direct3DCreate9" );
|
|
s_DynamicD3DPERF_BeginEvent = (LPD3DPERF_BEGINEVENT)GetProcAddress( s_hModD3D9, "D3DPERF_BeginEvent" );
|
|
s_DynamicD3DPERF_EndEvent = (LPD3DPERF_ENDEVENT)GetProcAddress( s_hModD3D9, "D3DPERF_EndEvent" );
|
|
s_DynamicD3DPERF_SetMarker = (LPD3DPERF_SETMARKER)GetProcAddress( s_hModD3D9, "D3DPERF_SetMarker" );
|
|
s_DynamicD3DPERF_SetRegion = (LPD3DPERF_SETREGION)GetProcAddress( s_hModD3D9, "D3DPERF_SetRegion" );
|
|
s_DynamicD3DPERF_QueryRepeatFrame = (LPD3DPERF_QUERYREPEATFRAME)GetProcAddress( s_hModD3D9, "D3DPERF_QueryRepeatFrame" );
|
|
s_DynamicD3DPERF_SetOptions = (LPD3DPERF_SETOPTIONS)GetProcAddress( s_hModD3D9, "D3DPERF_SetOptions" );
|
|
s_DynamicD3DPERF_GetStatus = (LPD3DPERF_GETSTATUS)GetProcAddress( s_hModD3D9, "D3DPERF_GetStatus" );
|
|
return true;
|
|
}
|
|
|
|
// MATCH
|
|
IDirect3D9 * WINAPI DXUT_Dynamic_Direct3DCreate9(UINT SDKVersion)
|
|
{
|
|
if( DXUT_EnsureD3DAPIs() && s_DynamicDirect3DCreate9 != NULL )
|
|
return s_DynamicDirect3DCreate9( SDKVersion );
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
// MATCH
|
|
int WINAPI DXUT_Dynamic_D3DPERF_BeginEvent( D3DCOLOR col, LPCTSTR wszName )
|
|
{
|
|
if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_BeginEvent != NULL )
|
|
return s_DynamicD3DPERF_BeginEvent( col, wszName );
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
// MATCH
|
|
int WINAPI DXUT_Dynamic_D3DPERF_EndEvent( void )
|
|
{
|
|
if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_EndEvent != NULL )
|
|
return s_DynamicD3DPERF_EndEvent();
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
// MATCH
|
|
void WINAPI DXUT_Dynamic_D3DPERF_SetMarker( D3DCOLOR col, LPCTSTR wszName )
|
|
{
|
|
if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_SetMarker != NULL )
|
|
s_DynamicD3DPERF_SetMarker( col, wszName );
|
|
}
|
|
|
|
// MATCH
|
|
void WINAPI DXUT_Dynamic_D3DPERF_SetRegion( D3DCOLOR col, LPCTSTR wszName )
|
|
{
|
|
if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_SetRegion != NULL )
|
|
s_DynamicD3DPERF_SetRegion( col, wszName );
|
|
}
|
|
|
|
// MATCH
|
|
BOOL WINAPI DXUT_Dynamic_D3DPERF_QueryRepeatFrame( void )
|
|
{
|
|
if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_QueryRepeatFrame != NULL )
|
|
return s_DynamicD3DPERF_QueryRepeatFrame();
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
// MATCH
|
|
void WINAPI DXUT_Dynamic_D3DPERF_SetOptions( DWORD dwOptions )
|
|
{
|
|
if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_SetOptions != NULL )
|
|
s_DynamicD3DPERF_SetOptions( dwOptions );
|
|
}
|
|
|
|
// MATCH
|
|
DWORD WINAPI DXUT_Dynamic_D3DPERF_GetStatus( void )
|
|
{
|
|
if( DXUT_EnsureD3DAPIs() && s_DynamicD3DPERF_GetStatus != NULL )
|
|
return s_DynamicD3DPERF_GetStatus();
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
//------------------------
|
|
|
|
HRESULT WINAPI DXTraceWrapper( const char* strFile, DWORD dwLine, HRESULT hr, const char* strMsg, BOOL bPopMsgBox )
|
|
{
|
|
#ifdef _DEBUG
|
|
TCHAR szBuffer[1024];
|
|
sprintf(szBuffer, "DXTrace: %s (%d) returned 0x%x, msg=%s", strFile, dwLine, hr, strMsg);
|
|
OutputDebugString(szBuffer);
|
|
#endif
|
|
return 0;
|
|
} |