windows-nt/Source/XPSP1/NT/multimedia/directx/dxg/ref8/hop/npatch.cpp
2020-09-26 16:20:57 +08:00

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;
}