547 lines
21 KiB
C++
547 lines
21 KiB
C++
|
/*============================================================================
|
||
|
*
|
||
|
* Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
|
||
|
*
|
||
|
* File: npatch.cpp
|
||
|
* Content: Implementation for N-Patches
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
#include "pch.cpp"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// RefDev::ProcessTessPrimitive
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT
|
||
|
RefDev::ProcessTessPrimitive( LPD3DHAL_DP2DRAWPRIMITIVE pDP )
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
if( RDVSD_ISLEGACY( m_CurrentVShaderHandle ) )
|
||
|
{
|
||
|
//
|
||
|
// The legacy FVF style: The Zero'th Stream is implied
|
||
|
//
|
||
|
DWORD dwFVF = m_CurrentVShaderHandle;
|
||
|
RDVStream& Stream = m_VStream[0];
|
||
|
DWORD dwStride = Stream.m_dwStride;
|
||
|
DWORD dwFVFSize = GetFVFVertexSize( dwFVF );
|
||
|
|
||
|
if( Stream.m_pData == NULL || dwStride == 0 )
|
||
|
{
|
||
|
DPFERR( "Zero'th stream doesnt have valid VB set" );
|
||
|
return DDERR_INVALIDPARAMS;
|
||
|
}
|
||
|
if( dwStride < dwFVFSize )
|
||
|
{
|
||
|
DPFERR( "The stride set for the vertex stream is less than"
|
||
|
" the FVF vertex size" );
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BYTE *pVerts = 0, *pNorms = 0;
|
||
|
unsigned vstride, nstride;
|
||
|
|
||
|
// Figure out where the positions and normals are
|
||
|
RDVDeclaration &Decl = m_pCurrentVShader->m_Declaration;
|
||
|
for(unsigned e = 0; e < Decl.m_dwNumElements; ++e)
|
||
|
{
|
||
|
RDVElement &velem = Decl.m_VertexElements[e];
|
||
|
if(velem.m_dwRegister == D3DVSDE_POSITION) // Position
|
||
|
{
|
||
|
RDVStream &vstream = m_VStream[velem.m_dwStreamIndex];
|
||
|
pVerts = vstream.m_pSavedData + pDP->VStart * vstream.m_dwStride + velem.m_dwOffset;
|
||
|
vstride = vstream.m_dwStride;
|
||
|
}
|
||
|
else if(velem.m_dwRegister == D3DVSDE_NORMAL) // Normal
|
||
|
{
|
||
|
RDVStream &vstream = m_VStream[velem.m_dwStreamIndex];
|
||
|
pNorms = vstream.m_pSavedData + pDP->VStart * vstream.m_dwStride + velem.m_dwOffset;
|
||
|
nstride = vstream.m_dwStride;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(pVerts == 0 || pNorms == 0)
|
||
|
{
|
||
|
DPFERR("This tessellation scheme needs positions and normals explicitely specified");
|
||
|
return DDERR_INVALIDPARAMS;
|
||
|
}
|
||
|
|
||
|
switch(pDP->primType)
|
||
|
{
|
||
|
case D3DPT_TRIANGLELIST:
|
||
|
{
|
||
|
for(unsigned i = 0; i < pDP->PrimitiveCount; ++i)
|
||
|
{
|
||
|
FLOAT *pV[3], *pN[3];
|
||
|
unsigned iM[3], iN[3];
|
||
|
|
||
|
pV[0] = (FLOAT*)(pVerts + i * 3 * vstride);
|
||
|
pV[1] = (FLOAT*)(pVerts + (i * 3 + 1) * vstride);
|
||
|
pV[2] = (FLOAT*)(pVerts + (i * 3 + 2) * vstride);
|
||
|
pN[0] = (FLOAT*)(pNorms + i * 3 * nstride);
|
||
|
pN[1] = (FLOAT*)(pNorms + (i * 3 + 1) * nstride);
|
||
|
pN[2] = (FLOAT*)(pNorms + (i * 3 + 2) * nstride);
|
||
|
iM[0] = pDP->VStart + i * 3; iN[0] = 0;
|
||
|
iM[1] = pDP->VStart + i * 3 + 1; iN[1] = 0;
|
||
|
iM[2] = pDP->VStart + i * 3 + 2; iN[2] = 0;
|
||
|
|
||
|
RDNPatch patch(pV, pN, GetRS()[D3DRS_POSITIONORDER], GetRS()[D3DRS_NORMALORDER]);
|
||
|
|
||
|
hr = DrawNPatch(patch, 0, iM, iN, unsigned(GetRSf()[D3DRS_PATCHSEGMENTS]));
|
||
|
if(FAILED(hr))
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case D3DPT_TRIANGLEFAN:
|
||
|
{
|
||
|
for(unsigned i = 0; i < pDP->PrimitiveCount; ++i)
|
||
|
{
|
||
|
FLOAT *pV[3], *pN[3];
|
||
|
unsigned iM[3], iN[3];
|
||
|
|
||
|
pV[0] = (FLOAT*)(pVerts);
|
||
|
pV[1] = (FLOAT*)(pVerts + (i + 1) * vstride);
|
||
|
pV[2] = (FLOAT*)(pVerts + (i + 2) * vstride);
|
||
|
pN[0] = (FLOAT*)(pNorms);
|
||
|
pN[1] = (FLOAT*)(pNorms + (i + 1) * nstride);
|
||
|
pN[2] = (FLOAT*)(pNorms + (i + 2) * nstride);
|
||
|
iM[0] = pDP->VStart; iN[0] = 0;
|
||
|
iM[1] = pDP->VStart + i + 1; iN[1] = 0;
|
||
|
iM[2] = pDP->VStart + i + 2; iN[2] = 0;
|
||
|
|
||
|
RDNPatch patch(pV, pN, GetRS()[D3DRS_POSITIONORDER], GetRS()[D3DRS_NORMALORDER]);
|
||
|
|
||
|
hr = DrawNPatch(patch, 0, iM, iN, unsigned(GetRSf()[D3DRS_PATCHSEGMENTS]));
|
||
|
if(FAILED(hr))
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case D3DPT_TRIANGLESTRIP:
|
||
|
{
|
||
|
for(unsigned i = 0; i < pDP->PrimitiveCount; ++i)
|
||
|
{
|
||
|
FLOAT *pV[3], *pN[3];
|
||
|
unsigned iM[3], iN[3];
|
||
|
|
||
|
pV[0] = (FLOAT*)(pVerts + i * vstride);
|
||
|
pN[0] = (FLOAT*)(pNorms + i * nstride);
|
||
|
iM[0] = pDP->VStart + i; iN[0] = 0;
|
||
|
iM[0] = pDP->VStart + i; iN[0] = 0;
|
||
|
if((i & 1) != 0)
|
||
|
{
|
||
|
pV[1] = (FLOAT*)(pVerts + (i + 2) * vstride);
|
||
|
pV[2] = (FLOAT*)(pVerts + (i + 1) * vstride);
|
||
|
pN[1] = (FLOAT*)(pNorms + (i + 2) * nstride);
|
||
|
pN[2] = (FLOAT*)(pNorms + (i + 1) * nstride);
|
||
|
iM[1] = pDP->VStart + i + 2; iN[1] = 0;
|
||
|
iM[2] = pDP->VStart + i + 1; iN[2] = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pV[1] = (FLOAT*)(pVerts + (i + 1) * vstride);
|
||
|
pV[2] = (FLOAT*)(pVerts + (i + 2) * vstride);
|
||
|
pN[1] = (FLOAT*)(pNorms + (i + 1) * nstride);
|
||
|
pN[2] = (FLOAT*)(pNorms + (i + 2) * nstride);
|
||
|
iM[1] = pDP->VStart + i + 1; iN[1] = 0;
|
||
|
iM[2] = pDP->VStart + i + 2; iN[2] = 0;
|
||
|
}
|
||
|
|
||
|
RDNPatch patch(pV, pN, GetRS()[D3DRS_POSITIONORDER], GetRS()[D3DRS_NORMALORDER]);
|
||
|
|
||
|
hr = DrawNPatch(patch, 0, iM, iN, unsigned(GetRSf()[D3DRS_PATCHSEGMENTS]));
|
||
|
if(FAILED(hr))
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
_ASSERT(FALSE, "Unsupported primitive type");
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// RefDev::ProcessTessIndexedPrimitive
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT
|
||
|
RefDev::ProcessTessIndexedPrimitive( LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE pDIP )
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
if( RDVSD_ISLEGACY( m_CurrentVShaderHandle ) )
|
||
|
{
|
||
|
//
|
||
|
// The legacy FVF style: The Zero'th Stream is implied
|
||
|
//
|
||
|
DWORD dwFVF = m_CurrentVShaderHandle;
|
||
|
RDVStream& Stream = m_VStream[0];
|
||
|
DWORD dwStride = Stream.m_dwStride;
|
||
|
DWORD dwFVFSize = GetFVFVertexSize( dwFVF );
|
||
|
|
||
|
if( Stream.m_pData == NULL || dwStride == 0 )
|
||
|
{
|
||
|
DPFERR( "Zero'th stream doesnt have valid VB set" );
|
||
|
return DDERR_INVALIDPARAMS;
|
||
|
}
|
||
|
if( dwStride < dwFVFSize )
|
||
|
{
|
||
|
DPFERR( "The stride set for the vertex stream is less than"
|
||
|
" the FVF vertex size" );
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
if( m_IndexStream.m_pData == NULL )
|
||
|
{
|
||
|
DPFERR( "Indices are not available" );
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BYTE *pVerts = 0, *pNorms = 0;
|
||
|
unsigned vstride, nstride;
|
||
|
|
||
|
// Figure out where the positions and normals are
|
||
|
RDVDeclaration &Decl = m_pCurrentVShader->m_Declaration;
|
||
|
for(unsigned e = 0; e < Decl.m_dwNumElements; ++e)
|
||
|
{
|
||
|
RDVElement &velem = Decl.m_VertexElements[e];
|
||
|
if(velem.m_dwRegister == D3DVSDE_POSITION) // Position
|
||
|
{
|
||
|
RDVStream &vstream = m_VStream[velem.m_dwStreamIndex];
|
||
|
pVerts = vstream.m_pSavedData + pDIP->BaseVertexIndex * vstream.m_dwStride + velem.m_dwOffset;
|
||
|
vstride = vstream.m_dwStride;
|
||
|
}
|
||
|
else if(velem.m_dwRegister == D3DVSDE_NORMAL) // Normal
|
||
|
{
|
||
|
RDVStream &vstream = m_VStream[velem.m_dwStreamIndex];
|
||
|
pNorms = vstream.m_pSavedData + pDIP->BaseVertexIndex * vstream.m_dwStride + velem.m_dwOffset;
|
||
|
nstride = vstream.m_dwStride;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(pVerts == 0 || pNorms == 0)
|
||
|
{
|
||
|
DPFERR("This tessellation scheme needs positions and normals explicitely specified");
|
||
|
return DDERR_INVALIDPARAMS;
|
||
|
}
|
||
|
|
||
|
RRIndexAccessor Index(m_IndexStream.m_pData, m_IndexStream.m_dwStride, pDIP->StartIndex);
|
||
|
|
||
|
switch(pDIP->primType)
|
||
|
{
|
||
|
case D3DPT_TRIANGLELIST:
|
||
|
{
|
||
|
for(unsigned i = 0; i < pDIP->PrimitiveCount; ++i)
|
||
|
{
|
||
|
FLOAT *pV[3], *pN[3];
|
||
|
unsigned iM[3], iN[3];
|
||
|
|
||
|
pV[0] = (FLOAT*)(pVerts + Index[i * 3] * vstride);
|
||
|
pV[1] = (FLOAT*)(pVerts + Index[i * 3 + 1] * vstride);
|
||
|
pV[2] = (FLOAT*)(pVerts + Index[i * 3 + 2] * vstride);
|
||
|
pN[0] = (FLOAT*)(pNorms + Index[i * 3] * nstride);
|
||
|
pN[1] = (FLOAT*)(pNorms + Index[i * 3 + 1] * nstride);
|
||
|
pN[2] = (FLOAT*)(pNorms + Index[i * 3 + 2] * nstride);
|
||
|
iM[0] = pDIP->BaseVertexIndex + Index[i * 3]; iN[0] = 0;
|
||
|
iM[1] = pDIP->BaseVertexIndex + Index[i * 3 + 1]; iN[1] = 0;
|
||
|
iM[2] = pDIP->BaseVertexIndex + Index[i * 3 + 2]; iN[2] = 0;
|
||
|
|
||
|
RDNPatch patch(pV, pN, GetRS()[D3DRS_POSITIONORDER], GetRS()[D3DRS_NORMALORDER]);
|
||
|
|
||
|
hr = DrawNPatch(patch, 0, iM, iN, unsigned(GetRSf()[D3DRS_PATCHSEGMENTS]));
|
||
|
if(FAILED(hr))
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case D3DPT_TRIANGLEFAN:
|
||
|
{
|
||
|
for(unsigned i = 0; i < pDIP->PrimitiveCount; ++i)
|
||
|
{
|
||
|
FLOAT *pV[3], *pN[3];
|
||
|
unsigned iM[3], iN[3];
|
||
|
|
||
|
pV[0] = (FLOAT*)(pVerts + Index[0] * vstride);
|
||
|
pV[1] = (FLOAT*)(pVerts + Index[i + 1] * vstride);
|
||
|
pV[2] = (FLOAT*)(pVerts + Index[i + 2] * vstride);
|
||
|
pN[0] = (FLOAT*)(pNorms + Index[0] * nstride);
|
||
|
pN[1] = (FLOAT*)(pNorms + Index[i + 1] * nstride);
|
||
|
pN[2] = (FLOAT*)(pNorms + Index[i + 2] * nstride);
|
||
|
iM[0] = pDIP->BaseVertexIndex + Index[0]; iN[0] = 0;
|
||
|
iM[1] = pDIP->BaseVertexIndex + Index[i + 1]; iN[1] = 0;
|
||
|
iM[2] = pDIP->BaseVertexIndex + Index[i + 2]; iN[2] = 0;
|
||
|
|
||
|
RDNPatch patch(pV, pN, GetRS()[D3DRS_POSITIONORDER], GetRS()[D3DRS_NORMALORDER]);
|
||
|
|
||
|
hr = DrawNPatch(patch, 0, iM, iN, unsigned(GetRSf()[D3DRS_PATCHSEGMENTS]));
|
||
|
if(FAILED(hr))
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case D3DPT_TRIANGLESTRIP:
|
||
|
{
|
||
|
for(unsigned i = 0; i < pDIP->PrimitiveCount; ++i)
|
||
|
{
|
||
|
FLOAT *pV[3], *pN[3];
|
||
|
unsigned iM[3], iN[3];
|
||
|
|
||
|
pV[0] = (FLOAT*)(pVerts + Index[i] * vstride);
|
||
|
pN[0] = (FLOAT*)(pNorms + Index[i] * nstride);
|
||
|
iM[0] = pDIP->BaseVertexIndex + Index[i]; iN[0] = 0;
|
||
|
iM[0] = pDIP->BaseVertexIndex + Index[i]; iN[0] = 0;
|
||
|
if((i & 1) != 0)
|
||
|
{
|
||
|
pV[1] = (FLOAT*)(pVerts + Index[i + 2] * vstride);
|
||
|
pV[2] = (FLOAT*)(pVerts + Index[i + 1] * vstride);
|
||
|
pN[1] = (FLOAT*)(pNorms + Index[i + 2] * nstride);
|
||
|
pN[2] = (FLOAT*)(pNorms + Index[i + 1] * nstride);
|
||
|
iM[1] = pDIP->BaseVertexIndex + Index[i + 2]; iN[1] = 0;
|
||
|
iM[2] = pDIP->BaseVertexIndex + Index[i + 1]; iN[2] = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pV[1] = (FLOAT*)(pVerts + Index[i + 1] * vstride);
|
||
|
pV[2] = (FLOAT*)(pVerts + Index[i + 2] * vstride);
|
||
|
pN[1] = (FLOAT*)(pNorms + Index[i + 1] * nstride);
|
||
|
pN[2] = (FLOAT*)(pNorms + Index[i + 2] * nstride);
|
||
|
iM[1] = pDIP->BaseVertexIndex + Index[i + 1]; iN[1] = 0;
|
||
|
iM[2] = pDIP->BaseVertexIndex + Index[i + 2]; iN[2] = 0;
|
||
|
}
|
||
|
|
||
|
RDNPatch patch(pV, pN, GetRS()[D3DRS_POSITIONORDER], GetRS()[D3DRS_NORMALORDER]);
|
||
|
|
||
|
hr = DrawNPatch(patch, 0, iM, iN, unsigned(GetRSf()[D3DRS_PATCHSEGMENTS]));
|
||
|
if(FAILED(hr))
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
_ASSERT(FALSE, "Unsupported primitive type");
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// RDCubicBezierTriangle::SamplePosition
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void RDCubicBezierTriangle::SamplePosition(double u, double v, FLOAT *Q) const
|
||
|
{
|
||
|
for(unsigned e = 0; e < 3; ++e)
|
||
|
{
|
||
|
Q[e] = FLOAT(m_B[0][0][e] * Basis(0, 0, u, v) +
|
||
|
m_B[0][3][e] * Basis(0, 3, u, v) +
|
||
|
m_B[3][0][e] * Basis(3, 0, u, v) +
|
||
|
m_B[0][1][e] * Basis(0, 1, u, v) +
|
||
|
m_B[0][2][e] * Basis(0, 2, u, v) +
|
||
|
m_B[1][2][e] * Basis(1, 2, u, v) +
|
||
|
m_B[2][1][e] * Basis(2, 1, u, v) +
|
||
|
m_B[2][0][e] * Basis(2, 0, u, v) +
|
||
|
m_B[1][0][e] * Basis(1, 0, u, v) +
|
||
|
m_B[1][1][e] * Basis(1, 1, u, v));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// RDCubicBezierTriangle::Sample
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void RDCubicBezierTriangle::Sample(DWORD dwDataType, double u, double v, const BYTE* const B[], BYTE *Q) const
|
||
|
{
|
||
|
double w = 1.0 - u - v;
|
||
|
unsigned dwElements = 0;
|
||
|
switch(dwDataType)
|
||
|
{
|
||
|
case D3DVSDT_FLOAT4:
|
||
|
++dwElements;
|
||
|
case D3DVSDT_FLOAT3:
|
||
|
++dwElements;
|
||
|
case D3DVSDT_FLOAT2:
|
||
|
++dwElements;
|
||
|
case D3DVSDT_FLOAT1:
|
||
|
++dwElements;
|
||
|
{
|
||
|
for(unsigned e = 0; e < dwElements; ++e)
|
||
|
{
|
||
|
((FLOAT*)Q)[e] = FLOAT(w * double(((FLOAT*)B[0])[e]) + v * double(((FLOAT*)B[1])[e]) + u * double(((FLOAT*)B[2])[e]));
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case D3DVSDT_D3DCOLOR:
|
||
|
case D3DVSDT_UBYTE4:
|
||
|
dwElements = 4;
|
||
|
{
|
||
|
for(unsigned e = 0; e < 4; ++e)
|
||
|
{
|
||
|
int t = int(w * double(B[0][e]) + v * double(B[1][e]) + u * double(B[2][e]));
|
||
|
Q[e] = BYTE(t < 0 ? 0 : (t > 255 ? 255 : t));
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case D3DVSDT_SHORT4:
|
||
|
dwElements += 2;
|
||
|
case D3DVSDT_SHORT2:
|
||
|
dwElements += 2;
|
||
|
{
|
||
|
for(unsigned e = 0; e < dwElements; ++e)
|
||
|
{
|
||
|
((SHORT*)Q)[e] = SHORT(w * double(((SHORT*)B[0])[e]) + v * double(((SHORT*)B[1])[e]) + u * double(((SHORT*)B[2])[e]));
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
_ASSERT(FALSE, "Ununderstood vertex element data type");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// RDNPatch::RDNPatch
|
||
|
//-----------------------------------------------------------------------------
|
||
|
RDNPatch::RDNPatch(const FLOAT* const pV[], const FLOAT* const pN[],
|
||
|
const DWORD PositionOrder, const DWORD NormalOrder)
|
||
|
{
|
||
|
_ASSERT((PositionOrder == D3DORDER_LINEAR) || (PositionOrder == D3DORDER_CUBIC),
|
||
|
"Unsupported position order in NPatch");
|
||
|
_ASSERT((NormalOrder == D3DORDER_LINEAR) || (NormalOrder == D3DORDER_QUADRATIC),
|
||
|
"Unsupported normal order in NPatch");
|
||
|
|
||
|
m_PositionOrder = PositionOrder;
|
||
|
m_NormalOrder = NormalOrder;
|
||
|
// Assign corner points
|
||
|
m_B[0][0][0] = double(pV[0][0]);
|
||
|
m_B[0][0][1] = double(pV[0][1]);
|
||
|
m_B[0][0][2] = double(pV[0][2]);
|
||
|
m_B[0][3][0] = double(pV[1][0]);
|
||
|
m_B[0][3][1] = double(pV[1][1]);
|
||
|
m_B[0][3][2] = double(pV[1][2]);
|
||
|
m_B[3][0][0] = double(pV[2][0]);
|
||
|
m_B[3][0][1] = double(pV[2][1]);
|
||
|
m_B[3][0][2] = double(pV[2][2]);
|
||
|
|
||
|
if (PositionOrder == D3DORDER_CUBIC)
|
||
|
{
|
||
|
// Compute edge control points
|
||
|
ComputeEdgeControlPoint(0, 1, pV, pN, 0, 1);
|
||
|
ComputeEdgeControlPoint(1, 0, pV, pN, 0, 2);
|
||
|
ComputeEdgeControlPoint(1, 2, pV, pN, 1, 2);
|
||
|
ComputeEdgeControlPoint(2, 1, pV, pN, 2, 1);
|
||
|
ComputeEdgeControlPoint(2, 0, pV, pN, 2, 0);
|
||
|
ComputeEdgeControlPoint(0, 2, pV, pN, 1, 0);
|
||
|
|
||
|
// Compute central control point
|
||
|
m_B[1][1][0] = (m_B[2][0][0] + m_B[1][0][0] + m_B[0][2][0] + m_B[0][1][0] + m_B[2][1][0] + m_B[1][2][0]) / 4.0 -
|
||
|
(m_B[3][0][0] + m_B[0][3][0] + m_B[0][0][0]) / 6.0;
|
||
|
m_B[1][1][1] = (m_B[2][0][1] + m_B[1][0][1] + m_B[0][2][1] + m_B[0][1][1] + m_B[2][1][1] + m_B[1][2][1]) / 4.0 -
|
||
|
(m_B[3][0][1] + m_B[0][3][1] + m_B[0][0][1]) / 6.0;
|
||
|
m_B[1][1][2] = (m_B[2][0][2] + m_B[1][0][2] + m_B[0][2][2] + m_B[0][1][2] + m_B[2][1][2] + m_B[1][2][2]) / 4.0 -
|
||
|
(m_B[3][0][2] + m_B[0][3][2] + m_B[0][0][2]) / 6.0;
|
||
|
}
|
||
|
if (NormalOrder == D3DORDER_QUADRATIC)
|
||
|
{
|
||
|
// Compute central control point
|
||
|
Normalize(*(RDVECTOR3*)pN[0]);
|
||
|
Normalize(*(RDVECTOR3*)pN[1]);
|
||
|
Normalize(*(RDVECTOR3*)pN[2]);
|
||
|
m_N002 = *(RDVECTOR3*)pN[0];
|
||
|
m_N020 = *(RDVECTOR3*)pN[1];
|
||
|
m_N200 = *(RDVECTOR3*)pN[2];
|
||
|
ComputeNormalControlPoint(&m_N110, 1, 2, pV, pN);
|
||
|
ComputeNormalControlPoint(&m_N101, 2, 0, pV, pN);
|
||
|
ComputeNormalControlPoint(&m_N011, 0, 1, pV, pN);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// RDNPatch::SamplePosition
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void RDNPatch::SamplePosition(double u, double v, FLOAT *Q) const
|
||
|
{
|
||
|
if (m_PositionOrder == D3DORDER_CUBIC)
|
||
|
RDCubicBezierTriangle::SamplePosition(u, v, Q);
|
||
|
else
|
||
|
{
|
||
|
double w = 1.0 - u - v;
|
||
|
Q[0] = m_B[0][0][0] * w + m_B[0][3][0] * v + m_B[3][0][0] * u;
|
||
|
Q[1] = m_B[0][0][1] * w + m_B[0][3][1] * v + m_B[3][0][1] * u;
|
||
|
Q[2] = m_B[0][0][2] * w + m_B[0][3][2] * v + m_B[3][0][2] * u;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// RDNPatch::SampleNormal
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void RDNPatch::SampleNormal(double u, double v, const BYTE* const B[], FLOAT *Q) const
|
||
|
{
|
||
|
if (m_NormalOrder == D3DORDER_LINEAR)
|
||
|
RDCubicBezierTriangle::Sample(D3DVSDT_FLOAT3, u, v, B, (BYTE*)Q);
|
||
|
else
|
||
|
{
|
||
|
// Computed by article "Curved PN Triangles" (Chas Boyd, ...)
|
||
|
double w = 1.0 - u - v;
|
||
|
double ww = w*w;
|
||
|
double uu = u*u;
|
||
|
double vv = v*v;
|
||
|
double uv = u*v;
|
||
|
double wu = w*u;
|
||
|
double wv = w*v;
|
||
|
Q[0] = m_N200.x * uu + m_N020.x * vv + m_N002.x * ww + m_N110.x * uv + m_N011.x * wv + m_N101.x * wu;
|
||
|
Q[1] = m_N200.y * uu + m_N020.y * vv + m_N002.y * ww + m_N110.y * uv + m_N011.y * wv + m_N101.y * wu;
|
||
|
Q[2] = m_N200.z * uu + m_N020.z * vv + m_N002.z * ww + m_N110.z * uv + m_N011.z * wv + m_N101.z * wu;
|
||
|
Normalize(*(RDVECTOR3*)Q);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// RDNPatch::ComputeNormalControlPoint
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void RDNPatch::ComputeNormalControlPoint(RDVECTOR3* cp, unsigned i, unsigned j,
|
||
|
const FLOAT* const pV[],
|
||
|
const FLOAT* const pN[])
|
||
|
{
|
||
|
RDVECTOR3 Pji, Nij;
|
||
|
SubtractVector(*(RDVECTOR3*)pV[j], *(RDVECTOR3*)pV[i], Pji);
|
||
|
AddVector(*(RDVECTOR3*)pN[j], *(RDVECTOR3*)pN[i], Nij);
|
||
|
FLOAT v = 2.0f * DotProduct(Pji, Nij) / DotProduct(Pji, Pji);
|
||
|
SubtractVector(Nij, ScaleVector(Pji, v), *cp);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// RDNPatch::ComputeEdgeControlPoint
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void RDNPatch::ComputeEdgeControlPoint(unsigned a, unsigned b, const FLOAT* const pV[], const FLOAT* const pN[], unsigned u, unsigned v)
|
||
|
{
|
||
|
static const double Tension = 1.0 / 3.0;
|
||
|
double t, Edge[3];
|
||
|
|
||
|
Edge[0] = double(pV[b][0]) - double(pV[a][0]);
|
||
|
Edge[1] = double(pV[b][1]) - double(pV[a][1]);
|
||
|
Edge[2] = double(pV[b][2]) - double(pV[a][2]);
|
||
|
|
||
|
t = Edge[0] * double(pN[a][0]) + Edge[1] * double(pN[a][1]) + Edge[2] * double(pN[a][2]);
|
||
|
|
||
|
m_B[u][v][0] = double(pV[a][0]) + (Edge[0] - t * double(pN[a][0])) * Tension;
|
||
|
m_B[u][v][1] = double(pV[a][1]) + (Edge[1] - t * double(pN[a][1])) * Tension;
|
||
|
m_B[u][v][2] = double(pV[a][2]) + (Edge[2] - t * double(pN[a][2])) * Tension;
|
||
|
}
|