You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1118 lines
48 KiB
1118 lines
48 KiB
/*============================================================================
|
|
*
|
|
* Copyright (C) 2001 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: npatch.cpp
|
|
* Content: Consersion of NPatches to Rect-Patches
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
//-----------------------------------------------------------------------------
|
|
UINT CVertexPointer::Stride[__NUMELEMENTS];
|
|
UINT CVertexPointer::NumUsedElements;
|
|
UINT CVertexPointer::DataType[__NUMELEMENTS];
|
|
//-----------------------------------------------------------------------------
|
|
static const float Tension = 1.0f/3.0f;
|
|
static const float OneOver3 = 1.0f/3.0f;
|
|
//-----------------------------------------------------------------------------
|
|
struct UVW
|
|
{
|
|
float u, v, w, uu, vv, ww, uv, uw, vw;
|
|
};
|
|
static UVW g_uvw[10];
|
|
//-----------------------------------------------------------------------------
|
|
CNPatch2TriPatch::CNPatch2TriPatch()
|
|
{
|
|
memset(this, 0, sizeof(this));
|
|
// Write only streams with RTPatches usage
|
|
for (int i=0; i < __NUMELEMENTS; i++)
|
|
m_pOutStream[i] = new CTLStream(TRUE, D3DUSAGE_RTPATCHES);
|
|
int k = 0;
|
|
for(int vv = 3; vv >= 0; --vv)
|
|
for(int uu = 0; uu < 4 - vv; ++uu)
|
|
{
|
|
int ww = 3 - uu - vv;
|
|
float u = uu * OneOver3;
|
|
float v = vv * OneOver3;
|
|
float w = ww * OneOver3;
|
|
g_uvw[k].u = u;
|
|
g_uvw[k].v = v;
|
|
g_uvw[k].w = w;
|
|
g_uvw[k].uu = u*u;
|
|
g_uvw[k].vv = v*v;
|
|
g_uvw[k].ww = w*w;
|
|
g_uvw[k].uv = u*v;
|
|
g_uvw[k].uw = u*w;
|
|
g_uvw[k].vw = v*w;
|
|
k++;
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void ComputeNormalControlPoint(D3DVECTOR* cp,
|
|
float* pVi, float* pVj,
|
|
float* pNi, float* pNj)
|
|
{
|
|
D3DVECTOR Pji;
|
|
D3DVECTOR Nij;
|
|
VecSub(*(D3DVECTOR*)pVj, *(D3DVECTOR*)pVi, Pji);
|
|
VecAdd(*(D3DVECTOR*)pNj, *(D3DVECTOR*)pNi, Nij);
|
|
FLOAT v = 2.0f * VecDot(Pji, Nij) / VecDot(Pji, Pji);
|
|
Pji.x *= v;
|
|
Pji.y *= v;
|
|
Pji.z *= v;
|
|
VecSub(Nij, Pji, *cp);
|
|
|
|
// Now go from polynomial coefficients to Bezier control points
|
|
|
|
cp->x *= 0.5f;
|
|
cp->y *= 0.5f;
|
|
cp->z *= 0.5f;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
CNPatch2TriPatch::~CNPatch2TriPatch()
|
|
{
|
|
for (int i=0; i < __NUMELEMENTS; i++)
|
|
delete m_pOutStream[i];
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
// Convert NPatch to Rect-Patch:
|
|
//
|
|
void CNPatch2TriPatch::MakeRectPatch(const CVertexPointer& pV0,
|
|
const CVertexPointer& pV2,
|
|
const CVertexPointer& pV1)
|
|
{
|
|
float t, Edge[3], B[10][3];
|
|
float n0[3];
|
|
float n1[3];
|
|
float n2[3];
|
|
|
|
float *p0 = (float*)pV0.pData[m_PositionIndex];
|
|
float *p1 = (float*)pV1.pData[m_PositionIndex];
|
|
float *p2 = (float*)pV2.pData[m_PositionIndex];
|
|
n0[0] = ((float*)pV0.pData[m_NormalIndex])[0];
|
|
n0[1] = ((float*)pV0.pData[m_NormalIndex])[1];
|
|
n0[2] = ((float*)pV0.pData[m_NormalIndex])[2];
|
|
n1[0] = ((float*)pV1.pData[m_NormalIndex])[0];
|
|
n1[1] = ((float*)pV1.pData[m_NormalIndex])[1];
|
|
n1[2] = ((float*)pV1.pData[m_NormalIndex])[2];
|
|
n2[0] = ((float*)pV2.pData[m_NormalIndex])[0];
|
|
n2[1] = ((float*)pV2.pData[m_NormalIndex])[1];
|
|
n2[2] = ((float*)pV2.pData[m_NormalIndex])[2];
|
|
|
|
// Coefficients to interpolate quadratic normals
|
|
D3DVECTOR N002;
|
|
D3DVECTOR N020;
|
|
D3DVECTOR N200;
|
|
D3DVECTOR N110;
|
|
D3DVECTOR N101;
|
|
D3DVECTOR N011;
|
|
|
|
// Convert NPatch to Tri-Patch first
|
|
|
|
if (m_PositionOrder == D3DORDER_CUBIC)
|
|
{
|
|
B[0][0] = p0[0];
|
|
B[0][1] = p0[1];
|
|
B[0][2] = p0[2];
|
|
B[6][0] = p1[0];
|
|
B[6][1] = p1[1];
|
|
B[6][2] = p1[2];
|
|
B[9][0] = p2[0];
|
|
B[9][1] = p2[1];
|
|
B[9][2] = p2[2];
|
|
|
|
Edge[0] = p1[0] - p0[0];
|
|
Edge[1] = p1[1] - p0[1];
|
|
Edge[2] = p1[2] - p0[2];
|
|
t = Edge[0] * n0[0] + Edge[1] * n0[1] + Edge[2] * n0[2];
|
|
B[1][0] = p0[0] + (Edge[0] - n0[0] * t) * Tension;
|
|
B[1][1] = p0[1] + (Edge[1] - n0[1] * t) * Tension;
|
|
B[1][2] = p0[2] + (Edge[2] - n0[2] * t) * Tension;
|
|
Edge[0] = p0[0] - p1[0];
|
|
Edge[1] = p0[1] - p1[1];
|
|
Edge[2] = p0[2] - p1[2];
|
|
t = Edge[0] * n1[0] + Edge[1] * n1[1] + Edge[2] * n1[2];
|
|
B[3][0] = p1[0] + (Edge[0] - n1[0] * t) * Tension;
|
|
B[3][1] = p1[1] + (Edge[1] - n1[1] * t) * Tension;
|
|
B[3][2] = p1[2] + (Edge[2] - n1[2] * t) * Tension;
|
|
Edge[0] = p2[0] - p1[0];
|
|
Edge[1] = p2[1] - p1[1];
|
|
Edge[2] = p2[2] - p1[2];
|
|
t = Edge[0] * n1[0] + Edge[1] * n1[1] + Edge[2] * n1[2];
|
|
B[7][0] = p1[0] + (Edge[0] - n1[0] * t) * Tension;
|
|
B[7][1] = p1[1] + (Edge[1] - n1[1] * t) * Tension;
|
|
B[7][2] = p1[2] + (Edge[2] - n1[2] * t) * Tension;
|
|
Edge[0] = p1[0] - p2[0];
|
|
Edge[1] = p1[1] - p2[1];
|
|
Edge[2] = p1[2] - p2[2];
|
|
t = Edge[0] * n2[0] + Edge[1] * n2[1] + Edge[2] * n2[2];
|
|
B[8][0] = p2[0] + (Edge[0] - n2[0] * t) * Tension;
|
|
B[8][1] = p2[1] + (Edge[1] - n2[1] * t) * Tension;
|
|
B[8][2] = p2[2] + (Edge[2] - n2[2] * t) * Tension;
|
|
Edge[0] = p2[0] - p0[0];
|
|
Edge[1] = p2[1] - p0[1];
|
|
Edge[2] = p2[2] - p0[2];
|
|
t = Edge[0] * n0[0] + Edge[1] * n0[1] + Edge[2] * n0[2];
|
|
B[2][0] = p0[0] + (Edge[0] - n0[0] * t) * Tension;
|
|
B[2][1] = p0[1] + (Edge[1] - n0[1] * t) * Tension;
|
|
B[2][2] = p0[2] + (Edge[2] - n0[2] * t) * Tension;
|
|
Edge[0] = p0[0] - p2[0];
|
|
Edge[1] = p0[1] - p2[1];
|
|
Edge[2] = p0[2] - p2[2];
|
|
t = Edge[0] * n2[0] + Edge[1] * n2[1] + Edge[2] * n2[2];
|
|
B[5][0] = p2[0] + (Edge[0] - n2[0] * t) * Tension;
|
|
B[5][1] = p2[1] + (Edge[1] - n2[1] * t) * Tension;
|
|
B[5][2] = p2[2] + (Edge[2] - n2[2] * t) * Tension;
|
|
|
|
B[4][0] = (B[1][0] + B[2][0] + B[3][0] + B[5][0] + B[7][0] + B[8][0]) / 4.0f - (B[0][0] + B[6][0] + B[9][0]) / 6.0f;
|
|
B[4][1] = (B[1][1] + B[2][1] + B[3][1] + B[5][1] + B[7][1] + B[8][1]) / 4.0f - (B[0][1] + B[6][1] + B[9][1]) / 6.0f;
|
|
B[4][2] = (B[1][2] + B[2][2] + B[3][2] + B[5][2] + B[7][2] + B[8][2]) / 4.0f - (B[0][2] + B[6][2] + B[9][2]) / 6.0f;
|
|
}
|
|
if (m_NormalOrder == D3DORDER_QUADRATIC)
|
|
{
|
|
// Compute central control point
|
|
if (m_bNormalizeNormals)
|
|
{
|
|
VecNormalizeFast(*n0);
|
|
VecNormalizeFast(*n1);
|
|
VecNormalizeFast(*n2);
|
|
}
|
|
N002 = *(D3DVECTOR*)n1;
|
|
N020 = *(D3DVECTOR*)n0;
|
|
N200 = *(D3DVECTOR*)n2;
|
|
|
|
// Compute edge control points
|
|
|
|
ComputeNormalControlPoint(&N110, p0, p2, n0, n2);
|
|
ComputeNormalControlPoint(&N101, p2, p1, n2, n1);
|
|
ComputeNormalControlPoint(&N011, p1, p0, n1, n0);
|
|
}
|
|
|
|
float CP[__NUMELEMENTS*4][10]; // Computed tri-patch control pointes
|
|
int iCP; // Float value index in the control point array
|
|
for(int k = 0; k < 10; k++)
|
|
{
|
|
iCP = 0;
|
|
const float U = g_uvw[k].u;
|
|
const float V = g_uvw[k].v;
|
|
const float W = g_uvw[k].w;
|
|
|
|
for (UINT iElement=0; iElement < CVertexPointer::NumUsedElements; iElement++)
|
|
{
|
|
if (iElement == m_PositionIndex)
|
|
{
|
|
if (m_PositionOrder == D3DORDER_CUBIC)
|
|
{
|
|
CP[iCP++][k] = B[k][0];
|
|
CP[iCP++][k] = B[k][1];
|
|
CP[iCP++][k] = B[k][2];
|
|
}
|
|
else
|
|
{
|
|
CP[iCP++][k] = p2[0] * U + p0[0] * V + p1[0] * W;
|
|
CP[iCP++][k] = p2[1] * U + p0[1] * V + p1[1] * W;
|
|
CP[iCP++][k] = p2[2] * U + p0[2] * V + p1[2] * W;
|
|
}
|
|
}
|
|
else
|
|
if (iElement == m_NormalIndex)
|
|
{
|
|
if (m_NormalOrder == D3DORDER_QUADRATIC)
|
|
{
|
|
D3DVECTOR Q;
|
|
// Do degree elevation from quadratic to cubic
|
|
switch (k)
|
|
{
|
|
case 0:
|
|
Q.x = N020.x;
|
|
Q.y = N020.y;
|
|
Q.z = N020.z;
|
|
break;
|
|
case 1:
|
|
Q.x = (2.0f*N011.x + N020.x) * OneOver3;
|
|
Q.y = (2.0f*N011.y + N020.y) * OneOver3;
|
|
Q.z = (2.0f*N011.z + N020.z) * OneOver3;
|
|
break;
|
|
case 2:
|
|
Q.x = (2.0f*N110.x + N020.x) * OneOver3;
|
|
Q.y = (2.0f*N110.y + N020.y) * OneOver3;
|
|
Q.z = (2.0f*N110.z + N020.z) * OneOver3;
|
|
break;
|
|
case 3:
|
|
Q.x = (2.0f*N011.x + N002.x) * OneOver3;
|
|
Q.y = (2.0f*N011.y + N002.y) * OneOver3;
|
|
Q.z = (2.0f*N011.z + N002.z) * OneOver3;
|
|
break;
|
|
case 4:
|
|
Q.x = (N011.x + N101.x + N110.x) * OneOver3;
|
|
Q.y = (N011.y + N101.y + N110.y) * OneOver3;
|
|
Q.z = (N011.z + N101.z + N110.z) * OneOver3;
|
|
break;
|
|
case 5:
|
|
Q.x = (2.0f*N110.x + N200.x) * OneOver3;
|
|
Q.y = (2.0f*N110.y + N200.y) * OneOver3;
|
|
Q.z = (2.0f*N110.z + N200.z) * OneOver3;
|
|
break;
|
|
case 6:
|
|
Q.x = N002.x;
|
|
Q.y = N002.y;
|
|
Q.z = N002.z;
|
|
break;
|
|
case 7:
|
|
Q.x = (2.0f*N101.x + N002.x) * OneOver3;
|
|
Q.y = (2.0f*N101.y + N002.y) * OneOver3;
|
|
Q.z = (2.0f*N101.z + N002.z) * OneOver3;
|
|
break;
|
|
case 8:
|
|
Q.x = (2.0f*N101.x + N200.x) * OneOver3;
|
|
Q.y = (2.0f*N101.y + N200.y) * OneOver3;
|
|
Q.z = (2.0f*N101.z + N200.z) * OneOver3;
|
|
break;
|
|
case 9:
|
|
Q.x = N200.x;
|
|
Q.y = N200.y;
|
|
Q.z = N200.z;
|
|
break;
|
|
}
|
|
CP[iCP++][k] = Q.x;
|
|
CP[iCP++][k] = Q.y;
|
|
CP[iCP++][k] = Q.z;
|
|
}
|
|
else
|
|
{
|
|
CP[iCP++][k] = n2[0] * U + n0[0] * V + n1[0] * W;
|
|
CP[iCP++][k] = n2[1] * U + n0[1] * V + n1[1] * W;
|
|
CP[iCP++][k] = n2[2] * U + n0[2] * V + n1[2] * W;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch(CVertexPointer::DataType[iElement])
|
|
{
|
|
case D3DVSDT_FLOAT1:
|
|
CP[iCP++][k] = ((float*)pV2.pData[iElement])[0] * U +
|
|
((float*)pV0.pData[iElement])[0] * V +
|
|
((float*)pV1.pData[iElement])[0] * W;
|
|
break;
|
|
case D3DVSDT_FLOAT2:
|
|
CP[iCP++][k] = ((float*)pV2.pData[iElement])[0] * U +
|
|
((float*)pV0.pData[iElement])[0] * V +
|
|
((float*)pV1.pData[iElement])[0] * W;
|
|
CP[iCP++][k] = ((float*)pV2.pData[iElement])[1] * U +
|
|
((float*)pV0.pData[iElement])[1] * V +
|
|
((float*)pV1.pData[iElement])[1] * W;
|
|
break;
|
|
case D3DVSDT_FLOAT3:
|
|
CP[iCP++][k] = ((float*)pV2.pData[iElement])[0] * U +
|
|
((float*)pV0.pData[iElement])[0] * V +
|
|
((float*)pV1.pData[iElement])[0] * W;
|
|
CP[iCP++][k] = ((float*)pV2.pData[iElement])[1] * U +
|
|
((float*)pV0.pData[iElement])[1] * V +
|
|
((float*)pV1.pData[iElement])[1] * W;
|
|
CP[iCP++][k] = ((float*)pV2.pData[iElement])[2] * U +
|
|
((float*)pV0.pData[iElement])[2] * V +
|
|
((float*)pV1.pData[iElement])[2] * W;
|
|
break;
|
|
case D3DVSDT_FLOAT4:
|
|
CP[iCP++][k] = ((float*)pV2.pData[iElement])[0] * U +
|
|
((float*)pV0.pData[iElement])[0] * V +
|
|
((float*)pV1.pData[iElement])[0] * W;
|
|
CP[iCP++][k] = ((float*)pV2.pData[iElement])[1] * U +
|
|
((float*)pV0.pData[iElement])[1] * V +
|
|
((float*)pV1.pData[iElement])[1] * W;
|
|
CP[iCP++][k] = ((float*)pV2.pData[iElement])[2] * U +
|
|
((float*)pV0.pData[iElement])[2] * V +
|
|
((float*)pV1.pData[iElement])[2] * W;
|
|
CP[iCP++][k] = ((float*)pV2.pData[iElement])[3] * U +
|
|
((float*)pV0.pData[iElement])[3] * V +
|
|
((float*)pV1.pData[iElement])[3] * W;
|
|
break;
|
|
case D3DVSDT_D3DCOLOR:
|
|
case D3DVSDT_UBYTE4:
|
|
DWORD c;
|
|
c = *(DWORD*)pV0.pData[iElement];
|
|
float r[3], g[3], b[3], a[3];
|
|
r[0] = float(c & 0xFF);
|
|
g[0] = float((c >> 8) & 0xFF);
|
|
b[0] = float((c >> 16) & 0xFF);
|
|
a[0] = float((c >> 24) & 0xFF);
|
|
c = *(DWORD*)pV1.pData[iElement];
|
|
r[1] = float(c & 0xFF);
|
|
g[1] = float((c >> 8) & 0xFF);
|
|
b[1] = float((c >> 16) & 0xFF);
|
|
a[1] = float((c >> 24) & 0xFF);
|
|
c = *(DWORD*)pV2.pData[iElement];
|
|
r[2] = float(c & 0xFF);
|
|
g[2] = float((c >> 8) & 0xFF);
|
|
b[2] = float((c >> 16) & 0xFF);
|
|
a[2] = float((c >> 24) & 0xFF);
|
|
CP[iCP++][k] = r[2] * U + r[0] * V + r[1] * W;
|
|
CP[iCP++][k] = g[2] * U + g[0] * V + g[1] * W;
|
|
CP[iCP++][k] = b[2] * U + b[0] * V + b[1] * W;
|
|
CP[iCP++][k] = a[2] * U + a[0] * V + a[1] * W;
|
|
break;
|
|
case D3DVSDT_SHORT2:
|
|
CP[iCP++][k]= (float)(
|
|
((short*)pV2.pData[iElement])[0] * U +
|
|
((short*)pV0.pData[iElement])[0] * V +
|
|
((short*)pV1.pData[iElement])[0] * W);
|
|
CP[iCP++][k] = (float)(
|
|
((short*)pV2.pData[iElement])[1] * U +
|
|
((short*)pV0.pData[iElement])[1] * V +
|
|
((short*)pV1.pData[iElement])[1] * W);
|
|
break;
|
|
case D3DVSDT_SHORT4:
|
|
CP[iCP++][k] = (float)(
|
|
((short*)pV2.pData[iElement])[0] * U +
|
|
((short*)pV0.pData[iElement])[0] * V +
|
|
((short*)pV1.pData[iElement])[0] * W);
|
|
CP[iCP++][k] = (float)(
|
|
((short*)pV2.pData[iElement])[1] * U +
|
|
((short*)pV0.pData[iElement])[1] * V +
|
|
((short*)pV1.pData[iElement])[1] * W);
|
|
CP[iCP++][k] = (float)(
|
|
((short*)pV2.pData[iElement])[2] * U +
|
|
((short*)pV0.pData[iElement])[2] * V +
|
|
((short*)pV1.pData[iElement])[2] * W);
|
|
CP[iCP++][k] = (float)(
|
|
((short*)pV2.pData[iElement])[3] * U +
|
|
((short*)pV0.pData[iElement])[3] * V +
|
|
((short*)pV1.pData[iElement])[3] * W);
|
|
break;
|
|
default: DXGASSERT(FALSE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now convert Tri-Patch to Rect-Patch by transforming 10 tri-patch control
|
|
// points to 16 rect-patch control points
|
|
|
|
float CPR[16][__NUMELEMENTS*4]; // Computed rect-patch control pointes
|
|
{
|
|
for (int i=0; i < iCP; i++)
|
|
{
|
|
// First row - copy first point 4 times
|
|
CPR[0][i] = CPR[1][i] =
|
|
CPR[2][i] = CPR[3][i] = CP[i][0];
|
|
|
|
// 2nd row
|
|
float v1 = CP[i][1];
|
|
float v2 = CP[i][2];
|
|
CPR[ 4][i] = v1;
|
|
CPR[ 5][i] = (v1 * 2.0f + v2 ) * OneOver3;
|
|
CPR[ 6][i] = (v1 + v2 * 2.0f) * OneOver3;
|
|
CPR[ 7][i] = v2;
|
|
|
|
// 3rd row
|
|
CPR[ 8][i] = CP[i][3];
|
|
CPR[ 9][i] = (CP[i][3] + CP[i][4] * 2.0f) * OneOver3;
|
|
CPR[10][i] = (CP[i][4] * 2.0f + CP[i][5] ) * OneOver3;
|
|
CPR[11][i] = CP[i][5];
|
|
|
|
// 4th row - copy all elements
|
|
CPR[12][i] = CP[i][6];
|
|
CPR[13][i] = CP[i][7];
|
|
CPR[14][i] = CP[i][8];
|
|
CPR[15][i] = CP[i][9];
|
|
}
|
|
}
|
|
|
|
// Output the result
|
|
|
|
{
|
|
for (int i=0; i < 16; i++)
|
|
{
|
|
UINT k = 0;
|
|
for (UINT iElement=0; iElement < CVertexPointer::NumUsedElements; iElement++)
|
|
{
|
|
float* pout = (float*)m_OutVertex.pData[iElement];
|
|
switch(CVertexPointer::DataType[iElement])
|
|
{
|
|
case D3DVSDT_FLOAT1:
|
|
pout[0] = CPR[i][k++];
|
|
break;
|
|
case D3DVSDT_FLOAT2:
|
|
pout[0] = CPR[i][k++];
|
|
pout[1] = CPR[i][k++];
|
|
break;
|
|
case D3DVSDT_FLOAT3:
|
|
pout[0] = CPR[i][k++];
|
|
pout[1] = CPR[i][k++];
|
|
pout[2] = CPR[i][k++];
|
|
break;
|
|
case D3DVSDT_FLOAT4:
|
|
pout[0] = CPR[i][k++];
|
|
pout[1] = CPR[i][k++];
|
|
pout[2] = CPR[i][k++];
|
|
pout[3] = CPR[i][k++];
|
|
break;
|
|
case D3DVSDT_D3DCOLOR:
|
|
case D3DVSDT_UBYTE4:
|
|
{
|
|
DWORD c;
|
|
float r = CPR[i][k++];
|
|
float g = CPR[i][k++];
|
|
float b = CPR[i][k++];
|
|
float a = CPR[i][k++];
|
|
c = DWORD(r);
|
|
c |= DWORD(g) << 8;
|
|
c |= DWORD(b) << 16;
|
|
c |= DWORD(a) << 24;
|
|
*(DWORD*)pout = c;
|
|
}
|
|
break;
|
|
case D3DVSDT_SHORT2:
|
|
((short*)pout)[0] = (short)(CPR[i][k++]);
|
|
((short*)pout)[1] = (short)(CPR[i][k++]);
|
|
break;
|
|
case D3DVSDT_SHORT4:
|
|
((short*)pout)[0] = (short)(CPR[i][k++]);
|
|
((short*)pout)[1] = (short)(CPR[i][k++]);
|
|
((short*)pout)[2] = (short)(CPR[i][k++]);
|
|
((short*)pout)[3] = (short)(CPR[i][k++]);
|
|
break;
|
|
default: DXGASSERT(FALSE);
|
|
}
|
|
}
|
|
m_OutVertex++;
|
|
}
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void DrawPatches(CD3DHal* pDevice, UINT PrimitiveCount)
|
|
{
|
|
// Unlock output vertex buffers
|
|
if (D3DVSD_ISLEGACY(pDevice->m_dwCurrentShaderHandle))
|
|
{
|
|
pDevice->m_pConvObj->m_pOutStream[0]->m_pVB->Unlock();
|
|
}
|
|
else
|
|
{
|
|
CVDeclaration* pDecl = &pDevice->m_pCurrentShader->m_Declaration;
|
|
CVStreamDecl* pStreamDecl = pDevice->m_pCurrentShader->m_Declaration.m_pActiveStreams;
|
|
while (pStreamDecl)
|
|
{
|
|
pDevice->m_pConvObj->m_pOutStream[pStreamDecl->m_dwStreamIndex]->m_pVB->Unlock();
|
|
pStreamDecl = (CVStreamDecl*)pStreamDecl->m_pNext;
|
|
}
|
|
}
|
|
|
|
// Draw rect patches
|
|
float numSegs[4];
|
|
numSegs[0] =
|
|
numSegs[1] =
|
|
numSegs[2] =
|
|
numSegs[3] = *(float*)&pDevice->rstates[D3DRS_PATCHSEGMENTS];
|
|
D3DRECTPATCH_INFO info;
|
|
info.StartVertexOffsetWidth = pDevice->m_pConvObj->m_FirstVertex;
|
|
info.StartVertexOffsetHeight = 0;
|
|
info.Width = 4;
|
|
info.Height = 4;
|
|
info.Stride = 4; // verticies to next row of verticies
|
|
info.Basis = D3DBASIS_BEZIER;
|
|
info.Order = D3DORDER_CUBIC;
|
|
|
|
for (UINT i = PrimitiveCount; i > 0; i--)
|
|
{
|
|
pDevice->DrawRectPatch(0, numSegs, &info);
|
|
info.StartVertexOffsetWidth += 16;
|
|
}
|
|
|
|
// Restore input vertex streams
|
|
if (D3DVSD_ISLEGACY(pDevice->m_dwCurrentShaderHandle))
|
|
{
|
|
// Always need to call SetStreamSource to decrease reference count of
|
|
// the internal VB buffer
|
|
pDevice->SetStreamSource(0, pDevice->m_pConvObj->m_InpStream[0].m_pVB,
|
|
CVertexPointer::Stride[0]);
|
|
if (pDevice->m_pConvObj->m_InpStream[0].m_pVB)
|
|
{
|
|
// Remove additional ref count, because the stream is set
|
|
// second time
|
|
pDevice->m_pConvObj->m_InpStream[0].m_pVB->Release();
|
|
pDevice->m_pConvObj->m_InpStream[0].m_pVB = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CVDeclaration* pDecl = &pDevice->m_pCurrentShader->m_Declaration;
|
|
CVStreamDecl* pStreamDecl = pDevice->m_pCurrentShader->m_Declaration.m_pActiveStreams;
|
|
while (pStreamDecl)
|
|
{
|
|
UINT si = pStreamDecl->m_dwStreamIndex;
|
|
UINT Stride = pStreamDecl->m_dwStride;
|
|
CVStream* pStream = &pDevice->m_pConvObj->m_InpStream[si];
|
|
// Always need to call SetStreamSource to decrease reference count
|
|
// of the internal VB buffer
|
|
pDevice->SetStreamSource(si, pStream->m_pVB, Stride);
|
|
if (pStream->m_pVB)
|
|
{
|
|
// Remove additional ref count, because the stream is set second
|
|
// time
|
|
pStream->m_pVB->Release();
|
|
pStream->m_pVB = NULL;
|
|
}
|
|
pStreamDecl = (CVStreamDecl*)pStreamDecl->m_pNext;
|
|
}
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void CD3DHal_DrawNPatch(CD3DBase* pBaseDevice, D3DPRIMITIVETYPE PrimitiveType,
|
|
UINT StartVertex, UINT PrimitiveCount)
|
|
{
|
|
CD3DHal* pDevice = static_cast<CD3DHal*>(pBaseDevice);
|
|
|
|
// Draw as usual for non-triangle primitive types
|
|
if (PrimitiveType < D3DPT_TRIANGLELIST)
|
|
{
|
|
(*pDevice->m_pfnDrawPrimFromNPatch)(pBaseDevice, PrimitiveType,
|
|
StartVertex, PrimitiveCount);
|
|
// m_pfnDrawPrim could be switched to fast path, so we need to restore it
|
|
pDevice->m_pfnDrawPrim = CD3DHal_DrawNPatch;
|
|
return;
|
|
}
|
|
|
|
#if DBG
|
|
UINT nVer = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount);
|
|
pDevice->ValidateDraw2(PrimitiveType, StartVertex, PrimitiveCount, nVer,
|
|
FALSE);
|
|
#endif
|
|
|
|
pDevice->PrepareNPatchConversion(PrimitiveCount, StartVertex);
|
|
|
|
// Go through triangles and generate tri-patches
|
|
|
|
CNPatch2TriPatch* pConvObj = pDevice->m_pConvObj;
|
|
switch( PrimitiveType )
|
|
{
|
|
case D3DPT_TRIANGLELIST:
|
|
{
|
|
for (UINT i = PrimitiveCount; i > 0; i--)
|
|
{
|
|
CVertexPointer pV0 = pConvObj->m_InpVertex;
|
|
pConvObj->m_InpVertex++;
|
|
CVertexPointer pV1 = pConvObj->m_InpVertex;
|
|
pConvObj->m_InpVertex++;
|
|
CVertexPointer pV2 = pConvObj->m_InpVertex;
|
|
pConvObj->m_InpVertex++;
|
|
pConvObj->MakeRectPatch(pV0, pV1, pV2);
|
|
}
|
|
}
|
|
break;
|
|
case D3DPT_TRIANGLESTRIP:
|
|
{
|
|
// Get initial vertex values.
|
|
CVertexPointer pV0;
|
|
CVertexPointer pV1 = pConvObj->m_InpVertex;
|
|
pConvObj->m_InpVertex++;
|
|
CVertexPointer pV2 = pConvObj->m_InpVertex;
|
|
pConvObj->m_InpVertex++;
|
|
|
|
for (UINT i =PrimitiveCount; i > 1; i -= 2)
|
|
{
|
|
pV0 = pV1;
|
|
pV1 = pV2;
|
|
pV2 = pConvObj->m_InpVertex;
|
|
pConvObj->m_InpVertex++;
|
|
pConvObj->MakeRectPatch(pV0, pV1, pV2);
|
|
|
|
pV0 = pV1;
|
|
pV1 = pV2;
|
|
pV2 = pConvObj->m_InpVertex;
|
|
pConvObj->m_InpVertex++;
|
|
pConvObj->MakeRectPatch(pV0, pV2, pV1);
|
|
}
|
|
|
|
if (i > 0)
|
|
{
|
|
pV0 = pV1;
|
|
pV1 = pV2;
|
|
pV2 = pConvObj->m_InpVertex;
|
|
pConvObj->MakeRectPatch(pV0, pV1, pV2);
|
|
}
|
|
}
|
|
break;
|
|
case D3DPT_TRIANGLEFAN:
|
|
{
|
|
CVertexPointer pV0;
|
|
CVertexPointer pV1;
|
|
CVertexPointer pV2;
|
|
pV2 = pConvObj->m_InpVertex;
|
|
pConvObj->m_InpVertex++;
|
|
// Preload initial pV0.
|
|
pV1 = pConvObj->m_InpVertex;
|
|
pConvObj->m_InpVertex++;
|
|
for (UINT i = PrimitiveCount; i > 0; i--)
|
|
{
|
|
pV0 = pV1;
|
|
pV1 = pConvObj->m_InpVertex;
|
|
pConvObj->m_InpVertex++;
|
|
pConvObj->MakeRectPatch(pV0, pV1, pV2);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
DXGASSERT(FALSE);
|
|
}
|
|
|
|
pDevice->m_pDDI->SetWithinPrimitive(TRUE);
|
|
DrawPatches(pDevice, PrimitiveCount);
|
|
pDevice->m_pDDI->SetWithinPrimitive(FALSE);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void CD3DHal_DrawIndexedNPatch(CD3DBase* pBaseDevice,
|
|
D3DPRIMITIVETYPE PrimitiveType,
|
|
UINT BaseIndex,
|
|
UINT MinIndex, UINT NumVertices,
|
|
UINT StartIndex,
|
|
UINT PrimitiveCount)
|
|
{
|
|
CD3DHal* pDevice = static_cast<CD3DHal*>(pBaseDevice);
|
|
|
|
// Draw as usual for non-triangle primitive types
|
|
if (PrimitiveType < D3DPT_TRIANGLELIST)
|
|
{
|
|
(*pDevice->m_pfnDrawIndexedPrimFromNPatch)(pBaseDevice, PrimitiveType,
|
|
BaseIndex, MinIndex, NumVertices,
|
|
StartIndex, PrimitiveCount);
|
|
// m_pfnDrawIndexedPrim could be switched to fast path, so we
|
|
// need to restore it
|
|
pDevice->m_pfnDrawIndexedPrim = CD3DHal_DrawIndexedNPatch;
|
|
return;
|
|
}
|
|
|
|
#if DBG
|
|
pDevice->ValidateDraw2(PrimitiveType, MinIndex + BaseIndex, PrimitiveCount, NumVertices,
|
|
TRUE, StartIndex);
|
|
#endif
|
|
|
|
pDevice->PrepareNPatchConversion(PrimitiveCount, BaseIndex);
|
|
|
|
// Go through triangles and generate tri-patches
|
|
|
|
CNPatch2TriPatch* pConvObj = pDevice->m_pConvObj;
|
|
|
|
if (pDevice->m_pIndexStream->m_dwStride == 2)
|
|
{
|
|
WORD* pIndices = (WORD*)pDevice->m_pIndexStream->Data() + StartIndex;
|
|
switch( PrimitiveType )
|
|
{
|
|
case D3DPT_TRIANGLELIST:
|
|
{
|
|
for (UINT i = PrimitiveCount; i > 0; i--)
|
|
{
|
|
CVertexPointer pV0;
|
|
CVertexPointer pV1;
|
|
CVertexPointer pV2;
|
|
pV0.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
pV1.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
pV2.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
pConvObj->MakeRectPatch(pV0, pV1, pV2);
|
|
}
|
|
}
|
|
break;
|
|
case D3DPT_TRIANGLESTRIP:
|
|
{
|
|
CVertexPointer pV0;
|
|
CVertexPointer pV1;
|
|
CVertexPointer pV2;
|
|
// Get initial vertex values.
|
|
pV1.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
pV2.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
|
|
for (UINT i = PrimitiveCount; i > 1; i -= 2)
|
|
{
|
|
pV0 = pV1;
|
|
pV1 = pV2;
|
|
pV2.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
pConvObj->MakeRectPatch(pV0, pV1, pV2);
|
|
|
|
pV0 = pV1;
|
|
pV1 = pV2;
|
|
pV2.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
pConvObj->MakeRectPatch(pV0, pV2, pV1);
|
|
}
|
|
|
|
if (i > 0)
|
|
{
|
|
pV0 = pV1;
|
|
pV1 = pV2;
|
|
pV2.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
pConvObj->MakeRectPatch(pV0, pV1, pV2);
|
|
}
|
|
}
|
|
break;
|
|
case D3DPT_TRIANGLEFAN:
|
|
{
|
|
CVertexPointer pV1;
|
|
CVertexPointer pV2;
|
|
pV2.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
// Preload initial pV0.
|
|
pV1.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
for (UINT i = PrimitiveCount; i > 0; i--)
|
|
{
|
|
CVertexPointer pV0 = pV1;
|
|
pV1.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
pConvObj->MakeRectPatch(pV0, pV2, pV1);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
DXGASSERT(FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DWORD* pIndices = (DWORD*)pDevice->m_pIndexStream->Data() + StartIndex;
|
|
switch( PrimitiveType )
|
|
{
|
|
case D3DPT_TRIANGLELIST:
|
|
{
|
|
for (UINT i = PrimitiveCount; i > 0; i--)
|
|
{
|
|
CVertexPointer pV0;
|
|
CVertexPointer pV1;
|
|
CVertexPointer pV2;
|
|
pV0.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
pV1.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
pV2.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
pConvObj->MakeRectPatch(pV0, pV1, pV2);
|
|
}
|
|
}
|
|
break;
|
|
case D3DPT_TRIANGLESTRIP:
|
|
{
|
|
CVertexPointer pV0;
|
|
CVertexPointer pV1;
|
|
CVertexPointer pV2;
|
|
// Get initial vertex values.
|
|
pV1.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
pV2.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
|
|
for (UINT i = PrimitiveCount; i > 1; i -= 2)
|
|
{
|
|
pV0 = pV1;
|
|
pV1 = pV2;
|
|
pV2.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
pConvObj->MakeRectPatch(pV0, pV1, pV2);
|
|
|
|
pV0 = pV1;
|
|
pV1 = pV2;
|
|
pV2.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
pConvObj->MakeRectPatch(pV0, pV2, pV1);
|
|
}
|
|
|
|
if (i > 0)
|
|
{
|
|
pV0 = pV1;
|
|
pV1 = pV2;
|
|
pV2.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
pConvObj->MakeRectPatch(pV0, pV1, pV2);
|
|
}
|
|
}
|
|
break;
|
|
case D3DPT_TRIANGLEFAN:
|
|
{
|
|
CVertexPointer pV1;
|
|
CVertexPointer pV2;
|
|
pV2.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
// Preload initial pV0.
|
|
pV1.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
for (UINT i = PrimitiveCount; i > 0; i--)
|
|
{
|
|
CVertexPointer pV0 = pV1;
|
|
pV1.SetVertex(pConvObj->m_InpVertex, (*pIndices++));
|
|
pConvObj->MakeRectPatch(pV0, pV2, pV1);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
DXGASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
DrawPatches(pDevice, PrimitiveCount);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
// Conversion output will have the same number of streams as input and the
|
|
// same vertex shader
|
|
//
|
|
void CD3DHal::PrepareNPatchConversion(UINT PrimitiveCount, UINT StartVertex)
|
|
{
|
|
if (m_pConvObj == NULL)
|
|
{
|
|
m_pConvObj = new CNPatch2TriPatch;
|
|
|
|
if (m_pConvObj == NULL)
|
|
{
|
|
D3D_THROW(E_OUTOFMEMORY, "Not enough memory");
|
|
}
|
|
|
|
// Pre-allocate output streams
|
|
for (int i=0; i < __NUMELEMENTS; i++)
|
|
{
|
|
m_pConvObj->m_pOutStream[i]->Grow(512*32, m_pDDI);
|
|
}
|
|
}
|
|
|
|
m_pConvObj->m_PositionOrder = (D3DORDERTYPE)rstates[D3DRS_POSITIONORDER];
|
|
m_pConvObj->m_NormalOrder = (D3DORDERTYPE)rstates[D3DRS_NORMALORDER];
|
|
m_pConvObj->m_bNormalizeNormals = rstates[D3DRS_NORMALIZENORMALS];
|
|
|
|
// Compute number of vertices in the output. Each output patch has 16
|
|
// control points
|
|
UINT nOutVertices = PrimitiveCount * 16;
|
|
|
|
if (D3DVSD_ISLEGACY(m_dwCurrentShaderHandle))
|
|
{
|
|
CVStream* pStream = &m_pStream[0];
|
|
UINT Stride = pStream->m_dwStride;
|
|
|
|
// Get memory pointer for the input stream 0
|
|
m_pConvObj->m_pInpStreamMem[0] = pStream->Data() + StartVertex * Stride;
|
|
if (Stride != m_pConvObj->m_pOutStream[0]->m_dwStride &&
|
|
m_pConvObj->m_pOutStream[0]->GetPrimitiveBase() != 0)
|
|
{
|
|
m_pDDI->FlushStates();
|
|
m_pConvObj->m_pOutStream[0]->Reset();
|
|
m_pConvObj->m_FirstVertex = 0;
|
|
}
|
|
// Allocate space in the corresponding output stream and get its
|
|
// memory pointer
|
|
m_pConvObj->m_pOutStreamMem[0] = m_pConvObj->m_pOutStream[0]->Lock(nOutVertices * Stride, m_pDDI);
|
|
m_pConvObj->m_pOutStream[0]->SetVertexSize(Stride);
|
|
m_pConvObj->m_FirstVertex = m_pConvObj->m_pOutStream[0]->GetPrimitiveBase();
|
|
m_pConvObj->m_FirstVertex /= Stride;
|
|
m_pConvObj->m_pOutStream[0]->SkipVertices(nOutVertices);
|
|
// Save the old vertex buffer
|
|
UINT tmp;
|
|
GetStreamSource(0, (IDirect3DVertexBuffer8**)&m_pConvObj->m_InpStream[0].m_pVB, &tmp);
|
|
// Set new vertex buffer as input stream
|
|
SetStreamSource(0, m_pConvObj->m_pOutStream[0]->m_pVB, Stride);
|
|
|
|
// Initialize vertex elements pointers based on the FVF handle
|
|
|
|
UINT VertexOffset = 0;
|
|
CVertexPointer::NumUsedElements = 0;
|
|
BYTE* pinp = m_pConvObj->m_pInpStreamMem[0];
|
|
BYTE* pout = m_pConvObj->m_pOutStreamMem[0];
|
|
// Position
|
|
m_pConvObj->m_PositionIndex = CVertexPointer::NumUsedElements;
|
|
m_pConvObj->m_InpVertex.Stride[CVertexPointer::NumUsedElements] = Stride;
|
|
m_pConvObj->m_InpVertex.pData[CVertexPointer::NumUsedElements] = pinp;
|
|
m_pConvObj->m_OutVertex.pData[CVertexPointer::NumUsedElements] = pout;
|
|
VertexOffset += 3*sizeof(float);
|
|
CVertexPointer::DataType[CVertexPointer::NumUsedElements] = D3DVSDT_FLOAT3;
|
|
CVertexPointer::NumUsedElements++;
|
|
// Data after position
|
|
switch (m_dwCurrentShaderHandle & D3DFVF_POSITION_MASK)
|
|
{
|
|
case D3DFVF_XYZB1:
|
|
m_pConvObj->m_InpVertex.Stride[CVertexPointer::NumUsedElements] = Stride;
|
|
m_pConvObj->m_InpVertex.pData[CVertexPointer::NumUsedElements] = pinp + VertexOffset;
|
|
m_pConvObj->m_OutVertex.pData[CVertexPointer::NumUsedElements] = pout + VertexOffset;
|
|
VertexOffset += sizeof(float);
|
|
CVertexPointer::DataType[CVertexPointer::NumUsedElements] = D3DVSDT_FLOAT1;
|
|
CVertexPointer::NumUsedElements++;
|
|
break;
|
|
case D3DFVF_XYZB2:
|
|
m_pConvObj->m_InpVertex.Stride[CVertexPointer::NumUsedElements] = Stride;
|
|
m_pConvObj->m_InpVertex.pData[CVertexPointer::NumUsedElements] = pinp + VertexOffset;
|
|
m_pConvObj->m_OutVertex.pData[CVertexPointer::NumUsedElements] = pout + VertexOffset;
|
|
VertexOffset += sizeof(float) * 2;
|
|
CVertexPointer::DataType[CVertexPointer::NumUsedElements] = D3DVSDT_FLOAT2;
|
|
CVertexPointer::NumUsedElements++;
|
|
break;
|
|
case D3DFVF_XYZB3:
|
|
m_pConvObj->m_InpVertex.Stride[CVertexPointer::NumUsedElements] = Stride;
|
|
m_pConvObj->m_InpVertex.pData[CVertexPointer::NumUsedElements] = pinp + VertexOffset;
|
|
m_pConvObj->m_OutVertex.pData[CVertexPointer::NumUsedElements] = pout + VertexOffset;
|
|
VertexOffset += sizeof(float) * 3;
|
|
CVertexPointer::DataType[CVertexPointer::NumUsedElements] = D3DVSDT_FLOAT3;
|
|
CVertexPointer::NumUsedElements++;
|
|
break;
|
|
case D3DFVF_XYZB4:
|
|
m_pConvObj->m_InpVertex.Stride[CVertexPointer::NumUsedElements] = Stride;
|
|
m_pConvObj->m_InpVertex.pData[CVertexPointer::NumUsedElements] = pinp + VertexOffset;
|
|
m_pConvObj->m_OutVertex.pData[CVertexPointer::NumUsedElements] = pout + VertexOffset;
|
|
VertexOffset += sizeof(float) * 4;
|
|
CVertexPointer::DataType[CVertexPointer::NumUsedElements] = D3DVSDT_FLOAT4;
|
|
CVertexPointer::NumUsedElements++;
|
|
break;
|
|
case D3DFVF_XYZB5:
|
|
m_pConvObj->m_InpVertex.Stride[CVertexPointer::NumUsedElements] = Stride;
|
|
m_pConvObj->m_InpVertex.pData[CVertexPointer::NumUsedElements] = pinp + VertexOffset;
|
|
m_pConvObj->m_OutVertex.pData[CVertexPointer::NumUsedElements] = pout + VertexOffset;
|
|
VertexOffset += sizeof(float) * 4;
|
|
CVertexPointer::DataType[CVertexPointer::NumUsedElements] = D3DVSDT_FLOAT4;
|
|
CVertexPointer::NumUsedElements++;
|
|
m_pConvObj->m_InpVertex.Stride[CVertexPointer::NumUsedElements] = Stride;
|
|
m_pConvObj->m_InpVertex.pData[CVertexPointer::NumUsedElements] = pinp + VertexOffset;
|
|
m_pConvObj->m_OutVertex.pData[CVertexPointer::NumUsedElements] = pout + VertexOffset;
|
|
VertexOffset += sizeof(float) * 1;
|
|
CVertexPointer::DataType[CVertexPointer::NumUsedElements] = D3DVSDT_FLOAT1;
|
|
CVertexPointer::NumUsedElements++;
|
|
break;
|
|
}
|
|
//Normal
|
|
m_pConvObj->m_NormalIndex = CVertexPointer::NumUsedElements;
|
|
m_pConvObj->m_InpVertex.Stride[CVertexPointer::NumUsedElements] = Stride;
|
|
m_pConvObj->m_InpVertex.pData[CVertexPointer::NumUsedElements] = pinp + VertexOffset;
|
|
m_pConvObj->m_OutVertex.pData[CVertexPointer::NumUsedElements] = pout + VertexOffset;
|
|
VertexOffset += 3*sizeof(float);
|
|
CVertexPointer::DataType[CVertexPointer::NumUsedElements] = D3DVSDT_FLOAT3;
|
|
CVertexPointer::NumUsedElements++;
|
|
if (m_dwCurrentShaderHandle & D3DFVF_PSIZE)
|
|
{
|
|
m_pConvObj->m_InpVertex.Stride[CVertexPointer::NumUsedElements] = Stride;
|
|
m_pConvObj->m_InpVertex.pData[CVertexPointer::NumUsedElements] = pinp + VertexOffset;
|
|
m_pConvObj->m_OutVertex.pData[CVertexPointer::NumUsedElements] = pout + VertexOffset;
|
|
VertexOffset += sizeof(float);
|
|
CVertexPointer::DataType[CVertexPointer::NumUsedElements] = D3DVSDT_FLOAT1;
|
|
CVertexPointer::NumUsedElements++;
|
|
}
|
|
if (m_dwCurrentShaderHandle & D3DFVF_DIFFUSE)
|
|
{
|
|
m_pConvObj->m_InpVertex.Stride[CVertexPointer::NumUsedElements] = Stride;
|
|
m_pConvObj->m_InpVertex.pData[CVertexPointer::NumUsedElements] = pinp + VertexOffset;
|
|
m_pConvObj->m_OutVertex.pData[CVertexPointer::NumUsedElements] = pout + VertexOffset;
|
|
VertexOffset += sizeof(DWORD);
|
|
CVertexPointer::DataType[CVertexPointer::NumUsedElements] = D3DVSDT_D3DCOLOR;
|
|
CVertexPointer::NumUsedElements++;
|
|
}
|
|
if (m_dwCurrentShaderHandle & D3DFVF_SPECULAR)
|
|
{
|
|
m_pConvObj->m_InpVertex.Stride[CVertexPointer::NumUsedElements] = Stride;
|
|
m_pConvObj->m_InpVertex.pData[CVertexPointer::NumUsedElements] = pinp + VertexOffset;
|
|
m_pConvObj->m_OutVertex.pData[CVertexPointer::NumUsedElements] = pout + VertexOffset;
|
|
VertexOffset += sizeof(DWORD);
|
|
CVertexPointer::DataType[CVertexPointer::NumUsedElements] = D3DVSDT_D3DCOLOR;
|
|
CVertexPointer::NumUsedElements++;
|
|
}
|
|
UINT iTexCount = FVF_TEXCOORD_NUMBER(m_dwCurrentShaderHandle);
|
|
for (UINT i = 0; i < iTexCount; i++)
|
|
{
|
|
switch (D3DFVF_GETTEXCOORDSIZE(m_dwCurrentShaderHandle, i))
|
|
{
|
|
case D3DFVF_TEXTUREFORMAT2:
|
|
m_pConvObj->m_InpVertex.Stride[CVertexPointer::NumUsedElements] = Stride;
|
|
m_pConvObj->m_InpVertex.pData[CVertexPointer::NumUsedElements] = pinp + VertexOffset;
|
|
m_pConvObj->m_OutVertex.pData[CVertexPointer::NumUsedElements] = pout + VertexOffset;
|
|
VertexOffset += sizeof(float) * 2;
|
|
CVertexPointer::DataType[CVertexPointer::NumUsedElements] = D3DVSDT_FLOAT2;
|
|
CVertexPointer::NumUsedElements++;
|
|
break;
|
|
case D3DFVF_TEXTUREFORMAT1:
|
|
m_pConvObj->m_InpVertex.Stride[CVertexPointer::NumUsedElements] = Stride;
|
|
m_pConvObj->m_InpVertex.pData[CVertexPointer::NumUsedElements] = pinp + VertexOffset;
|
|
m_pConvObj->m_OutVertex.pData[CVertexPointer::NumUsedElements] = pout + VertexOffset;
|
|
VertexOffset += sizeof(float);
|
|
CVertexPointer::DataType[CVertexPointer::NumUsedElements] = D3DVSDT_FLOAT1;
|
|
CVertexPointer::NumUsedElements++;
|
|
break;
|
|
case D3DFVF_TEXTUREFORMAT3:
|
|
m_pConvObj->m_InpVertex.Stride[CVertexPointer::NumUsedElements] = Stride;
|
|
m_pConvObj->m_InpVertex.pData[CVertexPointer::NumUsedElements] = pinp + VertexOffset;
|
|
m_pConvObj->m_OutVertex.pData[CVertexPointer::NumUsedElements] = pout + VertexOffset;
|
|
VertexOffset += sizeof(float) * 3;
|
|
CVertexPointer::DataType[CVertexPointer::NumUsedElements] = D3DVSDT_FLOAT3;
|
|
CVertexPointer::NumUsedElements++;
|
|
break;
|
|
case D3DFVF_TEXTUREFORMAT4:
|
|
m_pConvObj->m_InpVertex.Stride[CVertexPointer::NumUsedElements] = Stride;
|
|
m_pConvObj->m_InpVertex.pData[CVertexPointer::NumUsedElements] = pinp + VertexOffset;
|
|
m_pConvObj->m_OutVertex.pData[CVertexPointer::NumUsedElements] = pout + VertexOffset;
|
|
VertexOffset += sizeof(float) * 4;
|
|
CVertexPointer::DataType[CVertexPointer::NumUsedElements] = D3DVSDT_FLOAT4;
|
|
CVertexPointer::NumUsedElements++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Check if we can batch to the same output vertex streams.
|
|
// All output streams must have the same stride as declaration, the
|
|
// same primitive base and enough space to store output vertices
|
|
CVStreamDecl* pStreamDecl = m_pCurrentShader->m_Declaration.m_pActiveStreams;
|
|
BOOL bFirstStream = TRUE;
|
|
UINT FirstVertexIndex = 0;
|
|
while (pStreamDecl)
|
|
{
|
|
UINT si = pStreamDecl->m_dwStreamIndex;
|
|
UINT Stride = pStreamDecl->m_dwStride;
|
|
UINT PrimitiveBase = m_pConvObj->m_pOutStream[si]->GetPrimitiveBase();
|
|
PrimitiveBase /= Stride;
|
|
if (bFirstStream)
|
|
{
|
|
FirstVertexIndex = PrimitiveBase;
|
|
m_pConvObj->m_FirstVertex = FirstVertexIndex;
|
|
}
|
|
if ((m_pConvObj->m_pOutStream[si]->m_dwStride != Stride &&
|
|
PrimitiveBase != 0) || FirstVertexIndex != PrimitiveBase ||
|
|
!m_pConvObj->m_pOutStream[si]->CheckFreeSpace(nOutVertices * Stride))
|
|
{
|
|
m_pDDI->FlushStates();
|
|
for (int i=0; i < __NUMELEMENTS; i++)
|
|
{
|
|
m_pConvObj->m_pOutStream[i]->Reset();
|
|
}
|
|
m_pConvObj->m_FirstVertex = 0;
|
|
}
|
|
bFirstStream = FALSE;
|
|
pStreamDecl = (CVStreamDecl*)pStreamDecl->m_pNext;
|
|
}
|
|
|
|
// Build an array of all vertex elements used in the shader by going
|
|
// through all streams and elements inside each stream.
|
|
|
|
CVDeclaration* pDecl = &m_pCurrentShader->m_Declaration;
|
|
pStreamDecl = m_pCurrentShader->m_Declaration.m_pActiveStreams;
|
|
UINT ve = 0; // Vertex element index
|
|
bFirstStream = TRUE;
|
|
while (pStreamDecl)
|
|
{
|
|
UINT si = pStreamDecl->m_dwStreamIndex;
|
|
UINT Stride = pStreamDecl->m_dwStride;
|
|
CVStream * pStream = &m_pStream[si];
|
|
m_pConvObj->m_pInpStreamMem[si] = pStream->Data() + StartVertex * Stride;
|
|
// Allocate space in the corresponding output stream and get
|
|
// memory pointer
|
|
m_pConvObj->m_pOutStreamMem[si] = m_pConvObj->m_pOutStream[si]->Lock(nOutVertices * Stride, m_pDDI);
|
|
m_pConvObj->m_pOutStream[si]->SetVertexSize(Stride);
|
|
m_pConvObj->m_pOutStream[si]->SkipVertices(nOutVertices);
|
|
// Save the old vertex buffer
|
|
UINT tmp;
|
|
GetStreamSource(si, (IDirect3DVertexBuffer8**)&m_pConvObj->m_InpStream[si].m_pVB, &tmp);
|
|
// Set new vertex buffer as input
|
|
SetStreamSource(si, m_pConvObj->m_pOutStream[si]->m_pVB, Stride);
|
|
|
|
for (DWORD i=0; i < pStreamDecl->m_dwNumElements; i++)
|
|
{
|
|
if (i >= __NUMELEMENTS)
|
|
{
|
|
D3D_THROW_FAIL("Declaration is using too many elements");
|
|
}
|
|
// This is the array we build
|
|
CVElement* pVerElem = &pStreamDecl->m_Elements[i];
|
|
CVertexPointer::Stride[ve] = Stride;
|
|
CVertexPointer::DataType[ve] = pVerElem->m_dwDataType;
|
|
m_pConvObj->m_InpVertex.pData[ve] = m_pConvObj->m_pInpStreamMem[si] + pVerElem->m_dwOffset;
|
|
m_pConvObj->m_OutVertex.pData[ve] = m_pConvObj->m_pOutStreamMem[si] + pVerElem->m_dwOffset;
|
|
if (pVerElem->m_dwRegister == D3DVSDE_POSITION)
|
|
m_pConvObj->m_PositionIndex = ve;
|
|
else
|
|
if (pVerElem->m_dwRegister == D3DVSDE_NORMAL)
|
|
m_pConvObj->m_NormalIndex = ve;
|
|
ve++;
|
|
}
|
|
pStreamDecl = (CVStreamDecl*)pStreamDecl->m_pNext;
|
|
}
|
|
pDecl->m_dwNumElements = ve;
|
|
CVertexPointer::NumUsedElements = ve;
|
|
}
|
|
}
|