windows-nt/Source/XPSP1/NT/multimedia/directx/dxg/d3d8/tnl/pvone.mcp

1430 lines
51 KiB
Plaintext
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*============================ ==============================================;
*
* Copyright (C) 1998 Microsoft Corporation. All Rights Reserved.
*
* File: pvone.mcp
* Content: Clipping and vertex processing in one loop
*
***************************************************************************/
#include "pch.cpp"
#pragma hdrstop
include(`pvvid.mh') dnl
extern DWORD g_DebugFlags; // defined in pvvid.mcp
//--------------------------------------------------------------------------
// Bits describing a vertex
// Set if vertex participates in a completely inside triangle
const __VERTEX_IN_INSIDETRIANGLE = 1;
const __2_VERTEX_IN_INSIDETRIANGLE = 1 << 5;
const __3_VERTEX_IN_INSIDETRIANGLE = 1 << 10;
// Set if vertex participates in a triangle, which requires clipping
const __VERTEX_IN_CLIPTRIANGLE = 2;
const __2_VERTEX_IN_CLIPTRIANGLE = 2 << 5;
const __3_VERTEX_IN_CLIPTRIANGLE = 2 << 10;
// The following two bits are set for the first vertex of every triangle
// in the triangle strip.
const __TRIANGLE_OUTSIDE = 4;
const __TRIANGLE_CLIP = 8;
const __TRIANGLE_INSIDE = 16;
const __3_TRIANGLE_OUTSIDE = 4 << 10;
const __3_TRIANGLE_CLIP = 8 << 10;
const __2_TRIANGLE_OUTSIDE = 4 << 5;
const __2_TRIANGLE_CLIP = 8 << 5;
const __3_TRIANGLE_INSIDE = 16 << 10;
const __2_TRIANGLE_INSIDE = 16 << 5;
//--------------------------------------------------------------------------
// TransformVertexMakeClipCode
//
// Transforms vertex coordinates to the clipping space and computes clip code
//
// Arguments:
// pInp - input pointer (D3DVERTEX)
// pOut - output pointer (ClipVertex)
// Output:
// Returns clip code
// Transformed coordinates are written to the clip vertex (hx, hy, hz, hw, clip)
//
DWORD TransformVertexMakeClipCode(D3DFE_PROCESSVERTICES *pv, D3DVERTEX* pInp,
D3DVALUE* pWeights, BYTE* pMatrixIndices, ClipVertex* pOut)
{
D3DVALUE x,y,z,w;
DWORD clip;
d_TransformVertex(1, pInp, (&pv->mCTM[0]), x,y,z,w, pWeights, pMatrixIndices)
d_ComputeClipCode(1)
if (pv->dwDeviceFlags & D3DDEV_GUARDBAND)
{
d_ComputeClipCodeGB(2)
}
pOut->hx = x;
pOut->hy = y;
pOut->hz = z;
pOut->hw = w;
pOut->clip = clip;
return clip;
}
//--------------------------------------------------------------------------
// ComputeScreenCoordinates
//
// Computes screen coordinates for the ClipVertex
// Arguments:
// pOut - pointer to the ClipVertex
//
inline void ComputeScreenCoordinates(D3DFE_PROCESSVERTICES *pv, ClipVertex* pInp, D3DVECTORH *pOut)
{
D3DVALUE xs, ys, zs, w;
w = D3DVAL(1)/pInp->hw;
d_ComputeScreenCoordinatesNoOutput(1,pInp->hx,pInp->hy,pInp->hz,w,xs,ys,zs)
pOut->x = xs;
pOut->y = ys;
pOut->z = zs;
pOut->w = w;
}
//--------------------------------------------------------------------------
// Update input and output pointers to start from dwStartVertexIndex
//
inline void SetInputAndOutputPointers(D3DFE_PROCESSVERTICES *pv, DWORD dwStartVertexIndex)
{
// Update output pointer
pv->lpvOut = (char*)pv->lpvOut + dwStartVertexIndex * pv->dwOutputSize;
// Update input pointers
pv->position.lpvData = (char*)pv->position.lpvData + dwStartVertexIndex * pv->position.dwStride;
if (pv->dwDeviceFlags & D3DDEV_STRIDE)
{
pv->normal.lpvData = (char*)pv->normal.lpvData + dwStartVertexIndex * pv->normal.dwStride;
pv->diffuse.lpvData = (char*)pv->diffuse.lpvData + dwStartVertexIndex * pv->diffuse.dwStride;
pv->specular.lpvData = (char*)pv->specular.lpvData + dwStartVertexIndex * pv->specular.dwStride;
for (DWORD i=0; i < pv->nTexCoord; i++)
pv->textures[i].lpvData = (char*)pv->textures[i].lpvData +
dwStartVertexIndex * pv->textures[i].dwStride;
}
}
dnl//--------------------------------------------------------------------------
dnl// d_TransformVertexMakeClipCode
dnl//
dnl// Transforms vertex coordinates to the clipping space and computes clip code
dnl//
dnl// Arguments:
dnl// $1 - margin count
dnl// $2 - input pointer (D3DVERTEX)
dnl// $3 - output pointer (ClipVertex)
dnl// $4 - pointer to weights
dnl// $5 - pointer to matrix indices
dnl// Output:
dnl// x,y,z,w should be defined as float
dnl// clip should be defined as DWORD
dnl//
define(`d_TransformVertexMakeClipCode',`dnl
d_empty_($1)d_TransformVertex($1, $2, m, x,y,z,w, $4, $5)
d_margin($1)d_ComputeClipCode($1)
d_margin($1)if (pv->dwDeviceFlags & D3DDEV_GUARDBAND)
d_margin($1){
d_margin($1) d_ComputeClipCodeGB($1+1)
d_margin($1)}
d_margin($1)$3->hx = x;
d_margin($1)$3->hy = y;
d_margin($1)$3->hz = z;
d_margin($1)$3->hw = w;
d_margin($1)$3->clip = clip;') dnl
dnl//--------------------------------------------------------------------------
dnl// Copies processed vertex to the output FVF buffer
dnl//
dnl// Input:
dnl// $1 - Margin count
dnl// $2 - output buffer
dnl// Notes:
dnl// Output vertex pointer is moved to the next vertex
dnl//
define(`d_CopyToOutputVertex',`dnl
d_empty_($1)// copy to the output vertex
d_margin($1)$2->sx = x;
d_margin($1)$2->sy = y;
d_margin($1)$2->sz = z;
d_margin($1)$2->rhw = w;
d_margin($1)DWORD *pOut = (DWORD*)((char*)$2 + pv->diffuseOffsetOut);
d_margin($1)if (pv->dwVIDOut & D3DFVF_DIFFUSE)
d_margin($1) *pOut++ = pv->lighting.outDiffuse;
d_margin($1)if (pv->dwVIDOut & D3DFVF_SPECULAR)
d_margin($1) *pOut++ = pv->lighting.outSpecular;
d_margin($1)d_CopyTextureCoord($1, pOut)
d_margin($1)$2 = (D3DTLVERTEX*)((BYTE*)$2 + pv->dwOutputSize);')dnl
dnl//--------------------------------------------------------------------------
dnl// Copies processed vertex to the clip vertex
dnl//
dnl// Input:
dnl// $1 - Margin count
dnl// $2 - clip vertex address
dnl//
define(`d_CopyToClipVertex',`dnl
d_empty_($1)if (($2->clip & pv->dwClipMaskOffScreen) == 0)
d_margin($1){ // Copy screen coordinates
d_margin($1) $2->sx = x;
d_margin($1) $2->sy = y;
d_margin($1) $2->sz = z;
d_margin($1) $2->rhw = w;
d_margin($1)}
d_margin($1)$2->color = pv->lighting.outDiffuse;
d_margin($1)$2->specular= pv->lighting.outSpecular;
d_margin($1)d_CopyTextureCoord($1, $2->tex)') dnl
dnl//--------------------------------------------------------------------------
define(`d_ProcessPrimitive',`dnl
d_empty_($1){
d_margin($1) pv->pGeometryFuncs->ProcessVertices(pv);
d_margin($1) if (pv->dwClipIntersection)
d_margin($1) return D3D_OK;
d_margin($1) return (DoDrawPrimitive(pv));
d_margin($1)}')dnl
//---------------------------------------------------------------------
// Clipping and lighting a non-indexed triangle list in one pass
//
HRESULT D3DFE_PVFUNCSI::ProcessTriangleList(D3DFE_PROCESSVERTICES *pv)
{
#ifdef DEBUG_PIPELINE
if (g_DebugFlags & __DEBUG_ONEPASS)
d_ProcessPrimitive(1)
#endif
if (pv->dwDeviceFlags & D3DDEV_DONOTCLIP)
d_ProcessPrimitive(1)
pv->dwFirstClippedVertex = 0xFFFFFFFF;
pv->dwFlags |= D3DPV_ONEPASSCLIPPING;
pv->pGeometryFuncs->ProcessVertices(pv);
int primitiveCount = 0; // Number of triangles in the current unclipped part
BYTE *startVertex = (BYTE*)pv->lpvOut;
if (pv->dwFirstClippedVertex != 0xFFFFFFFF)
{
if (pv->dwFirstClippedVertex > 3)
{
// Compute number of unclipped primitives
primitiveCount = pv->dwFirstClippedVertex / 3;
// Index of the first vertex to process
DWORD dwStartVertexIndex = primitiveCount * 3;
DWORD dwVertexCount = dwStartVertexIndex;
// Compute new number of primitives to process
pv->dwNumPrimitives = pv->dwNumPrimitives - primitiveCount;
SetInputAndOutputPointers(pv, dwStartVertexIndex);
}
}
else
{
pv->dwFlags &= ~D3DPV_ONEPASSCLIPPING;
if (pv->dwClipIntersection)
return D3D_OK;
return (DoDrawPrimitive(pv));
}
HRESULT ret = D3D_OK;
D3DTLVERTEX*lpOutVer = (D3DTLVERTEX*)pv->lpvOut;
ClipVertex cv[3];
DWORD dwClipMaskOffScreen = pv->dwClipMaskOffScreen;
LPD3DMATRIXI m = &pv->mCTM[0];
D3DLIGHTINGELEMENT EyeSpaceData;
d_Setup()
cv[0].next = &cv[1];
cv[1].next = &cv[2];
for (DWORD i = pv->dwNumPrimitives; i; i--)
{
ClipVertex *out = cv;
D3DVERTEX *lpInpVer = (D3DVERTEX*)in;
D3DVALUE *pWeights = inWeights;
BYTE *pMatrixIndices = inMatrixIndices;
// First we transform three vertices and compute the clip codes
dwClipUnion = 0;
dwClipIntersection = ~0;
for (DWORD i=3; i; i--)
{
DWORD clip = TransformVertexMakeClipCode(pv, lpInpVer, pWeights, pMatrixIndices, out);
out++;
dwClipUnion |= clip;
dwClipIntersection &= clip;
lpInpVer = (D3DVERTEX*)((BYTE*)lpInpVer + dwInpVerSize);
pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
}
pv->dwClipUnion |= dwClipUnion;
pv->dwClipIntersection &= dwClipIntersection;
// Now we can check where the triangle is
if (!dwClipIntersection)
{
if (!(dwClipUnion & dwClipMaskOffScreen))
{ // The triangle does not require clipping
ClipVertex *lpXfmVer = cv;
primitiveCount++;
for (DWORD i=3; i; i--)
{
D3DVALUE x,y,z,w;
w = D3DVAL(1)/lpXfmVer->hw;
d_ComputeScreenCoordinates(5, lpXfmVer->hx, lpXfmVer->hy, lpXfmVer->hz, w, lpOutVer)
d_DoLightingAndFog(5, in, inNormal, inDiffuse, inSpecular, lpOutVer, inWeights, inMatrixIndices)
D3DVALUE *pOutTexture = (D3DVALUE*)((BYTE*)lpOutVer + pv->texOffsetOut);
d_CopyTextureCoordUpdateInputPointers(5, pOutTexture)
lpXfmVer = lpXfmVer->next;
lpOutVer = (D3DTLVERTEX*)((BYTE*)lpOutVer + dwOutVerSize);
}
}
else
{ // The triangle requires clipping
if (primitiveCount)
{ // first draw the ones that didn't need clipping
DWORD vertexCount = primitiveCount*3;
ret = DRAW_PRIM(pv, D3DPT_TRIANGLELIST, startVertex,
vertexCount, primitiveCount);
startVertex = (BYTE*)lpOutVer;
if (ret)
goto l_Exit;
}
primitiveCount = 0;
ClipVertex *lpXfmVer = cv;
for (DWORD i=3; i; i--)
{
if ((lpXfmVer->clip & dwClipMaskOffScreen) == 0)
{
float x,y,z;
float w = D3DVAL(1)/lpXfmVer->hw;
d_ComputeScreenCoordinates(6, lpXfmVer->hx, lpXfmVer->hy, lpXfmVer->hz, w, lpXfmVer)
}
d_ComputeOutputColors(5, in, inNormal, inDiffuse, inSpecular, inWeights, inMatrixIndices)
if (pv->dwVIDOut & D3DFVF_DIFFUSE)
lpXfmVer->color = pv->lighting.outDiffuse;
if (pv->dwVIDOut & D3DFVF_SPECULAR)
lpXfmVer->specular = pv->lighting.outSpecular;
d_CopyTextureCoordUpdateInputPointers(5, lpXfmVer->tex)
lpXfmVer++;
}
ret = Clip(pv, &cv[0], &cv[1], &cv[2]);
if (ret != D3D_OK)
goto l_Exit;
}
}
else
{ // Triangle is outside
// Update input pointers
d_UpdateInputPointers(3)
d_UpdateInputPointers(3)
d_UpdateInputPointers(3)
}
}
// draw final batch, if any
if (primitiveCount)
{
DWORD dwVertexCount = primitiveCount*3;
ret = DRAW_PRIM(pv, D3DPT_TRIANGLELIST, startVertex,
dwVertexCount, primitiveCount);
}
l_Exit:
return ret;
}
//---------------------------------------------------------------------
// Clipping and lighting a non-indexed triangle fan in one pass
//
HRESULT D3DFE_PVFUNCSI::ProcessTriangleFan(D3DFE_PROCESSVERTICES *pv)
{
#ifdef DEBUG_PIPELINE
if (g_DebugFlags & __DEBUG_ONEPASS)
d_ProcessPrimitive(1)
#endif
if (pv->dwDeviceFlags & D3DDEV_DONOTCLIP)
d_ProcessPrimitive(1)
// TRUE, if the current triangle is the first in the unclipped part of the primitive
BOOL bFirstInsideTriangle = TRUE;
// Index of a vertex to start processing from
DWORD dwStartVertexIndex = 0;
int primitiveCount = 0; // Number of triangles in the current unclipped part
// Start vertex for the current unclipped part of the triangle fan
BYTE *startVertex = (BYTE*)pv->lpvOut;
// Current pointer to the output vertex buffer
D3DTLVERTEX*lpOutVer = (D3DTLVERTEX*)startVertex;
DWORD dwVertexCount = 1; // Number of processed vertices (first vertex is processed
// outside of the vretx loop)
DWORD dwInsideVertexCount= 0; // Number of vertices, put to the lpVout buffer
pv->dwFirstClippedVertex = 0xFFFFFFFF;
pv->dwFlags |= D3DPV_ONEPASSCLIPPING;
pv->pGeometryFuncs->ProcessVertices(pv);
if (pv->dwFirstClippedVertex == 0xFFFFFFFF)
{
pv->dwFlags &= ~D3DPV_ONEPASSCLIPPING;
if (pv->dwClipIntersection)
return D3D_OK;
return (DoDrawPrimitive(pv));
}
else
{
if (pv->dwFirstClippedVertex >= 3)
{
bFirstInsideTriangle = FALSE; // First vertex is already copied to the output
// We process again the last unclipped vertex
dwStartVertexIndex = pv->dwFirstClippedVertex - 1;
// Update output pointer
pv->lpvOut = (char*)pv->lpvOut + dwStartVertexIndex * pv->dwOutputSize;
lpOutVer = (D3DTLVERTEX*)pv->lpvOut;
primitiveCount = dwStartVertexIndex - 2;
dwVertexCount += pv->dwFirstClippedVertex;
dwInsideVertexCount += pv->dwFirstClippedVertex;
}
}
HRESULT ret;
ClipVertex cv1;
ClipVertex *cv2; // Vertex to process
ClipVertex *cv3; // Vertex to transform
ClipVertex *cv; // Previous to cv2. Used for clipping
D3DVERTEX *lpInpStart; // Next input vertex to transform
D3DVALUE *pWeights; // Vertex weights. Should be in ssync with lpInpStart
BYTE *pMatrixIndices; // Vertex weights. Should be in ssync with lpInpStart
DWORD dwClipMaskOffScreen = pv->dwClipMaskOffScreen; // Mask for guard band bits
LPD3DMATRIXI m = &pv->mCTM[0];
// Vertex flags has 5 bits per vertex
// Bits 0 - 4 - vertex cv2
// Bits 5 - 9 - vertex cv3
DWORD vf = 0;
D3DLIGHTINGELEMENT EyeSpaceData;
d_Setup()
lpInpStart = (D3DVERTEX*)in;
pWeights = (D3DVALUE*)inWeights;
pMatrixIndices = (BYTE*)inMatrixIndices;
// This is the loop count. We use "+1", because the processed vertex is behind the
// transformed one.
DWORD i = pv->dwNumPrimitives + 1;
{
// Transform, process and keep the first vertex
DWORD clip = TransformVertexMakeClipCode(pv, lpInpStart, pWeights, pMatrixIndices, &cv1);
// PSGP could transform vertices with different precision. It is possible that
// PSGP detects that a vertex is inside, but we here mark it as the outside.
// We force the clipping code to be zero in case when we re-transform vertices
if (pv->dwFirstClippedVertex >= 3)
{
clip = 0;
}
if ((clip & dwClipMaskOffScreen) == 0)
{
ComputeScreenCoordinates(pv, &cv1, (D3DVECTORH*)&cv1.sx);
}
d_ComputeOutputColors(2, in, inNormal, inDiffuse, inSpecular, inWeights, inMatrixIndices)
cv1.color = pv->lighting.outDiffuse;
cv1.specular = pv->lighting.outSpecular;
d_CopyTextureCoordUpdateInputPointers(2, ((DWORD*)(cv1.tex)))
lpInpStart = (D3DVERTEX*)in;
pWeights = inWeights;
pMatrixIndices = inMatrixIndices;
}
cv2 = &pv->clipVer[0]; // Next output vertex for process
cv3 = &pv->clipVer[1]; // Next output vertex for transform
// In case when there were unclipped part, we have to update pointers
// to start from dwStartVertex
if (pv->dwFirstClippedVertex >= 3)
{
// Update input pointers
in = (D3DVECTOR*)((char*)pv->position.lpvData + dwStartVertexIndex * pv->position.dwStride);
if (pv->dwDeviceFlags & D3DDEV_STRIDE)
{
inWeights = (D3DVALUE*)((char*)pv->weights.lpvData + dwStartVertexIndex * pv->weights.dwStride);
inMatrixIndices = (BYTE*)pv->matrixIndices.lpvData + dwStartVertexIndex * pv->matrixIndices.dwStride;
inNormal = (D3DVECTOR*)((char*)pv->normal.lpvData + dwStartVertexIndex * pv->normal.dwStride);
inDiffuse = (DWORD*)((char*)pv->diffuse.lpvData + dwStartVertexIndex * pv->diffuse.dwStride);
inSpecular = (DWORD*)((char*)pv->specular.lpvData + dwStartVertexIndex * pv->specular.dwStride);
for (DWORD i=0; i < pv->nTexCoord; i++)
inTexture[i] = (D3DVALUE*)((char*)pv->textures[i].lpvData +
dwStartVertexIndex * pv->textures[i].dwStride);
}
else
{
inWeights = (D3DVALUE*) ((char*)in + 3*sizeof(float));
inMatrixIndices = (BYTE*)(inWeights + pv->dwNumVerBlends - 1);
inNormal = (D3DVECTOR*) ((char*)in + pv->normalOffset);
inDiffuse = (DWORD*) ((char*)in + pv->diffuseOffset);
inSpecular = (DWORD*) ((char*)in + pv->specularOffset);
inTexture[0] = (D3DVALUE*) ((char*)in + pv->texOffset);
}
// Process the last unclipped vertex and copy it to the cv2
// This vertex will be copied to the output buffer later
TransformVertexMakeClipCode(pv, (D3DVERTEX*)in, inWeights, inMatrixIndices, cv2);
// Transformed vertex is ahead by one vertex
lpInpStart = (D3DVERTEX*)((BYTE*)in + dwInpVerSize);
pWeights = (D3DVALUE*)((BYTE*)inWeights + pv->weights.dwStride);
pMatrixIndices = inMatrixIndices + pv->matrixIndices.dwStride;
i = i-pv->dwFirstClippedVertex + 2; // New loop count
cv2->clip = 0; // Fixes potential PSGP precision problem
goto l_InsideLoop;
}
// Transformed vertex will be ahead of the processed one, because we want
// to know where is the triangle when processing a vertex
{
TransformVertexMakeClipCode(pv, lpInpStart, pWeights, pMatrixIndices, cv2);
lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
}
dwClipUnion |= cv1.clip | cv2->clip;
dwClipIntersection &= cv1.clip & cv2->clip;
float x,y,z,w;
int clip;
l_ClippedLoop:
d_TransformVertexMakeClipCode(1, lpInpStart, cv3, pWeights, pMatrixIndices)
dwClipUnion |= clip;
dwClipIntersection &= clip;
l_ClippedLoop2:
// Set status for cv1, cv2, cv3 vertices based on their clip codes
if (!(cv1.clip & cv2->clip & cv3->clip))
{
if (!((cv1.clip | cv2->clip | cv3->clip) & dwClipMaskOffScreen))
vf |= __VERTEX_IN_INSIDETRIANGLE |__2_VERTEX_IN_INSIDETRIANGLE |
__2_TRIANGLE_INSIDE;
else
vf |= __VERTEX_IN_CLIPTRIANGLE | __2_VERTEX_IN_CLIPTRIANGLE |
__2_TRIANGLE_CLIP;
}
else
vf |= __2_TRIANGLE_OUTSIDE;
l_ClippedLoopProcessOnly:
if ((cv2->clip & pv->dwClipMaskOffScreen) == 0)
{ // vertex is inside the guardband or frustum
// Compute screen coordinates
w = D3DVAL(1)/cv2->hw;
d_ComputeScreenCoordinatesNoOutput(2, cv2->hx, cv2->hy, cv2->hz, w, x,y,z)
}
if (vf & (__VERTEX_IN_INSIDETRIANGLE | __VERTEX_IN_CLIPTRIANGLE))
{
// Compute colors
d_ComputeOutputColors(2, in, inNormal, inDiffuse, inSpecular, inWeights, inMatrixIndices)
}
if (vf & __VERTEX_IN_INSIDETRIANGLE)
{
if (vf & __TRIANGLE_OUTSIDE)
{
if (primitiveCount > 0)
{
DWORD dwVerCount = primitiveCount+2;
// Draw batched primitive
if (dwInsideVertexCount < dwVertexCount)
{
ret = DRAW_PRIM(pv, D3DPT_TRIANGLEFAN, startVertex,
dwVerCount, primitiveCount);
if (ret != D3D_OK)
goto l_Exit;
// Prepare for the next part of the primitive
startVertex += dwVerCount * pv->dwOutputSize;
}
else
{
// Suppose we have a fan with 5 vertices. When there is the
// following sequence of triangles:
// "inside" - "outside" - "inside", 6 vertices will be put to
// the vertex buffer, but space was allocated only for 5.
// To prevent similar cases draw the previous primitive as clipped
// and re-use vertex buffer space
pv->dwFlags |= D3DPV_NONCLIPPED;
ret = DRAW_CLIPPED_PRIM(pv, D3DPT_TRIANGLEFAN, startVertex,
dwVerCount, primitiveCount);
pv->dwFlags &= ~D3DPV_NONCLIPPED;
dwInsideVertexCount -= dwVerCount;
lpOutVer = (D3DTLVERTEX*)startVertex;
if (ret != D3D_OK)
goto l_Exit;
}
primitiveCount = 0;
bFirstInsideTriangle = TRUE;
}
}
if (bFirstInsideTriangle)
{
// For the first completely inside triangle we have to
// write the first vertex to the output
MAKE_TL_VERTEX_FVF(pv, (BYTE*)lpOutVer, &cv1);
lpOutVer = (D3DTLVERTEX*)((BYTE*)lpOutVer + pv->dwOutputSize);
bFirstInsideTriangle = FALSE;
dwInsideVertexCount++;
}
d_CopyToOutputVertex(2, lpOutVer)
dwInsideVertexCount++;
}
if (vf & __VERTEX_IN_CLIPTRIANGLE)
{
d_CopyToClipVertex(2, cv2)
}
if (vf & __TRIANGLE_INSIDE)
{ // Triangle is inside the frustum
primitiveCount++;
}
else
{
if (primitiveCount > 0)
{
// Draw batched primitive
DWORD dwVerCount = primitiveCount+2;
ret = DRAW_PRIM(pv, D3DPT_TRIANGLEFAN, startVertex,
dwVerCount, primitiveCount);
if (ret != D3D_OK)
goto l_Exit;
// Prepare for the next part of the primitive
startVertex += dwVerCount * pv->dwOutputSize;
primitiveCount = 0;
bFirstInsideTriangle = TRUE;
}
if (vf & __TRIANGLE_CLIP)
{ // The triangle requires clipping
// Clip prev triangle - cv1, cv, cv2
HRESULT ret = Clip(pv, cv, cv2, &cv1);
if (ret != D3D_OK)
goto l_Exit;
}
}
d_UpdateInputPointers(1);
lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
cv = cv2;
cv2 = cv3;
cv3 = cv3->next;
vf >>= 5;
dwVertexCount++;
if (--i > 1)
{
if (dwClipUnion == 0 && primitiveCount == 1)
{
// If all vertices are inside the frustum we use the optimized loop
goto l_InsideLoop;
}
goto l_ClippedLoop;
}
// For the last vertex we have to do processing only
if (i)
goto l_ClippedLoopProcessOnly;
goto l_Exit;
l_InsideLoop:
d_TransformVertex(1, lpInpStart, m, x,y,z,w, pWeights, pMatrixIndices)
d_ComputeClipCode(1)
cv3->hx = x;
cv3->hy = y;
cv3->hz = z;
cv3->hw = w;
cv3->clip = 0;
if (clip)
goto l_ExitInsideLoop;
lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
l_InsideLoopProcessOnly:
{
w = D3DVAL(1)/cv2->hw;
d_ComputeScreenCoordinatesNoOutput(2, cv2->hx, cv2->hy, cv2->hz, w, x,y,z)
d_ComputeOutputColors(2, in, inNormal, inDiffuse, inSpecular, inWeights, inMatrixIndices)
d_CopyToOutputVertex(2, lpOutVer)
d_UpdateInputPointers(2)
primitiveCount++;
cv2 = cv3;
cv3 = cv3->next;
dwVertexCount++;
dwInsideVertexCount++;
if (--i > 1)
goto l_InsideLoop;
if (i)
goto l_InsideLoopProcessOnly;
}
goto l_Exit;
l_ExitInsideLoop:
{
// For the last transforem vertex (cv3) we computed only clip code
// without guardband
d_ComputeClipCodeGB(2)
cv3->clip = clip;
dwClipUnion |= clip;
// We have to set status for the cv2 vertex
vf |= __VERTEX_IN_INSIDETRIANGLE | __TRIANGLE_INSIDE;
goto l_ClippedLoop2;
}
l_Exit:
if (primitiveCount > 0)
{
// Draw batched primitive
DWORD dwVertexCount = primitiveCount+2;
ret = DRAW_PRIM(pv, D3DPT_TRIANGLEFAN, startVertex,
dwVertexCount, primitiveCount);
}
pv->dwClipUnion = dwClipUnion;
pv->dwClipIntersection = dwClipIntersection;
return D3D_OK;
}
//---------------------------------------------------------------------
// Clipping and lighting a non-indexed triangle strip in one pass
//
// Vertices cv1 cv2 cv3 cv4 cv5
// Next to Next to
// process transform
// | | | |
// * * * * * * * *
//
HRESULT D3DFE_PVFUNCSI::ProcessTriangleStrip(D3DFE_PROCESSVERTICES *pv)
{
#ifdef DEBUG_PIPELINE
if (g_DebugFlags & __DEBUG_ONEPASS)
d_ProcessPrimitive(1)
#endif
if (pv->dwDeviceFlags & D3DDEV_DONOTCLIP)
d_ProcessPrimitive(1)
int primitiveCount; // Number of triangles in the current unclipped part
DWORD dwTriIndex; // Index of the current triangle in the primitive
// Start vertex for the current unclipped part of the triangle strip
BYTE *startVertex = (BYTE*)pv->lpvOut;
// Vertex flags has 5 bits per vertex
// Bits 0 - 4 - vertex cv3
// Bits 5 - 9 - vertex cv4
// Bits 10 - 14 - vertex cv5
DWORD vf = 0;
D3DLIGHTINGELEMENT EyeSpaceData;
pv->dwFirstClippedVertex = 0xFFFFFFFF;
pv->dwFlags |= D3DPV_ONEPASSCLIPPING;
pv->pGeometryFuncs->ProcessVertices(pv);
if (pv->dwFirstClippedVertex == 0xFFFFFFFF)
{
pv->dwFlags &= ~D3DPV_ONEPASSCLIPPING;
if (pv->dwClipIntersection)
return D3D_OK;
return (DoDrawPrimitive(pv));
}
else
{
primitiveCount = 0;
dwTriIndex = 0;
if (pv->dwFirstClippedVertex > 3)
{
DWORD dwStartVertexIndex = pv->dwFirstClippedVertex - 2;
primitiveCount = dwStartVertexIndex - 2;
dwTriIndex = dwStartVertexIndex;
SetInputAndOutputPointers(pv, dwStartVertexIndex);
}
}
HRESULT ret = D3D_OK;
// Current pointer to the output vertex buffer
D3DTLVERTEX*lpOutVer = (D3DTLVERTEX*)pv->lpvOut;
ClipVertex *cv1; // First vertex of delayed clipped triangle
ClipVertex *cv2; // Second vertex of delayed clipped triangle
ClipVertex *cv4;
ClipVertex *cv3; // Vertex to process
ClipVertex *cv5; // Vertex to transform
D3DVERTEX *lpInpStart; // Next input vertex to transform
D3DVALUE *pWeights; // Vertex weights. Should be in ssync with lpInpStart
BYTE *pMatrixIndices; // Vertex weights. Should be in ssync with lpInpStart
DWORD dwClipMaskOffScreen = pv->dwClipMaskOffScreen; // Mask for guard band bits
LPD3DMATRIXI m = &pv->mCTM[0];
DWORD dwNumPrimitives = pv->dwNumPrimitives;
DWORD i;
BOOL bOddStrip = FALSE; // Strip starts from odd vertex index
// (1, 3, 5 ...). First triangle is drawn as
// indexed.
d_Setup()
lpInpStart = (D3DVERTEX*)in;
pWeights = (D3DVALUE*)inWeights;
pMatrixIndices = (BYTE*)inMatrixIndices;
cv1 = NULL;
cv2 = NULL;
cv3 = pv->clipVer;
cv5 = pv->clipVer;
cv4 = cv3->next;
// Transform first two vertices and copy them to the clip buffer
for (DWORD j=2; j; j--)
{
DWORD clip = TransformVertexMakeClipCode(pv, lpInpStart, pWeights, pMatrixIndices, cv5);
dwClipUnion |= clip;
dwClipIntersection &= clip;
cv5 = cv5->next;
lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
}
float x,y,z,w;
int clip;
if (pv->dwFirstClippedVertex > 3)
{
// Force clip code to be zero to fix potential PSGP precision problem
cv3->clip = 0;
cv4->clip = 0;
dwClipIntersection = 0;
// We have to set status for the cv3 and cv4 vertices
vf |= __VERTEX_IN_INSIDETRIANGLE |__2_VERTEX_IN_INSIDETRIANGLE |
__TRIANGLE_INSIDE | __2_TRIANGLE_INSIDE;
goto l_InsideLoop;
}
dwClipUnion |= cv3->clip | cv4->clip;
dwClipIntersection &= cv3->clip & cv4->clip;
l_ClippedLoop:
d_TransformVertexMakeClipCode(1, lpInpStart, cv5, pWeights, pMatrixIndices)
dwClipUnion |= clip;
dwClipIntersection &= clip;
l_ClippedLoop2:
// Set status for cv3, cv4, cv5 vertices based on their clip codes
if (!(cv3->clip & cv4->clip & cv5->clip))
{
if (!((cv3->clip | cv4->clip | cv5->clip) & dwClipMaskOffScreen))
vf |= __VERTEX_IN_INSIDETRIANGLE |__2_VERTEX_IN_INSIDETRIANGLE |
__3_VERTEX_IN_INSIDETRIANGLE | __3_TRIANGLE_INSIDE;
else
vf |= __VERTEX_IN_CLIPTRIANGLE | __2_VERTEX_IN_CLIPTRIANGLE |
__3_VERTEX_IN_CLIPTRIANGLE | __3_TRIANGLE_CLIP;
}
else
vf |= __3_TRIANGLE_OUTSIDE;
l_ProcessOnly:
// When we process a vertex, its status is completely defined
if ((cv3->clip & pv->dwClipMaskOffScreen) == 0)
{ // vertex is inside the guardband or frustum
// Compute screen coordinates
w = D3DVAL(1)/cv3->hw;
d_ComputeScreenCoordinatesNoOutput(2, cv3->hx, cv3->hy, cv3->hz, w, x,y,z)
}
if (vf & (__VERTEX_IN_INSIDETRIANGLE | __VERTEX_IN_CLIPTRIANGLE))
{
// Compute colors
d_ComputeOutputColors(2, in, inNormal, inDiffuse, inSpecular, inWeights, inMatrixIndices)
}
if (vf & __VERTEX_IN_INSIDETRIANGLE)
{
d_CopyToOutputVertex(2, lpOutVer)
}
if (vf & __VERTEX_IN_CLIPTRIANGLE)
{
d_CopyToClipVertex(2, cv3)
}
if (vf & __TRIANGLE_INSIDE)
{
primitiveCount++;
if (primitiveCount == 1)
{
if (dwTriIndex & 1)
// First triangle has an odd index
bOddStrip = TRUE;
else
bOddStrip = FALSE;
}
}
else
{
if (primitiveCount > 0)
{
// Draw batched primitive
if (bOddStrip)
{
// Draw first triangle as indexed triangle
WORD indices[3] = {0, 2, 1};
pv->lpvOut = startVertex;
pv->dwIndexSize = 2;
pv->pDDI->SetIndexedPrimParams(0, 0, 3, pv->pDDI->GetCurrentPrimBase());
ret = DRAW_INDEX_PRIM(pv, D3DPT_TRIANGLELIST, indices, 3, 1);
if (ret != D3D_OK)
goto l_Error;
primitiveCount--;
// Move to the next vertex
startVertex += pv->dwOutputSize;
pv->pDDI->SkipVertices(1);
}
DWORD dwVerCount = primitiveCount+2;
if (primitiveCount > 0)
{
ret = DRAW_PRIM(pv, D3DPT_TRIANGLESTRIP, startVertex,
dwVerCount, primitiveCount);
if (ret != D3D_OK)
goto l_Error;
}
else
{
// When primitiveCount is 0 we still need to skip 2 vertices
// of the odd triangle
pv->pDDI->SkipVertices(2);
}
// Prepare for the next part of the primitive
startVertex += dwVerCount * pv->dwOutputSize;
primitiveCount = 0;
// If next triangle is inside, we have to re-use the last vertex
// of just rendered part of the triangle strip
if (vf & __2_TRIANGLE_INSIDE)
{
pv->pDDI->MovePrimitiveBase(-1);
startVertex -= pv->dwOutputSize;
}
}
if (vf & __TRIANGLE_CLIP)
{ // The triangle requires clipping
// Clip prev triangle - cv1, cv2, cv3
HRESULT ret;
if (dwTriIndex & 1)
ret = Clip(pv, cv1, cv3, cv2);
else
ret = Clip(pv, cv1, cv2, cv3);
if (ret != D3D_OK)
goto l_Exit;
}
}
d_UpdateInputPointers(1);
lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
cv1 = cv2;
cv2 = cv3;
cv3 = cv4;
cv4 = cv5;
cv5 = cv5->next;
dwTriIndex++;
vf >>= 5;
if (dwTriIndex < dwNumPrimitives)
{
if (dwClipUnion == 0 && primitiveCount == 1)
{
// If all vertices are inside the frustum we use the optimized loop
goto l_InsideLoop;
}
goto l_ClippedLoop;
}
// We still have to process the last two vertices. They are already transformed
if (dwTriIndex < dwNumPrimitives + 2)
goto l_ProcessOnly;
goto l_Exit;
l_InsideLoop:
d_TransformVertex(1, lpInpStart, m, x,y,z,w, pWeights, pMatrixIndices)
d_ComputeClipCode(1)
cv5->hx = x;
cv5->hy = y;
cv5->hz = z;
cv5->hw = w;
cv5->clip = 0;
if (clip)
goto l_ExitInsideLoop;
lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
l_InsideLoopProcessOnly:
{
// Because "primitiveCount" is now in sync with the transformed vertex
// (not processed one as it should be), it is greater by 2 then the actual
// primitive count
primitiveCount++;
w = D3DVAL(1)/cv3->hw;
d_ComputeScreenCoordinatesNoOutput(2, cv3->hx, cv3->hy, cv3->hz, w, x,y,z)
d_ComputeOutputColors(2, in, inNormal, inDiffuse, inSpecular, inWeights, inMatrixIndices)
d_CopyToOutputVertex(2, lpOutVer)
dwTriIndex++;
cv3 = cv3->next;
cv5 = cv5->next;
d_UpdateInputPointers(2);
if (dwTriIndex < dwNumPrimitives)
{
goto l_InsideLoop;
}
// We still have to process the last two vertices. They are already transformed
if (dwTriIndex < dwNumPrimitives + 2)
goto l_InsideLoopProcessOnly;
}
goto l_Exit;
l_ExitInsideLoop:
{
// For the last transforem vertex (cv5) we computed only clip code
// without guardband
d_ComputeClipCodeGB(2)
cv5->clip = clip;
dwClipUnion |= clip;
// We have to set status for the cv3 and cv4 vertices
vf |= __VERTEX_IN_INSIDETRIANGLE |__2_VERTEX_IN_INSIDETRIANGLE |
__TRIANGLE_INSIDE | __2_TRIANGLE_INSIDE;
cv4 = cv3->next;
goto l_ClippedLoop2;
}
l_Exit:
if (primitiveCount > 0)
{
// Draw batched primitive
if (bOddStrip)
{
// Draw first triangle as indexed triangle
WORD indices[3] = {0, 2, 1};
pv->dwIndexSize = 2;
pv->lpvOut = startVertex;
pv->pDDI->SetIndexedPrimParams(0, 0, 3, pv->pDDI->GetCurrentPrimBase());
ret = DRAW_INDEX_PRIM(pv, D3DPT_TRIANGLELIST, indices, 3, 1);
if (ret != D3D_OK)
goto l_Exit;
primitiveCount--;
// Move to the next vertex
pv->pDDI->SkipVertices(1);
startVertex += pv->dwOutputSize;
}
DWORD dwVertexCount = primitiveCount+2;
if (primitiveCount > 0)
{
ret = DRAW_PRIM(pv, D3DPT_TRIANGLESTRIP, startVertex,
dwVertexCount, primitiveCount);
if (ret != D3D_OK)
goto l_Error;
}
else
{
pv->pDDI->SkipVertices(2);
}
}
pv->dwClipUnion = dwClipUnion;
pv->dwClipIntersection = dwClipIntersection;
l_Error:
return ret;
}
//---------------------------------------------------------------------
// Clipping and lighting a non-indexed line list in one pass
//
HRESULT D3DFE_PVFUNCSI::ProcessLineList(D3DFE_PROCESSVERTICES *pv)
{
#ifdef DEBUG_PIPELINE
if (g_DebugFlags & __DEBUG_ONEPASS)
d_ProcessPrimitive(1)
#endif
if (pv->dwDeviceFlags & D3DDEV_DONOTCLIP)
d_ProcessPrimitive(1)
pv->dwFirstClippedVertex = 0xFFFFFFFF;
pv->dwFlags |= D3DPV_ONEPASSCLIPPING;
pv->pGeometryFuncs->ProcessVertices(pv);
int primitiveCount = 0; // Number of triangles in the current unclipped part
BYTE *startVertex = (BYTE*)pv->lpvOut;
if (pv->dwFirstClippedVertex != 0xFFFFFFFF)
{
if (pv->dwFirstClippedVertex > 2)
{
// Compute number of unclipped primitives
primitiveCount = pv->dwFirstClippedVertex >> 1;
// Index of the first vertex to process
DWORD dwStartVertexIndex = primitiveCount << 1;
DWORD dwVertexCount = dwStartVertexIndex;
// Compute new number of primitives to process
pv->dwNumPrimitives = pv->dwNumPrimitives - primitiveCount;
SetInputAndOutputPointers(pv, dwStartVertexIndex);
}
}
else
{
pv->dwFlags &= ~D3DPV_ONEPASSCLIPPING;
if (pv->dwClipIntersection)
return D3D_OK;
return (DoDrawPrimitive(pv));
}
HRESULT ret = D3D_OK;
D3DTLVERTEX*lpOutVer = (D3DTLVERTEX*)pv->lpvOut;
ClipVertex cv[2];
DWORD dwClipMaskOffScreen = pv->dwClipMaskOffScreen;
LPD3DMATRIXI m = &pv->mCTM[0];
D3DLIGHTINGELEMENT EyeSpaceData;
d_Setup()
cv[0].next = &cv[1];
for (DWORD n = pv->dwNumPrimitives; n; n--)
{
ClipVertex *out = cv;
D3DVERTEX *lpInpVer = (D3DVERTEX*)in;
D3DVALUE *pWeights = inWeights;
BYTE* pMatrixIndices = inMatrixIndices;
// First we transform three vertices and compute the clip codes
dwClipUnion = 0;
dwClipIntersection = ~0;
for (DWORD i=2; i; i--)
{
DWORD clip = TransformVertexMakeClipCode(pv, lpInpVer, pWeights, pMatrixIndices, out);
out++;
dwClipUnion |= clip;
dwClipIntersection &= clip;
lpInpVer = (D3DVERTEX*)((BYTE*)lpInpVer + dwInpVerSize);
pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
}
pv->dwClipUnion |= dwClipUnion;
pv->dwClipIntersection &= dwClipIntersection;
// Now we can check where the triangle is
if (!dwClipIntersection)
{
if (!(dwClipUnion & dwClipMaskOffScreen))
{ // The line does not require clipping
ClipVertex *lpXfmVer = cv;
primitiveCount++;
for (DWORD i=2; i; i--)
{
ComputeScreenCoordinates(pv, lpXfmVer, (D3DVECTORH*)lpOutVer);
d_DoLightingAndFog(5, in, inNormal, inDiffuse, inSpecular, lpOutVer, inWeights, inMatrixIndices)
D3DVALUE *pOutTexture = (D3DVALUE*)((BYTE*)lpOutVer + pv->texOffsetOut);
d_CopyTextureCoordUpdateInputPointers(5, pOutTexture)
lpXfmVer = lpXfmVer->next;
lpOutVer = (D3DTLVERTEX*)((BYTE*)lpOutVer + dwOutVerSize);
}
}
else
{ // The line requires clipping
if (primitiveCount)
{ // first draw the ones that didn't need clipping
DWORD vertexCount = primitiveCount << 1;
ret = DRAW_PRIM(pv, D3DPT_LINELIST, startVertex,
vertexCount, primitiveCount);
startVertex = (BYTE*)lpOutVer;
if (ret)
goto l_Exit;
}
primitiveCount = 0;
ClipVertex *lpXfmVer = cv;
for (DWORD i=2; i; i--)
{
if ((lpXfmVer->clip & dwClipMaskOffScreen) == 0)
{
ComputeScreenCoordinates(pv, lpXfmVer, (D3DVECTORH*)&lpXfmVer->sx);
}
d_ComputeOutputColors(5, in, inNormal, inDiffuse, inSpecular, inWeights, inMatrixIndices)
if (pv->dwVIDOut & D3DFVF_DIFFUSE)
lpXfmVer->color = pv->lighting.outDiffuse;
if (pv->dwVIDOut & D3DFVF_SPECULAR)
lpXfmVer->specular = pv->lighting.outSpecular;
d_CopyTextureCoordUpdateInputPointers(5, lpXfmVer->tex)
lpXfmVer++;
}
ret = ClipLine(pv, &cv[0], &cv[1]);
if (ret != D3D_OK)
goto l_Exit;
}
}
else
{ // Line is outside
// Update input pointers
d_UpdateInputPointers(3)
d_UpdateInputPointers(3)
}
}
// draw final batch, if any
if (primitiveCount)
{
DWORD dwVertexCount = primitiveCount << 1;
ret = DRAW_PRIM(pv, D3DPT_LINELIST, startVertex, dwVertexCount, primitiveCount);
}
l_Exit:
return ret;
}
//---------------------------------------------------------------------
// Clipping and lighting a non-indexed triangle line in one pass
//
// Vertices cv1 cv2 cv3
// Next to Next to
// process transform
// | | |
// * * * * * * *
//
HRESULT D3DFE_PVFUNCSI::ProcessLineStrip(D3DFE_PROCESSVERTICES *pv)
{
#ifdef DEBUG_PIPELINE
if (g_DebugFlags & __DEBUG_ONEPASS)
d_ProcessPrimitive(1)
#endif
if (pv->dwDeviceFlags & D3DDEV_DONOTCLIP)
d_ProcessPrimitive(1)
int primitiveCount; // Number of triangles in the current unclipped part
DWORD dwTriIndex; // Index of the current triangle in the primitive
// Start vertex for the current unclipped part of the triangle strip
BYTE *startVertex = (BYTE*)pv->lpvOut;
// Vertex flags has 5 bits per vertex
// Bits 0 - 4 - vertex cv2
// Bits 5 - 9 - vertex cv3
DWORD vf = 0;
D3DLIGHTINGELEMENT EyeSpaceData;
pv->dwFirstClippedVertex = 0xFFFFFFFF;
pv->dwFlags |= D3DPV_ONEPASSCLIPPING;
pv->pGeometryFuncs->ProcessVertices(pv);
if (pv->dwFirstClippedVertex == 0xFFFFFFFF)
{
pv->dwFlags &= ~D3DPV_ONEPASSCLIPPING;
if (pv->dwClipIntersection)
return D3D_OK;
return (DoDrawPrimitive(pv));
}
else
{
primitiveCount = 0;
dwTriIndex = 0;
if (pv->dwFirstClippedVertex > 2)
{
DWORD dwStartVertexIndex = pv->dwFirstClippedVertex - 1;
primitiveCount = dwStartVertexIndex - 1;
dwTriIndex = dwStartVertexIndex;
// We have to set status for the cv2 vertex
vf |= __VERTEX_IN_INSIDETRIANGLE | __TRIANGLE_INSIDE;
SetInputAndOutputPointers(pv, dwStartVertexIndex);
}
}
HRESULT ret = D3D_OK;
// Current pointer to the output vertex buffer
D3DTLVERTEX*lpOutVer = (D3DTLVERTEX*)pv->lpvOut;
ClipVertex *cv1; // First vertex of delayed clipped line
ClipVertex *cv2; // Vertex to process
ClipVertex *cv3; // Vertex to transform
D3DVERTEX *lpInpStart; // Next input vertex to transform
D3DVALUE *pWeights; // Vertex weights. Should be in ssync with lpInpStart
BYTE *pMatrixIndices; // Vertex weights. Should be in ssync with lpInpStart
DWORD dwClipMaskOffScreen = pv->dwClipMaskOffScreen; // Mask for guard band bits
LPD3DMATRIXI m = &pv->mCTM[0];
DWORD dwNumPrimitives = pv->dwNumPrimitives;
DWORD i;
d_Setup()
lpInpStart = (D3DVERTEX*)in;
pWeights = (D3DVALUE*)inWeights;
pMatrixIndices = (BYTE*)inMatrixIndices;
cv1 = NULL;
cv2 = pv->clipVer;
cv3 = pv->clipVer;
{
// Transform first vertex and copy it to the clip buffer
DWORD clip = TransformVertexMakeClipCode(pv, lpInpStart, pWeights, pMatrixIndices, cv3);
dwClipUnion |= clip;
dwClipIntersection &= clip;
cv3 = cv3->next;
lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
}
dwClipUnion |= cv2->clip;
dwClipIntersection &= cv2->clip;
float x,y,z,w;
int clip;
if (pv->dwFirstClippedVertex > 2)
{
// Force clip code to be zero to fix potential PSGP precision problem
cv2->clip = 0;
dwClipIntersection = 0;
goto l_InsideLoop;
}
l_ClippedLoop:
clip = TransformVertexMakeClipCode(pv, lpInpStart, pWeights, pMatrixIndices, cv3);
dwClipUnion |= clip;
dwClipIntersection &= clip;
l_ClippedLoop2:
// Set status for cv2, cv3 vertices based on their clip codes
if (!(cv2->clip & cv3->clip))
{
if (!((cv2->clip | cv3->clip) & dwClipMaskOffScreen))
vf |= __VERTEX_IN_INSIDETRIANGLE |__2_VERTEX_IN_INSIDETRIANGLE |
__2_TRIANGLE_INSIDE;
else
vf |= __VERTEX_IN_CLIPTRIANGLE | __2_VERTEX_IN_CLIPTRIANGLE |
__2_TRIANGLE_CLIP;
}
else
vf |= __2_TRIANGLE_OUTSIDE;
l_ProcessOnly:
// When we process a vertex, its status is completely defined
if ((cv2->clip & pv->dwClipMaskOffScreen) == 0)
{ // vertex is inside the guardband or frustum
// Compute screen coordinates
w = D3DVAL(1)/cv2->hw;
d_ComputeScreenCoordinatesNoOutput(2, cv2->hx, cv2->hy, cv2->hz, w, x,y,z)
}
if (vf & (__VERTEX_IN_INSIDETRIANGLE | __VERTEX_IN_CLIPTRIANGLE))
{
// Compute colors
d_ComputeOutputColors(2, in, inNormal, inDiffuse, inSpecular, inWeights, inMatrixIndices)
}
if (vf & __VERTEX_IN_INSIDETRIANGLE)
{
d_CopyToOutputVertex(2, lpOutVer)
}
if (vf & __VERTEX_IN_CLIPTRIANGLE)
{
d_CopyToClipVertex(2, cv2)
}
if (vf & __TRIANGLE_INSIDE)
{
primitiveCount++;
}
else
{
if (primitiveCount > 0)
{
// Draw batched primitive
DWORD dwVerCount = primitiveCount+1;
ret = DRAW_PRIM(pv, D3DPT_LINESTRIP, startVertex, dwVerCount, primitiveCount);
if (ret != D3D_OK)
goto l_Exit;
// Prepare for the next part of the primitive
startVertex += dwVerCount * pv->dwOutputSize;
primitiveCount = 0;
}
if (vf & __TRIANGLE_CLIP)
{ // The line requires clipping
// Clip prev triangle - cv1, cv2
HRESULT ret;
ret = ClipLine(pv, cv1, cv2);
if (ret != D3D_OK)
goto l_Exit;
}
}
d_UpdateInputPointers(1);
lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
cv1 = cv2;
cv2 = cv3;
cv3 = cv3->next;
dwTriIndex++;
vf >>= 5;
if (dwTriIndex < dwNumPrimitives)
{
if (dwClipUnion == 0 && primitiveCount == 1)
{
// If all vertices are inside the frustum we use the optimized loop
goto l_InsideLoop;
}
goto l_ClippedLoop;
}
// We still have to process one last vertex. It is already transformed
if (dwTriIndex < dwNumPrimitives + 1)
goto l_ProcessOnly;
goto l_Exit;
l_InsideLoop:
d_TransformVertex(1, lpInpStart, m, x,y,z,w, pWeights, pMatrixIndices)
d_ComputeClipCode(1)
cv3->hx = x;
cv3->hy = y;
cv3->hz = z;
cv3->hw = w;
cv3->clip = 0;
if (clip)
goto l_ExitInsideLoop;
lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
pWeights = (D3DVALUE*)((BYTE*)pWeights + pv->weights.dwStride);
pMatrixIndices = pMatrixIndices + pv->matrixIndices.dwStride;
l_InsideLoopProcessOnly:
{
// Because "primitiveCount" is now in sync with the transformed vertex
// (not processed one as it should be), it is greater by 1 then the actual
// primitive count
primitiveCount++;
w = D3DVAL(1)/cv2->hw;
d_ComputeScreenCoordinatesNoOutput(2, cv2->hx, cv2->hy, cv2->hz, w, x,y,z)
d_ComputeOutputColors(2, in, inNormal, inDiffuse, inSpecular, inWeights, inMatrixIndices)
d_CopyToOutputVertex(2, lpOutVer)
dwTriIndex++;
cv2 = cv2->next;
cv3 = cv3->next;
d_UpdateInputPointers(2);
if (dwTriIndex < dwNumPrimitives)
{
goto l_InsideLoop;
}
// We still have to process one last two vertex. It is already transformed
if (dwTriIndex < dwNumPrimitives + 1)
goto l_InsideLoopProcessOnly;
}
goto l_Exit;
l_ExitInsideLoop:
{
// For the last transforem vertex (cv3) we computed only clip code
// without guardband
d_ComputeClipCodeGB(2)
cv3->clip = clip;
dwClipUnion |= clip;
// We have to set status for the cv3 and cv4 vertices
vf |= __VERTEX_IN_INSIDETRIANGLE | __TRIANGLE_INSIDE ;
goto l_ClippedLoop2;
}
l_Exit:
if (primitiveCount > 0)
{
// Draw batched primitive
DWORD dwVertexCount = primitiveCount+1;
ret = DRAW_PRIM(pv, D3DPT_LINESTRIP, startVertex, dwVertexCount, primitiveCount);
}
pv->dwClipUnion = dwClipUnion;
pv->dwClipIntersection = dwClipIntersection;
return ret;
}