339 lines
10 KiB
C++
339 lines
10 KiB
C++
// DXHELP3.cpp : Contains routines shared by multiple 3D effects
|
|
#include "dxhelp3.h"
|
|
#include <malloc.h>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
|
|
void Rotate::Set(D3DVECTOR d3dvctrNormal, double dAngle)
|
|
{
|
|
#ifdef _DEBUG
|
|
float NormalSum = d3dvctrNormal.x * d3dvctrNormal.x +
|
|
d3dvctrNormal.y * d3dvctrNormal.y +
|
|
d3dvctrNormal.z * d3dvctrNormal.z;
|
|
_ASSERT(NormalSum == 0.0f || (0.99f < NormalSum && NormalSum < 1.01f));
|
|
#endif
|
|
|
|
// The following transformation matrix routines are from
|
|
// Graphics Gems (the first one) page 466 (Converting
|
|
// between Matrix and Axis-Amount Representations)
|
|
float s = (float)sin(dAngle), c = (float)cos(dAngle);
|
|
float t = 1.0f - c;
|
|
|
|
m_d3dvctrXComponent.x = t * d3dvctrNormal.x * d3dvctrNormal.x + c;
|
|
m_d3dvctrXComponent.y = t * d3dvctrNormal.x * d3dvctrNormal.y - s * d3dvctrNormal.z;
|
|
m_d3dvctrXComponent.z = t * d3dvctrNormal.x * d3dvctrNormal.z + s * d3dvctrNormal.y;
|
|
|
|
m_d3dvctrYComponent.x = t * d3dvctrNormal.x * d3dvctrNormal.y + s * d3dvctrNormal.z;
|
|
m_d3dvctrYComponent.y = t * d3dvctrNormal.y * d3dvctrNormal.y + c;
|
|
m_d3dvctrYComponent.z = t * d3dvctrNormal.y * d3dvctrNormal.z - s * d3dvctrNormal.x;
|
|
|
|
m_d3dvctrZComponent.x = t * d3dvctrNormal.x * d3dvctrNormal.z - s * d3dvctrNormal.y;
|
|
m_d3dvctrZComponent.y = t * d3dvctrNormal.y * d3dvctrNormal.z + s * d3dvctrNormal.x;
|
|
m_d3dvctrZComponent.z = t * d3dvctrNormal.z * d3dvctrNormal.z + c;
|
|
}
|
|
|
|
static HRESULT DecoupleOneMeshBuilder(void *lpThis /* Ignored */,
|
|
IDirect3DRMMeshBuilder3 *lpMeshBuilderOut,
|
|
IDirect3DRMMeshBuilder3 *lpMeshBuilderIn)
|
|
{
|
|
HRESULT hr = lpMeshBuilderOut->SetAppData(lpMeshBuilderIn->GetAppData());
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
const int ciOutputFaceCount = lpMeshBuilderOut->GetFaceCount();
|
|
const int ciMaxFaceCount = lpMeshBuilderIn->GetFaceCount();
|
|
if(!ciMaxFaceCount)
|
|
{
|
|
return hr;
|
|
}
|
|
CComPtr<IDirect3DRMFaceArray> cpD3DRMFaceArray;
|
|
|
|
hr = lpMeshBuilderIn->GetFaces(&cpD3DRMFaceArray);
|
|
if(hr != D3DRM_OK)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
D3DVECTOR *lpvctrPosition = NULL;
|
|
D3DVECTOR *lpvctrFaceNormals = NULL;
|
|
DWORD dwMaxVertexCount = 0;
|
|
|
|
// By reserving space we speed things up by a factor of 20 or 30 X!
|
|
|
|
DWORD dwTotalVertexCount = lpMeshBuilderIn->GetVertexCount();
|
|
_ASSERT(dwTotalVertexCount >= 3);
|
|
if (dwTotalVertexCount/ciMaxFaceCount < 3)
|
|
{
|
|
dwTotalVertexCount = ciMaxFaceCount * 3; // There will be at least 3 vertices per face.
|
|
}
|
|
hr = lpMeshBuilderOut->ReserveSpace(dwTotalVertexCount, dwTotalVertexCount, ciMaxFaceCount);
|
|
|
|
if(hr != D3DRM_OK)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
// Need to have seperate vertices for each face in the output mesh.
|
|
int iFaceIndex = 0;
|
|
do
|
|
{
|
|
CComPtr<IDirect3DRMFace> cpd3dInFaceTemp;
|
|
CComPtr<IDirect3DRMFace2> cpd3dOutFace;
|
|
|
|
if(FAILED(hr = cpD3DRMFaceArray->GetElement((DWORD)iFaceIndex, &cpd3dInFaceTemp)))
|
|
{
|
|
break;
|
|
}
|
|
_ASSERT(cpd3dInFaceTemp);
|
|
|
|
CComPtr<IDirect3DRMFace2> cpd3dInFace;
|
|
if(FAILED(hr = cpd3dInFaceTemp->QueryInterface(
|
|
IID_IDirect3DRMFace2, (void **)&cpd3dInFace)))
|
|
{
|
|
break;
|
|
}
|
|
|
|
DWORD dwVertexCount;
|
|
|
|
cpd3dInFace->GetVertices(&dwVertexCount, NULL, NULL);
|
|
_ASSERT(dwVertexCount >= 3);
|
|
|
|
if(dwVertexCount > dwMaxVertexCount)
|
|
{
|
|
dwMaxVertexCount = dwVertexCount;
|
|
|
|
D3DVECTOR *lpTemp = lpvctrPosition;
|
|
D3DVECTOR *lpNormalTemp = lpvctrFaceNormals;
|
|
|
|
lpvctrPosition = (D3DVECTOR *)realloc(lpvctrPosition, dwMaxVertexCount * sizeof (*lpvctrPosition));
|
|
lpvctrFaceNormals = (D3DVECTOR *)realloc(lpvctrFaceNormals, dwMaxVertexCount * sizeof (*lpvctrFaceNormals));
|
|
|
|
if(!lpvctrPosition || !lpvctrFaceNormals)
|
|
{
|
|
free(lpTemp);
|
|
free(lpNormalTemp);
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
// We may have a problem in the amount of space reserved in the output meshbuilder.
|
|
if((ciMaxFaceCount - iFaceIndex) * dwMaxVertexCount > dwTotalVertexCount)
|
|
{
|
|
dwTotalVertexCount = (ciMaxFaceCount - iFaceIndex) * dwMaxVertexCount;
|
|
hr = lpMeshBuilderOut->ReserveSpace(dwTotalVertexCount, dwTotalVertexCount, ciMaxFaceCount - iFaceIndex);
|
|
|
|
if(hr != D3DRM_OK)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(FAILED(hr = cpd3dInFace->GetVertices(&dwVertexCount, lpvctrPosition, lpvctrFaceNormals)) ||
|
|
FAILED(hr = lpMeshBuilderOut->CreateFace(&cpd3dOutFace)) ||
|
|
FAILED(hr = cpd3dOutFace->SetAppData(cpd3dInFace->GetAppData())))
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
CComPtr<IDirect3DRMMaterial2> cpMaterial;
|
|
CComPtr<IDirect3DRMTexture3> cpTexture;
|
|
BOOL bU, bV;
|
|
|
|
if(hr != D3DRM_OK ||
|
|
(hr = cpd3dInFace->GetMaterial(&cpMaterial)) != D3DRM_OK ||
|
|
(hr = cpd3dOutFace->SetMaterial(cpMaterial)) != D3DRM_OK ||
|
|
(hr = cpd3dOutFace->SetColor(cpd3dInFace->GetColor())) != D3DRM_OK ||
|
|
(hr = cpd3dInFace->GetTexture(&cpTexture)) != D3DRM_OK ||
|
|
(hr = cpd3dOutFace->SetTexture(cpTexture)) != D3DRM_OK ||
|
|
(hr = cpd3dInFace->GetTextureTopology(&bU, &bV)) != D3DRM_OK ||
|
|
(hr = cpd3dOutFace->SetTextureTopology(bU, bV)) != D3DRM_OK)
|
|
{
|
|
break;
|
|
}
|
|
|
|
DWORD dwInFaceVertex = 0;
|
|
do
|
|
{
|
|
int iVIndex = lpMeshBuilderOut->AddVertex(lpvctrPosition[dwInFaceVertex].x,
|
|
lpvctrPosition[dwInFaceVertex].y,
|
|
lpvctrPosition[dwInFaceVertex].z);
|
|
int iNIndex = lpMeshBuilderOut->AddNormal(lpvctrFaceNormals[dwInFaceVertex].x,
|
|
lpvctrFaceNormals[dwInFaceVertex].y,
|
|
lpvctrFaceNormals[dwInFaceVertex].z);
|
|
|
|
D3DVALUE U, V;
|
|
|
|
if(FAILED(hr = cpd3dOutFace->AddVertexAndNormalIndexed(iVIndex, iNIndex)) ||
|
|
FAILED(hr = cpd3dInFace->GetTextureCoordinates(dwInFaceVertex, &U, &V)) ||
|
|
FAILED(hr = cpd3dOutFace->SetTextureCoordinates(dwInFaceVertex, U, V)))
|
|
{
|
|
break;
|
|
}
|
|
} while (++dwInFaceVertex < dwVertexCount);
|
|
dwTotalVertexCount -= dwVertexCount;
|
|
} while (hr == D3DRM_OK && ++iFaceIndex < ciMaxFaceCount);
|
|
|
|
free(lpvctrPosition);
|
|
free(lpvctrFaceNormals);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT TraverseSubMeshes( HRESULT (*lpCallBack)(void *lpThis,
|
|
IDirect3DRMMeshBuilder3* lpOut,
|
|
IDirect3DRMMeshBuilder3* lpIn),
|
|
void *lpThis,
|
|
IDirect3DRMMeshBuilder3* lpMeshBuilderOut,
|
|
IDirect3DRMMeshBuilder3* lpMeshBuilderIn)
|
|
{
|
|
HRESULT hr;
|
|
|
|
_ASSERT(lpCallBack);
|
|
if(FAILED(hr = (*lpCallBack)(lpThis, lpMeshBuilderOut, lpMeshBuilderIn)))
|
|
return hr;
|
|
|
|
DWORD dwInSubMeshCount;
|
|
hr = lpMeshBuilderIn->GetSubMeshes(&dwInSubMeshCount, NULL);
|
|
|
|
if(FAILED(hr) || dwInSubMeshCount == 0)
|
|
return hr;
|
|
|
|
DWORD dwOutSubMeshCount;
|
|
if(FAILED(hr = lpMeshBuilderOut->GetSubMeshes(&dwOutSubMeshCount, NULL)))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
const BOOL bCreateOutMeshes = (dwOutSubMeshCount == 0);
|
|
_ASSERT(bCreateOutMeshes || dwInSubMeshCount == dwOutSubMeshCount);
|
|
|
|
LPUNKNOWN *lplpunkInSubMeshes =
|
|
(LPUNKNOWN *)malloc(dwInSubMeshCount * sizeof(*lplpunkInSubMeshes));
|
|
|
|
LPUNKNOWN *lplpunkOutSubMeshes = (bCreateOutMeshes? NULL:
|
|
(LPUNKNOWN *)malloc(dwOutSubMeshCount * sizeof(*lplpunkOutSubMeshes)));
|
|
|
|
if(!lplpunkInSubMeshes || !bCreateOutMeshes && !lplpunkOutSubMeshes)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if(FAILED(hr = lpMeshBuilderIn->GetSubMeshes(&dwInSubMeshCount, lplpunkInSubMeshes)) ||
|
|
!bCreateOutMeshes &&
|
|
FAILED(hr = lpMeshBuilderOut->GetSubMeshes(&dwOutSubMeshCount, lplpunkOutSubMeshes)))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
CComPtr<IDirect3DRMMeshBuilder3> cpInSubMesh, cpOutSubMesh;
|
|
|
|
DWORD dwSubMesh;
|
|
for(dwSubMesh = 0; SUCCEEDED(hr) && dwSubMesh < dwInSubMeshCount; dwSubMesh++)
|
|
{
|
|
cpInSubMesh = NULL;
|
|
cpOutSubMesh = NULL;
|
|
|
|
// Get the current input submesh.
|
|
hr = lplpunkInSubMeshes[dwSubMesh]->QueryInterface(IID_IDirect3DRMMeshBuilder3,
|
|
(void **)&cpInSubMesh);
|
|
|
|
if(FAILED(hr))
|
|
break;
|
|
|
|
if(bCreateOutMeshes)
|
|
{
|
|
// Create a new submesh in the output mesh to match the input submesh.
|
|
LPUNKNOWN lpunkSubmesh;
|
|
|
|
if(FAILED(hr = lpMeshBuilderOut->CreateSubMesh(&lpunkSubmesh)))
|
|
break;
|
|
|
|
hr = lpunkSubmesh->QueryInterface(IID_IDirect3DRMMeshBuilder3,
|
|
(void **)&cpOutSubMesh);
|
|
lpunkSubmesh->Release();
|
|
}
|
|
else
|
|
{
|
|
// Get the current output submesh.
|
|
hr = lplpunkOutSubMeshes[dwSubMesh]->QueryInterface(IID_IDirect3DRMMeshBuilder3,
|
|
(void **)&cpOutSubMesh);
|
|
}
|
|
if(FAILED(hr))
|
|
break;
|
|
|
|
// Do all the children for these two MeshBuilders.
|
|
hr = TraverseSubMeshes(lpCallBack, lpThis, cpOutSubMesh, cpInSubMesh);
|
|
}
|
|
|
|
for(dwSubMesh = 0; dwSubMesh < dwInSubMeshCount; dwSubMesh++)
|
|
{
|
|
lplpunkInSubMeshes[dwSubMesh]->Release();
|
|
|
|
if(lplpunkOutSubMeshes)
|
|
{
|
|
lplpunkOutSubMeshes[dwSubMesh]->Release();
|
|
}
|
|
}
|
|
|
|
free(lplpunkInSubMeshes);
|
|
free(lplpunkOutSubMeshes);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT DecoupleVertices(IDirect3DRMMeshBuilder3* lpMeshBuilderOut,
|
|
IDirect3DRMMeshBuilder3* lpMeshBuilderIn)
|
|
{
|
|
DWORD dwSubMeshCount;
|
|
|
|
HRESULT hr = lpMeshBuilderOut->GetSubMeshes(&dwSubMeshCount, NULL);
|
|
|
|
if(FAILED(hr))
|
|
return hr;
|
|
|
|
if(lpMeshBuilderOut->GetFaceCount() || dwSubMeshCount)
|
|
{
|
|
if(FAILED(hr = lpMeshBuilderOut->Empty(0)))
|
|
return hr;
|
|
}
|
|
hr = TraverseSubMeshes(DecoupleOneMeshBuilder, NULL,
|
|
lpMeshBuilderOut, lpMeshBuilderIn);
|
|
return hr;
|
|
}
|
|
|
|
float GetDlgItemFloat(HWND hDlg, int id)
|
|
{
|
|
TCHAR *pEnd;
|
|
TCHAR szItemText[20];
|
|
GetDlgItemText(hDlg, id, szItemText, 20);
|
|
return (float)strtod(szItemText, &pEnd);
|
|
}
|
|
|
|
BOOL SetDlgItemFloat( HWND hDlg, int id, float f )
|
|
{
|
|
TCHAR szItem[20];
|
|
_stprintf( szItem, _T("%.2f"), f );
|
|
return SetDlgItemText( hDlg, id, szItem );
|
|
}
|
|
|
|
double GetDlgItemDouble(HWND hDlg, int id)
|
|
{
|
|
TCHAR *pEnd;
|
|
TCHAR szItemText[20];
|
|
GetDlgItemText(hDlg, id, szItemText, 20);
|
|
return strtod(szItemText, &pEnd);
|
|
}
|
|
|
|
BOOL SetDlgItemDouble( HWND hDlg, int id, double d )
|
|
{
|
|
TCHAR szItem[20];
|
|
_stprintf( szItem, _T("%.2d"), d );
|
|
return SetDlgItemText( hDlg, id, szItem );
|
|
}
|
|
|