/*****************************************************************************\ FILE: util.cpp DESCRIPTION: BryanSt 12/22/2000 Copyright (C) Microsoft Corp 2000-2001. All rights reserved. \*****************************************************************************/ #include "stdafx.h" #include "..\\d3dsaver\\dxutil.h" #define SECURITY_WIN32 #include extern "C" { #include // for GetUserNameEx() } // Define some things for debug.h // #define SZ_DEBUGINI "ccshell.ini" #define SZ_DEBUGSECTION "MSMUSEUM" #define SZ_MODULE "MSMUSEUM" #define DECLARE_DEBUG #undef __IShellFolder2_FWD_DEFINED__ #include #include #include "util.h" BOOL g_fOverheadViewTest = FALSE; #ifdef DEBUG DWORD g_TLSliStopWatchStartHi = 0xFFFFFFFF; DWORD g_TLSliStopWatchStartLo = 0xFFFFFFFF; LARGE_INTEGER g_liStopWatchFreq = {0}; #endif // DEBUG ///////////////////////////////////////////////////////////////////// // Debug Timing Helpers ///////////////////////////////////////////////////////////////////// #ifdef DEBUG void DebugStartWatch(void) { LARGE_INTEGER liStopWatchStart; if (-1 == g_TLSliStopWatchStartHi) { g_TLSliStopWatchStartHi = TlsAlloc(); g_TLSliStopWatchStartLo = TlsAlloc(); liStopWatchStart.QuadPart = 0; QueryPerformanceFrequency(&g_liStopWatchFreq); // Only a one time call since it's value can't change while the system is running. } else { liStopWatchStart.HighPart = PtrToUlong(TlsGetValue(g_TLSliStopWatchStartHi)); liStopWatchStart.LowPart = PtrToUlong(TlsGetValue(g_TLSliStopWatchStartLo)); } QueryPerformanceCounter(&liStopWatchStart); TlsSetValue(g_TLSliStopWatchStartHi, IntToPtr(liStopWatchStart.HighPart)); TlsSetValue(g_TLSliStopWatchStartLo, IntToPtr(liStopWatchStart.LowPart)); } DWORD DebugStopWatch(void) { LARGE_INTEGER liDiff; LARGE_INTEGER liStopWatchStart; QueryPerformanceCounter(&liDiff); liStopWatchStart.HighPart = PtrToUlong(TlsGetValue(g_TLSliStopWatchStartHi)); liStopWatchStart.LowPart = PtrToUlong(TlsGetValue(g_TLSliStopWatchStartLo)); liDiff.QuadPart -= liStopWatchStart.QuadPart; DWORD dwTime = (DWORD)((liDiff.QuadPart * 1000) / g_liStopWatchFreq.QuadPart); TlsSetValue(g_TLSliStopWatchStartHi, (LPVOID) 0); TlsSetValue(g_TLSliStopWatchStartLo, (LPVOID) 0); return dwTime; } #else // DEBUG void DebugStartWatch(void) { } DWORD DebugStopWatch(void) { return 0; } #endif // DEBUG float rnd(void) { return (((FLOAT)rand() ) / RAND_MAX); } int GetRandomInt(int nMin, int nMax) { int nDelta = (nMax - nMin + 1); float fRandom = (((float) rand()) / ((float) RAND_MAX)); float fDelta = (fRandom * nDelta); int nAmount = (int)(fDelta); nAmount = min(nAmount, nDelta - 1); return (nMin + nAmount); } HRESULT SetBoxStripVertexes(MYVERTEX * ppvVertexs, D3DXVECTOR3 vLocation, D3DXVECTOR3 vSize, D3DXVECTOR3 vNormal) { HRESULT hr = S_OK; float fTextureScale = 1.0f; // How many repeats per 1 unit. // Draw Object if (vNormal.x) // The object is in the y-z plane { ppvVertexs[0] = MYVERTEX(D3DXVECTOR3(vLocation.x, vLocation.y, vLocation.z), vNormal, 0, fTextureScale); ppvVertexs[1] = MYVERTEX(D3DXVECTOR3(vLocation.x, vLocation.y + vSize.y, vLocation.z), vNormal, 0, 0); ppvVertexs[2] = MYVERTEX(D3DXVECTOR3(vLocation.x, vLocation.y, vLocation.z + vSize.z), vNormal, fTextureScale, fTextureScale); ppvVertexs[3] = MYVERTEX(D3DXVECTOR3(vLocation.x, vLocation.y + vSize.y, vLocation.z + vSize.z), vNormal, fTextureScale, 0); } else if (vNormal.y) // The object is in the x-z plane { ppvVertexs[0] = MYVERTEX(D3DXVECTOR3(vLocation.x, vLocation.y, vLocation.z), vNormal, 0, fTextureScale); ppvVertexs[1] = MYVERTEX(D3DXVECTOR3(vLocation.x, vLocation.y, vLocation.z + vSize.z), vNormal, 0, 0); ppvVertexs[2] = MYVERTEX(D3DXVECTOR3(vLocation.x + vSize.x, vLocation.y, vLocation.z), vNormal, fTextureScale, fTextureScale); ppvVertexs[3] = MYVERTEX(D3DXVECTOR3(vLocation.x + vSize.x, vLocation.y, vLocation.z + vSize.z), vNormal, fTextureScale, 0); } else { // The object is in the x-y plane ppvVertexs[0] = MYVERTEX(D3DXVECTOR3(vLocation.x, vLocation.y, vLocation.z), vNormal, 0, fTextureScale); ppvVertexs[1] = MYVERTEX(D3DXVECTOR3(vLocation.x, vLocation.y + vSize.y, vLocation.z), vNormal, 0, 0); ppvVertexs[2] = MYVERTEX(D3DXVECTOR3(vLocation.x + vSize.x, vLocation.y, vLocation.z), vNormal, fTextureScale, fTextureScale); ppvVertexs[3] = MYVERTEX(D3DXVECTOR3(vLocation.x + vSize.x, vLocation.y + vSize.y, vLocation.z), vNormal, fTextureScale, 0); } return hr; } float AddVectorComponents(D3DXVECTOR3 vDir) { return (vDir.x + vDir.y + vDir.z); } int CALLBACK DPALocalFree_Callback(LPVOID p, LPVOID pData) { LocalFree(p); // NULLs will be ignored. return 1; } int CALLBACK DPAStrCompare(void * pv1, void * pv2, LPARAM lParam) { LPCTSTR pszSearch = (LPCTSTR) pv1; LPCTSTR pszCurrent = (LPCTSTR) pv2; if (pszSearch && pszCurrent && !StrCmpI(pszSearch, pszCurrent)) { return 0; // They match } return 1; } float GetSurfaceRatio(IDirect3DTexture8 * pTexture) { float fX = 1.0f; float fY = 1.0f; if (pTexture) { D3DSURFACE_DESC desc; if (SUCCEEDED(pTexture->GetLevelDesc(0, &desc))) { fX = (float) desc.Width; fY = (float) desc.Height; } } if (0.0f == fX) { fX = 1.0f; // Protect from zero divides } return (fY / fX); } int GetTextureHeight(IDirect3DTexture8 * pTexture) { int nHeight = 0; if (pTexture) { D3DSURFACE_DESC desc; if (SUCCEEDED(pTexture->GetLevelDesc(0, &desc))) { nHeight = desc.Height; } } return nHeight; } int GetTextureWidth(IDirect3DTexture8 * pTexture) { int nWidth = 0; if (pTexture) { D3DSURFACE_DESC desc; if (SUCCEEDED(pTexture->GetLevelDesc(0, &desc))) { nWidth = desc.Width; } } return nWidth; } ///////////////////////////////////////////////////////////////////// // Registry Helpers ///////////////////////////////////////////////////////////////////// HRESULT HrRegOpenKeyEx(HKEY hKey, LPCTSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) { DWORD dwError = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, phkResult); return HRESULT_FROM_WIN32(dwError); } HRESULT HrRegCreateKeyEx(HKEY hKey, LPCTSTR lpSubKey, DWORD Reserved, LPTSTR lpClass, DWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition) { DWORD dwError = RegCreateKeyEx(hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition); return HRESULT_FROM_WIN32(dwError); } HRESULT HrSHGetValue(IN HKEY hKey, IN LPCTSTR pszSubKey, OPTIONAL IN LPCTSTR pszValue, OPTIONAL OUT LPDWORD pdwType, OPTIONAL OUT LPVOID pvData, OPTIONAL OUT LPDWORD pcbData) { DWORD dwError = SHGetValue(hKey, pszSubKey, pszValue, pdwType, pvData, pcbData); return HRESULT_FROM_WIN32(dwError); } HRESULT HrSHSetValue(IN HKEY hkey, IN LPCTSTR pszSubKey, OPTIONAL IN LPCTSTR pszValue, DWORD dwType, OPTIONAL OUT LPVOID pvData, IN DWORD cbData) { DWORD dwError = SHSetValue(hkey, pszSubKey, pszValue, dwType, pvData, cbData); return HRESULT_FROM_WIN32(dwError); } HRESULT HrRegSetValueString(IN HKEY hKey, IN LPCTSTR pszSubKey, IN LPCTSTR pszValueName, OUT LPCWSTR pszString) { DWORD cbSize = ((lstrlenW(pszString) + 1) * sizeof(pszString[0])); return HrSHSetValue(hKey, pszSubKey, pszValueName, REG_SZ, (BYTE *)pszString, cbSize); } HRESULT HrRegGetValueString(IN HKEY hKey, IN LPCTSTR pszSubKey, IN LPCTSTR pszValueName, IN LPWSTR pszString, IN DWORD cchSize) { DWORD dwType; DWORD cbSize = (cchSize * sizeof(pszString[0])); HRESULT hr = HrSHGetValue(hKey, pszSubKey, pszValueName, &dwType, (BYTE *)pszString, &cbSize); if (SUCCEEDED(hr) && (REG_SZ != dwType)) { hr = E_FAIL; } return hr; } HRESULT HrRegGetDWORD(IN HKEY hKey, IN LPCTSTR pszSubKey, OPTIONAL IN LPCTSTR pszValue, LPDWORD pdwValue, DWORD dwDefaultValue) { DWORD dwType; DWORD cbSize = sizeof(*pdwValue); HRESULT hr = HrSHGetValue(hKey, pszSubKey, pszValue, &dwType, (void *) pdwValue, &cbSize); if (FAILED(hr)) { *pdwValue = dwDefaultValue; hr = S_OK; } return hr; } HRESULT HrRegSetDWORD(IN HKEY hKey, IN LPCTSTR pszSubKey, OPTIONAL IN LPCTSTR pszValue, DWORD dwValue) { return HrSHSetValue(hKey, pszSubKey, pszValue, REG_DWORD, (void *) &dwValue, sizeof(dwValue)); } // UI Wrappers void SetCheckBox(HWND hwndDlg, UINT idControl, BOOL fChecked) { SendMessage((HWND)GetDlgItem(hwndDlg, idControl), BM_SETCHECK, (WPARAM)fChecked, 0); } BOOL GetCheckBox(HWND hwndDlg, UINT idControl) { return (BST_CHECKED == SendMessage((HWND)GetDlgItem(hwndDlg, idControl), BM_GETCHECK, 0, 0)); } HRESULT ShellFolderParsePath(LPCWSTR pszPath, LPITEMIDLIST * ppidl) { IShellFolder * psf; HRESULT hr = SHGetDesktopFolder(&psf); if (SUCCEEDED(hr)) { hr = psf->ParseDisplayName(NULL, NULL, (LPOLESTR) pszPath, NULL, ppidl, NULL); psf->Release(); } return hr; } HRESULT ShellFolderGetPath(LPCITEMIDLIST pidl, LPWSTR pszPath, DWORD cchSize) { IShellFolder * psf; HRESULT hr = SHGetDesktopFolder(&psf); if (SUCCEEDED(hr)) { IShellFolder * psfFolder; LPITEMIDLIST pidlParent = ILCloneParent(pidl); if (pidlParent) { hr = psf->BindToObject(pidlParent, NULL, IID_IShellFolder, (void **) &psfFolder); if (SUCCEEDED(hr)) { STRRET strRet = {0}; LPITEMIDLIST pidlLast = ILFindLastID(pidl); hr = psfFolder->GetDisplayNameOf(pidlLast, (SHGDN_NORMAL | SHGDN_FORPARSING), &strRet); if (SUCCEEDED(hr)) { hr = StrRetToBuf(&strRet, pidlLast, pszPath, cchSize); } psfFolder->Release(); } ILFree(pidlParent); } else { hr = E_OUTOFMEMORY; } psf->Release(); } return hr; } BOOL PathDeleteDirectoryRecursively(LPCTSTR pszDir) { BOOL fReturn = FALSE; HANDLE hFind; WIN32_FIND_DATA wfd; TCHAR szTemp[MAX_PATH]; StrCpyN(szTemp, pszDir, ARRAYSIZE(szTemp)); PathAppend(szTemp, TEXT("*.*")); hFind = FindFirstFile(szTemp, &wfd); if (INVALID_HANDLE_VALUE != hFind) { do { if (!PathIsDotOrDotDot(wfd.cFileName)) { // build the path of the directory or file found StrCpyN(szTemp, pszDir, ARRAYSIZE(szTemp)); PathAppend(szTemp, wfd.cFileName); if (FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes) { // We found a directory - call this function recursively // Note that since we use recursion, this can only go so far // before it blows the stack. If you plan on going into deep // directories, put szTemp above on the heap. fReturn = PathDeleteDirectoryRecursively(szTemp); } else { DeleteFile(szTemp); } } } while (FindNextFile(hFind, &wfd)); FindClose(hFind); } fReturn = RemoveDirectory(pszDir); return fReturn; } ULONGLONG PathGetFileSize(LPCTSTR pszPath) { ULONGLONG ullResult = 0; HANDLE hFile = CreateFile(pszPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != hFile) { LARGE_INTEGER liFileSize; if (GetFileSizeEx(hFile, &liFileSize)) { ullResult = liFileSize.QuadPart; } CloseHandle(hFile); } return ullResult; } void PrintLocation(LPTSTR pszTemplate, D3DXVECTOR3 vLoc, D3DXVECTOR3 vTangent) { TCHAR szOut[1024]; TCHAR szVector1[90]; TCHAR szVector2[90]; TCHAR szFloat1[20]; TCHAR szFloat2[20]; TCHAR szFloat3[20]; FloatToString(vLoc.x, 4, szFloat1, ARRAYSIZE(szFloat1)); FloatToString(vLoc.y, 4, szFloat2, ARRAYSIZE(szFloat2)); FloatToString(vLoc.z, 4, szFloat3, ARRAYSIZE(szFloat3)); wnsprintf(szVector1, ARRAYSIZE(szVector1), TEXT("<%s, %s, %s>"), szFloat1, szFloat2, szFloat3); FloatToString(vTangent.x, 4, szFloat1, ARRAYSIZE(szFloat1)); FloatToString(vTangent.y, 4, szFloat2, ARRAYSIZE(szFloat2)); FloatToString(vTangent.z, 4, szFloat3, ARRAYSIZE(szFloat3)); wnsprintf(szVector2, ARRAYSIZE(szVector2), TEXT("<%s, %s, %s>\n"), szFloat1, szFloat2, szFloat3); wnsprintf(szOut, ARRAYSIZE(szOut), pszTemplate, szVector1, szVector2); DXUtil_Trace(szOut); } //----------------------------------------------------------------------------- // Name: UpdateCullInfo() // Desc: Sets up the frustum planes, endpoints, and center for the frustum // defined by a given view matrix and projection matrix. This info will // be used when culling each object in CullObject(). //----------------------------------------------------------------------------- VOID UpdateCullInfo( CULLINFO* pCullInfo, D3DXMATRIX* pMatView, D3DXMATRIX* pMatProj ) { D3DXMATRIX mat; D3DXMatrixMultiply( &mat, pMatView, pMatProj ); D3DXMatrixInverse( &mat, NULL, &mat ); pCullInfo->vecFrustum[0] = D3DXVECTOR3(-1.0f, -1.0f, 0.0f); // xyz pCullInfo->vecFrustum[1] = D3DXVECTOR3( 1.0f, -1.0f, 0.0f); // Xyz pCullInfo->vecFrustum[2] = D3DXVECTOR3(-1.0f, 1.0f, 0.0f); // xYz pCullInfo->vecFrustum[3] = D3DXVECTOR3( 1.0f, 1.0f, 0.0f); // XYz pCullInfo->vecFrustum[4] = D3DXVECTOR3(-1.0f, -1.0f, 1.0f); // xyZ pCullInfo->vecFrustum[5] = D3DXVECTOR3( 1.0f, -1.0f, 1.0f); // XyZ pCullInfo->vecFrustum[6] = D3DXVECTOR3(-1.0f, 1.0f, 1.0f); // xYZ pCullInfo->vecFrustum[7] = D3DXVECTOR3( 1.0f, 1.0f, 1.0f); // XYZ pCullInfo->vecFrustumCenter = D3DXVECTOR3(0, 0, 0); for( INT i = 0; i < 8; i++ ) { D3DXVec3TransformCoord( &pCullInfo->vecFrustum[i], &pCullInfo->vecFrustum[i], &mat ); pCullInfo->vecFrustumCenter += pCullInfo->vecFrustum[i]; } pCullInfo->vecFrustumCenter /= 8; D3DXPlaneFromPoints( &pCullInfo->planeFrustum[0], &pCullInfo->vecFrustum[0], &pCullInfo->vecFrustum[1], &pCullInfo->vecFrustum[2] ); // Near D3DXPlaneFromPoints( &pCullInfo->planeFrustum[1], &pCullInfo->vecFrustum[6], &pCullInfo->vecFrustum[7], &pCullInfo->vecFrustum[5] ); // Far D3DXPlaneFromPoints( &pCullInfo->planeFrustum[2], &pCullInfo->vecFrustum[2], &pCullInfo->vecFrustum[6], &pCullInfo->vecFrustum[4] ); // Left D3DXPlaneFromPoints( &pCullInfo->planeFrustum[3], &pCullInfo->vecFrustum[7], &pCullInfo->vecFrustum[3], &pCullInfo->vecFrustum[5] ); // Right D3DXPlaneFromPoints( &pCullInfo->planeFrustum[4], &pCullInfo->vecFrustum[2], &pCullInfo->vecFrustum[3], &pCullInfo->vecFrustum[6] ); // Top D3DXPlaneFromPoints( &pCullInfo->planeFrustum[5], &pCullInfo->vecFrustum[1], &pCullInfo->vecFrustum[0], &pCullInfo->vecFrustum[4] ); // Bottom } //----------------------------------------------------------------------------- // Name: CullObject() // Desc: Determine the cullstate for an object. //----------------------------------------------------------------------------- CULLSTATE CullObject( CULLINFO* pCullInfo, D3DXVECTOR3* pVecBounds, D3DXPLANE* pPlaneBounds ) { BYTE bOutside[8]; ZeroMemory( &bOutside, sizeof(bOutside) ); // Check boundary vertices against all 6 frustum planes, // and store result (1 if outside) in a bitfield for( int iPoint = 0; iPoint < 8; iPoint++ ) { for( int iPlane = 0; iPlane < 6; iPlane++ ) { if( pCullInfo->planeFrustum[iPlane].a * pVecBounds[iPoint].x + pCullInfo->planeFrustum[iPlane].b * pVecBounds[iPoint].y + pCullInfo->planeFrustum[iPlane].c * pVecBounds[iPoint].z + pCullInfo->planeFrustum[iPlane].d < 0) { bOutside[iPoint] |= (1 << iPlane); } } // If any point is inside all 6 frustum planes, it is inside // the frustum, so the object must be rendered. if( bOutside[iPoint] == 0 ) return CS_INSIDE; } // If all points are outside any single frustum plane, the object is // outside the frustum if( (bOutside[0] & bOutside[1] & bOutside[2] & bOutside[3] & bOutside[4] & bOutside[5] & bOutside[6] & bOutside[7]) != 0 ) { return CS_OUTSIDE; } // Now see if any of the frustum edges penetrate any of the faces of // the bounding box D3DXVECTOR3 edge[12][2] = { pCullInfo->vecFrustum[0], pCullInfo->vecFrustum[1], // front bottom pCullInfo->vecFrustum[2], pCullInfo->vecFrustum[3], // front top pCullInfo->vecFrustum[0], pCullInfo->vecFrustum[2], // front left pCullInfo->vecFrustum[1], pCullInfo->vecFrustum[3], // front right pCullInfo->vecFrustum[4], pCullInfo->vecFrustum[5], // back bottom pCullInfo->vecFrustum[6], pCullInfo->vecFrustum[7], // back top pCullInfo->vecFrustum[4], pCullInfo->vecFrustum[6], // back left pCullInfo->vecFrustum[5], pCullInfo->vecFrustum[7], // back right pCullInfo->vecFrustum[0], pCullInfo->vecFrustum[4], // left bottom pCullInfo->vecFrustum[2], pCullInfo->vecFrustum[6], // left top pCullInfo->vecFrustum[1], pCullInfo->vecFrustum[5], // right bottom pCullInfo->vecFrustum[3], pCullInfo->vecFrustum[7], // right top }; D3DXVECTOR3 face[6][4] = { pVecBounds[0], pVecBounds[2], pVecBounds[3], pVecBounds[1], // front pVecBounds[4], pVecBounds[5], pVecBounds[7], pVecBounds[6], // back pVecBounds[0], pVecBounds[4], pVecBounds[6], pVecBounds[2], // left pVecBounds[1], pVecBounds[3], pVecBounds[7], pVecBounds[5], // right pVecBounds[2], pVecBounds[6], pVecBounds[7], pVecBounds[3], // top pVecBounds[0], pVecBounds[4], pVecBounds[5], pVecBounds[1], // bottom }; D3DXVECTOR3* pEdge; D3DXVECTOR3* pFace; pEdge = &edge[0][0]; for( INT iEdge = 0; iEdge < 12; iEdge++ ) { pFace = &face[0][0]; for( INT iFace = 0; iFace < 6; iFace++ ) { if( EdgeIntersectsFace( pEdge, pFace, &pPlaneBounds[iFace] ) ) { return CS_INSIDE_SLOW; } pFace += 4; } pEdge += 2; } // Now see if frustum is contained in bounding box // If the frustum center is outside any plane of the bounding box, // the frustum is not contained in the bounding box, so the object // is outside the frustum for( INT iPlane = 0; iPlane < 6; iPlane++ ) { if( pPlaneBounds[iPlane].a * pCullInfo->vecFrustumCenter.x + pPlaneBounds[iPlane].b * pCullInfo->vecFrustumCenter.y + pPlaneBounds[iPlane].c * pCullInfo->vecFrustumCenter.z + pPlaneBounds[iPlane].d < 0 ) { return CS_OUTSIDE_SLOW; } } // Bounding box must contain the frustum, so render the object return CS_INSIDE_SLOW; } //----------------------------------------------------------------------------- // Name: EdgeIntersectsFace() // Desc: Determine if the edge bounded by the two vectors in pEdges intersects // the quadrilateral described by the four vectors in pFacePoints. // Note: pPlanePoints could be derived from pFacePoints using // D3DXPlaneFromPoints, but it is precomputed in advance for greater // speed. //----------------------------------------------------------------------------- BOOL EdgeIntersectsFace( D3DXVECTOR3* pEdges, D3DXVECTOR3* pFacePoints, D3DXPLANE* pPlane ) { // If both edge points are on the same side of the plane, the edge does // not intersect the face FLOAT fDist1; FLOAT fDist2; fDist1 = pPlane->a * pEdges[0].x + pPlane->b * pEdges[0].y + pPlane->c * pEdges[0].z + pPlane->d; fDist2 = pPlane->a * pEdges[1].x + pPlane->b * pEdges[1].y + pPlane->c * pEdges[1].z + pPlane->d; if( fDist1 > 0 && fDist2 > 0 || fDist1 < 0 && fDist2 < 0 ) { return FALSE; } // Find point of intersection between edge and face plane (if they're // parallel, edge does not intersect face and D3DXPlaneIntersectLine // returns NULL) D3DXVECTOR3 ptIntersection; if( NULL == D3DXPlaneIntersectLine( &ptIntersection, pPlane, &pEdges[0], &pEdges[1] ) ) return FALSE; // Project onto a 2D plane to make the pt-in-poly test easier FLOAT fAbsA = (pPlane->a > 0 ? pPlane->a : -pPlane->a); FLOAT fAbsB = (pPlane->b > 0 ? pPlane->b : -pPlane->b); FLOAT fAbsC = (pPlane->c > 0 ? pPlane->c : -pPlane->c); D3DXVECTOR2 facePoints[4]; D3DXVECTOR2 point; if( fAbsA > fAbsB && fAbsA > fAbsC ) { // Plane is mainly pointing along X axis, so use Y and Z for( INT i = 0; i < 4; i++) { facePoints[i].x = pFacePoints[i].y; facePoints[i].y = pFacePoints[i].z; } point.x = ptIntersection.y; point.y = ptIntersection.z; } else if( fAbsB > fAbsA && fAbsB > fAbsC ) { // Plane is mainly pointing along Y axis, so use X and Z for( INT i = 0; i < 4; i++) { facePoints[i].x = pFacePoints[i].x; facePoints[i].y = pFacePoints[i].z; } point.x = ptIntersection.x; point.y = ptIntersection.z; } else { // Plane is mainly pointing along Z axis, so use X and Y for( INT i = 0; i < 4; i++) { facePoints[i].x = pFacePoints[i].x; facePoints[i].y = pFacePoints[i].y; } point.x = ptIntersection.x; point.y = ptIntersection.y; } // If point is on the outside of any of the face edges, it is // outside the face. // We can do this by taking the determinant of the following matrix: // | x0 y0 1 | // | x1 y1 1 | // | x2 y2 1 | // where (x0,y0) and (x1,y1) are points on the face edge and (x2,y2) // is our test point. If this value is positive, the test point is // "to the left" of the line. To determine whether a point needs to // be "to the right" or "to the left" of the four lines to qualify as // inside the face, we need to see if the faces are specified in // clockwise or counter-clockwise order (it could be either, since the // edge could be penetrating from either side). To determine this, we // do the same test to see if the third point is "to the right" or // "to the left" of the line formed by the first two points. // See http://forum.swarthmore.edu/dr.math/problems/scott5.31.96.html FLOAT x0, x1, x2, y0, y1, y2; x0 = facePoints[0].x; y0 = facePoints[0].y; x1 = facePoints[1].x; y1 = facePoints[1].y; x2 = facePoints[2].x; y2 = facePoints[2].y; BOOL bClockwise = FALSE; if( x1*y2 - y1*x2 - x0*y2 + y0*x2 + x0*y1 - y0*x1 < 0 ) bClockwise = TRUE; x2 = point.x; y2 = point.y; for( INT i = 0; i < 4; i++ ) { x0 = facePoints[i].x; y0 = facePoints[i].y; if( i < 3 ) { x1 = facePoints[i+1].x; y1 = facePoints[i+1].y; } else { x1 = facePoints[0].x; y1 = facePoints[0].y; } if( ( x1*y2 - y1*x2 - x0*y2 + y0*x2 + x0*y1 - y0*x1 > 0 ) == bClockwise ) return FALSE; } // If we get here, the point is inside all four face edges, // so it's inside the face. return TRUE; } BOOL Is3DRectViewable(CULLINFO* pCullInfo, D3DXMATRIX* pMatWorld, D3DXVECTOR3 vecMin, D3DXVECTOR3 vecMax) { BOOL fViewable = TRUE; D3DXVECTOR3 vecBoundsLocal[8]; D3DXVECTOR3 vecBoundsWorld[8]; D3DXPLANE planeBoundsWorld[6]; CULLSTATE cs; vecBoundsLocal[0] = D3DXVECTOR3( vecMin.x, vecMin.y, vecMin.z ); // xyz vecBoundsLocal[1] = D3DXVECTOR3( vecMax.x, vecMin.y, vecMin.z ); // Xyz vecBoundsLocal[2] = D3DXVECTOR3( vecMin.x, vecMax.y, vecMin.z ); // xYz vecBoundsLocal[3] = D3DXVECTOR3( vecMax.x, vecMax.y, vecMin.z ); // XYz vecBoundsLocal[4] = D3DXVECTOR3( vecMin.x, vecMin.y, vecMax.z ); // xyZ vecBoundsLocal[5] = D3DXVECTOR3( vecMax.x, vecMin.y, vecMax.z ); // XyZ vecBoundsLocal[6] = D3DXVECTOR3( vecMin.x, vecMax.y, vecMax.z ); // xYZ vecBoundsLocal[7] = D3DXVECTOR3( vecMax.x, vecMax.y, vecMax.z ); // XYZ for( int i = 0; i < 8; i++ ) { D3DXVec3TransformCoord( &vecBoundsWorld[i], &vecBoundsLocal[i], pMatWorld ); } // Determine planes of bounding box coords D3DXPlaneFromPoints( &planeBoundsWorld[0], &vecBoundsWorld[0], &vecBoundsWorld[1], &vecBoundsWorld[2] ); // Near D3DXPlaneFromPoints( &planeBoundsWorld[1], &vecBoundsWorld[6], &vecBoundsWorld[7], &vecBoundsWorld[5] ); // Far D3DXPlaneFromPoints( &planeBoundsWorld[2], &vecBoundsWorld[2], &vecBoundsWorld[6], &vecBoundsWorld[4] ); // Left D3DXPlaneFromPoints( &planeBoundsWorld[3], &vecBoundsWorld[7], &vecBoundsWorld[3], &vecBoundsWorld[5] ); // Right D3DXPlaneFromPoints( &planeBoundsWorld[4], &vecBoundsWorld[2], &vecBoundsWorld[3], &vecBoundsWorld[6] ); // Top D3DXPlaneFromPoints( &planeBoundsWorld[5], &vecBoundsWorld[1], &vecBoundsWorld[0], &vecBoundsWorld[4] ); // Bottom cs = CullObject( pCullInfo, vecBoundsWorld, planeBoundsWorld ); fViewable = (cs != CS_OUTSIDE && cs != CS_OUTSIDE_SLOW); return fViewable; } HRESULT GetCurrentUserCustomName(LPWSTR pszDisplayName, DWORD cchSize) { HRESULT hr = S_OK; ULONG cchUserSize = cchSize; if (GetUserNameEx(NameDisplay, pszDisplayName, &cchUserSize)) { // It succeeded, so use it. } else { // It failed, so load "My". It's better than nothing. LoadString(HINST_THISDLL, IDS_LOBBY_TITLE, pszDisplayName, cchSize); } return hr; } D3DXVECTOR3 D3DXVec3Multiply(CONST D3DXVECTOR3 v1, CONST D3DXVECTOR3 v2) { D3DXVECTOR3 vResults; vResults.x = (v1.x * v2.x); vResults.y = (v1.y * v2.y); vResults.z = (v1.z * v2.z); return vResults; } void FloatToString(float fValue, int nDecimalDigits, LPTSTR pszString, DWORD cchSize) { int nIntValue = (int) fValue; float fDecimalValue = (float)((fValue - (float)nIntValue) * (pow(10, nDecimalDigits))); int nDecimalValue = (int) fDecimalValue; if (0 == nDecimalDigits) { wnsprintf(pszString, cchSize, TEXT("%d"), nIntValue); } else { wnsprintf(pszString, cchSize, TEXT("%d.%d"), nIntValue, nDecimalValue); } } /////// // Critical section helper stuff // #ifdef DEBUG UINT g_CriticalSectionCount = 0; DWORD g_CriticalSectionOwner = 0; #ifdef STACKBACKTRACE DBstkback g_CriticalSectionLastCall[4] = { 0 }; #endif void Dll_EnterCriticalSection(CRITICAL_SECTION * pcsDll) { #ifdef STACKBACKTRACE int var0; // *must* be 1st on frame #endif EnterCriticalSection(pcsDll); if (g_CriticalSectionCount++ == 0) { g_CriticalSectionOwner = GetCurrentThreadId(); #ifdef STACKBACKTRACE int fp = (int) (1 + (int *)&var0); DBGetStackBack(&fp, g_CriticalSectionLastCall, ARRAYSIZE(g_CriticalSectionLastCall)); #endif } } void Dll_LeaveCriticalSection(CRITICAL_SECTION * pcsDll) { if (--g_CriticalSectionCount == 0) g_CriticalSectionOwner = 0; LeaveCriticalSection(pcsDll); } #endif #include #include #include #include #include