Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1438 lines
52 KiB

/*============================ ==============================================;
*
* Copyright (C) 1998 Microsoft Corporation. All Rights Reserved.
*
* File: pvone.mcp
* Content: Clipping and vertex processing in one loop
*
***************************************************************************/
#define DEBUG_PIPELINE
#include "pch.cpp"
#pragma hdrstop
#include "light.h"
#include "clipper.h"
#include "drawprim.hpp"
#include "clipfunc.h"
#include "pvvid.h"
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, ClipVertex* pOut)
{
D3DVALUE x,y,z,w;
DWORD clip;
d_TransformVertex(1, pInp, (&pv->mCTM), x,y,z,w)
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;
}
//--------------------------------------------------------------------------
inline void UpdateVertexBatch(D3DFE_PROCESSVERTICES *pv, DWORD dwVertexBaseOrg)
{
DDASSERT(pv->dwVertexBase >= dwVertexBaseOrg);
pv->dwDP2VertexCount = pv->dwVertexBase;
pv->dwVertexPoolSize = (pv->dwVertexBase - dwVertexBaseOrg) * pv->dwOutputSize;
}
//--------------------------------------------------------------------------
// 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;
if (pv->dwDeviceFlags & D3DDEV_FVF || pv->dwFlags & D3DPV_VBCALL)
{
for (DWORD i=0; i < pv->nTexCoord; i++)
pv->textures[i].lpvData = (char*)pv->textures[i].lpvData +
dwStartVertexIndex * pv->textures[i].dwStride;
}
else
{
if (pv->nTexCoord)
{
DWORD i = pv->dwTextureIndexToCopy;
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// 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)
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) this->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_PVFUNCS::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;
this->ProcessVertices(pv);
int primitiveCount = 0; // Number of triangles in the current unclipped part
BYTE *startVertex = (BYTE*)pv->lpvOut;
DWORD dwVertexBaseOrg = pv->dwVertexBase;
if (pv->dwFirstClippedVertex != 0xFFFFFFFF)
{
dwVertexBaseOrg = pv->dwVertexBase;
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;
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;
// 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, out);
out++;
dwClipUnion |= clip;
dwClipIntersection &= clip;
lpInpVer = (D3DVERTEX*)((BYTE*)lpInpVer + dwInpVerSize);
}
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)
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);
pv->dwVertexBase += vertexCount;
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)
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);
pv->dwVertexBase += dwVertexCount;
}
l_Exit:
d_UpdateExtents()
UpdateVertexBatch(pv, dwVertexBaseOrg);
return ret;
}
//---------------------------------------------------------------------
// Clipping and lighting a non-indexed triangle fan in one pass
//
HRESULT D3DFE_PVFUNCS::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 dwVertexBaseOrg; // Original vertex base. It is used to compute number of vertices
// in the unclipped part of the primitive
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;
this->ProcessVertices(pv);
if (pv->dwFirstClippedVertex == 0xFFFFFFFF)
{
pv->dwFlags &= ~D3DPV_ONEPASSCLIPPING;
if (pv->dwClipIntersection)
return D3D_OK;
return (DoDrawPrimitive(pv));
}
else
{
dwVertexBaseOrg = pv->dwVertexBase;
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
DWORD dwClipMaskOffScreen = pv->dwClipMaskOffScreen; // Mask for guard band bits
LPD3DMATRIXI m = &pv->mCTM;
// Vertex flags has 5 bits per vertex
// Bits 0 - 4 - vertex cv2
// Bits 5 - 9 - vertex cv3
DWORD vf = 0;
D3DLIGHTINGELEMENT EyeSpaceData;
lpInpStart = (D3DVERTEX*)pv->position.lpvData;
d_Setup()
// 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, &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)
cv1.color = pv->lighting.outDiffuse;
cv1.specular = pv->lighting.outSpecular;
d_CopyTextureCoordUpdateInputPointers(2, ((DWORD*)(cv1.tex)))
lpInpStart = (D3DVERTEX*)in;
}
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)
{
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);
if (pv->dwDeviceFlags & D3DDEV_FVF || pv->dwFlags & D3DPV_VBCALL)
{
for (DWORD i=0; i < pv->nTexCoord; i++)
inTexture[i] = (D3DVALUE*)((char*)pv->textures[i].lpvData +
dwStartVertexIndex * pv->textures[i].dwStride);
}
else
{
if (pv->nTexCoord)
{
DWORD i = pv->dwTextureIndexToCopy;
inTexture[i] = (D3DVALUE*)((char*)pv->textures[i].lpvData +
dwStartVertexIndex * pv->textures[i].dwStride);
}
}
}
else
{
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, cv2);
// Transformed vertex is ahead by one vertex
lpInpStart = (D3DVERTEX*)((BYTE*)in + dwInpVerSize);
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, cv2);
lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
}
dwClipUnion |= cv1.clip | cv2->clip;
dwClipIntersection &= cv1.clip & cv2->clip;
float x,y,z,w;
int clip;
l_ClippedLoop:
d_TransformVertexMakeClipCode(1, lpInpStart, cv3)
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)
}
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
pv->dwVertexBase += dwVerCount; // Required by DP2 batching code
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
pv->dwVertexBase += dwVerCount; // Required by DP2 batching code
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);
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)
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);
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)
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->dwVertexBase += dwVertexCount;
}
d_UpdateExtents()
pv->dwClipUnion = dwClipUnion;
pv->dwClipIntersection = dwClipIntersection;
UpdateVertexBatch(pv, dwVertexBaseOrg);
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_PVFUNCS::ProcessTriangleStrip(D3DFE_PROCESSVERTICES *pv)
{
pv->dwFlags |= D3DPV_WITHINPRIMITIVE;
#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;
DWORD dwVertexBaseOrg; // Original vertex base. It is used to compute number of vertices
// in the unclipped part of the primitive
D3DLIGHTINGELEMENT EyeSpaceData;
pv->dwFirstClippedVertex = 0xFFFFFFFF;
pv->dwFlags |= D3DPV_ONEPASSCLIPPING;
this->ProcessVertices(pv);
if (pv->dwFirstClippedVertex == 0xFFFFFFFF)
{
pv->dwFlags &= ~D3DPV_ONEPASSCLIPPING;
if (pv->dwClipIntersection)
return D3D_OK;
return (DoDrawPrimitive(pv));
}
else
{
primitiveCount = 0;
dwTriIndex = 0;
dwVertexBaseOrg = pv->dwVertexBase;
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
DWORD dwClipMaskOffScreen = pv->dwClipMaskOffScreen; // Mask for guard band bits
LPD3DMATRIXI m = &pv->mCTM;
DWORD dwOddVertexRenderState; // Cull state used for a sub-strip,
//started from an odd index
DWORD dwOrgCullRenderState; // Original cull state
DWORD dwNumPrimitives = pv->dwNumPrimitives;
DWORD i;
d_Setup()
// Determine the cull state for sub-strips, started fron an odd triangle index
dwOrgCullRenderState = pv->lpdwRStates[D3DRENDERSTATE_CULLMODE];
switch (dwOrgCullRenderState)
{
case D3DCULL_NONE: dwOddVertexRenderState = D3DCULL_NONE; break;
case D3DCULL_CW: dwOddVertexRenderState = D3DCULL_CCW; break;
case D3DCULL_CCW: dwOddVertexRenderState = D3DCULL_CW; break;
}
lpInpStart = (D3DVERTEX*)pv->position.lpvData;
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, cv5);
dwClipUnion |= clip;
dwClipIntersection &= clip;
cv5 = cv5->next;
lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
}
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)
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)
}
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)
{
// Start new primitive
if (dwTriIndex & 1)
{ // First triangle has an odd index
if (dwOddVertexRenderState != pv->lpdwRStates[D3DRENDERSTATE_CULLMODE])
{
pv->lpdwRStates[D3DRENDERSTATE_CULLMODE] = dwOddVertexRenderState;
pv->SetRenderStateI(D3DRENDERSTATE_CULLMODE, dwOddVertexRenderState);
}
}
else
{ // First triangle has an even index
if (dwOrgCullRenderState != pv->lpdwRStates[D3DRENDERSTATE_CULLMODE])
{
pv->lpdwRStates[D3DRENDERSTATE_CULLMODE] = dwOrgCullRenderState;
pv->SetRenderStateI(D3DRENDERSTATE_CULLMODE, dwOrgCullRenderState);
}
}
}
}
else
{
if (primitiveCount > 0)
{
// Draw batched primitive
DWORD dwVerCount = primitiveCount+2;
ret = DRAW_PRIM(pv, D3DPT_TRIANGLESTRIP, startVertex,
dwVerCount, primitiveCount);
if (ret != D3D_OK)
goto l_Exit;
// Prepare for the next part of the primitive
pv->dwVertexBase += dwVerCount; // Required by DP2 batching code
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->dwVertexBase--; // Required by DP2 batching code
startVertex -= pv->dwOutputSize;
}
}
if (vf & __TRIANGLE_CLIP)
{ // The triangle requires clipping
// Clip prev triangle - cv1, cv2, cv3
if (dwOrgCullRenderState != pv->lpdwRStates[D3DRENDERSTATE_CULLMODE])
{
pv->lpdwRStates[D3DRENDERSTATE_CULLMODE] = dwOrgCullRenderState;
pv->SetRenderStateI(D3DRENDERSTATE_CULLMODE, dwOrgCullRenderState);
}
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);
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)
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);
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)
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
DWORD dwVertexCount = primitiveCount+2;
ret = DRAW_PRIM(pv, D3DPT_TRIANGLESTRIP, startVertex,
dwVertexCount, primitiveCount);
pv->dwVertexBase += dwVertexCount;
}
pv->dwClipUnion = dwClipUnion;
pv->dwClipIntersection = dwClipIntersection;
UpdateVertexBatch(pv, dwVertexBaseOrg);
d_UpdateExtents()
// Restore the original D3DRENDERSTATE_CULL state
if (dwOrgCullRenderState != pv->lpdwRStates[D3DRENDERSTATE_CULLMODE])
{
pv->lpdwRStates[D3DRENDERSTATE_CULLMODE] = dwOrgCullRenderState;
pv->SetRenderStateI(D3DRENDERSTATE_CULLMODE, dwOrgCullRenderState);
}
pv->dwFlags &= ~D3DPV_WITHINPRIMITIVE;
return ret;
}
//---------------------------------------------------------------------
// Clipping and lighting a non-indexed line list in one pass
//
HRESULT D3DFE_PVFUNCS::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;
this->ProcessVertices(pv);
int primitiveCount = 0; // Number of triangles in the current unclipped part
BYTE *startVertex = (BYTE*)pv->lpvOut;
DWORD dwVertexBaseOrg; // Original vertex base. It is used to compute number of vertices
// in the unclipped part of the primitive
if (pv->dwFirstClippedVertex != 0xFFFFFFFF)
{
dwVertexBaseOrg = pv->dwVertexBase;
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;
D3DLIGHTINGELEMENT EyeSpaceData;
d_Setup()
cv[0].next = &cv[1];
for (DWORD n = pv->dwNumPrimitives; n; n--)
{
ClipVertex *out = cv;
D3DVERTEX *lpInpVer = (D3DVERTEX*)in;
// 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, out);
out++;
dwClipUnion |= clip;
dwClipIntersection &= clip;
lpInpVer = (D3DVERTEX*)((BYTE*)lpInpVer + dwInpVerSize);
}
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)
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);
pv->dwVertexBase += vertexCount;
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)
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);
pv->dwVertexBase += dwVertexCount;
}
l_Exit:
d_UpdateExtents()
UpdateVertexBatch(pv, dwVertexBaseOrg);
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_PVFUNCS::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;
DWORD dwVertexBaseOrg; // Original vertex base. It is used to compute number of vertices
// in the unclipped part of the primitive
D3DLIGHTINGELEMENT EyeSpaceData;
pv->dwFirstClippedVertex = 0xFFFFFFFF;
pv->dwFlags |= D3DPV_ONEPASSCLIPPING;
this->ProcessVertices(pv);
if (pv->dwFirstClippedVertex == 0xFFFFFFFF)
{
pv->dwFlags &= ~D3DPV_ONEPASSCLIPPING;
if (pv->dwClipIntersection)
return D3D_OK;
return (DoDrawPrimitive(pv));
}
else
{
primitiveCount = 0;
dwTriIndex = 0;
dwVertexBaseOrg = pv->dwVertexBase;
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
DWORD dwClipMaskOffScreen = pv->dwClipMaskOffScreen; // Mask for guard band bits
LPD3DMATRIXI m = &pv->mCTM;
DWORD dwNumPrimitives = pv->dwNumPrimitives;
DWORD i;
d_Setup()
lpInpStart = (D3DVERTEX*)pv->position.lpvData;
cv1 = NULL;
cv2 = pv->clipVer;
cv3 = pv->clipVer;
{
// Transform first vertex and copy it to the clip buffer
DWORD clip = TransformVertexMakeClipCode(pv, lpInpStart, cv3);
dwClipUnion |= clip;
dwClipIntersection &= clip;
cv3 = cv3->next;
lpInpStart = (D3DVERTEX*)((BYTE*)lpInpStart + dwInpVerSize);
}
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, 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)
}
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
pv->dwVertexBase += dwVerCount; // Required by DP2 batching code
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);
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)
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);
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)
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->dwVertexBase += dwVertexCount;
}
pv->dwClipUnion = dwClipUnion;
pv->dwClipIntersection = dwClipIntersection;
d_UpdateExtents()
UpdateVertexBatch(pv, dwVertexBaseOrg);
return ret;
}