windows-nt/Source/XPSP1/NT/multimedia/directx/dxg/d3d8/tnl/clipprim.h
2020-09-26 16:20:57 +08:00

533 lines
18 KiB
C

/*==========================================================================;
*
* Copyright (C) 1997 Microsoft Corporation. All Rights Reserved.
*
* File: clip.h
* Content: Template for functions to clip primitives
*
* The following symbol should be defined before included this file:
* __PROCESS_LINE_NAME - name for a function to clip triangles
* __INDEX_PRIM - name for a function to clip lines
*
* All these symbols are undefined at the end of this file
***************************************************************************/
#ifdef __INDEX_PRIM
#define __DRAW DRAW_INDEX_PRIM
#else
#define __DRAW DRAW_PRIM
#endif
//*********************************************************************
HRESULT D3DFE_PVFUNCSI::__PROCESS_TRI_LIST_NAME(D3DFE_PROCESSVERTICES *pv)
{
int vertexSize3;
D3DFE_CLIPCODE *clipCode;
DWORD i;
HRESULT ret;
BYTE *vertex;
#ifdef __INDEX_PRIM
DWORD dwIndexSize = pv->dwIndexSize;
DWORD dwIndexSize3 = pv->dwIndexSize * 3;
// Start indexed of the current in-screen triangle batch
WORD* startVertex = pv->lpwIndices;
// Start index of the current triangle
LPBYTE index = (LPBYTE)pv->lpwIndices;
#else
// Start vertex of the current in-screen triangle batch
BYTE *startVertex = (BYTE*)pv->lpvOut;
#endif
int primitiveCount;
DWORD vertexSize;
ClipVertex cv[3];
BOOL vertexTransformed;
vertexTransformed = pv->dwFlags & D3DPV_TLVCLIP;
clipCode = pv->lpClipFlags;
vertex = (BYTE*)pv->lpvOut;
vertexSize = pv->dwOutputSize;
primitiveCount = 0;
#ifdef __INDEX_PRIM
// Update the address of the vertex array to handle the index base
if (pv->dwIndexOffset != 0)
{
vertex -= pv->dwIndexOffset * vertexSize;
clipCode -= pv->dwIndexOffset;
}
#endif
vertexSize3 = vertexSize*3;
for (i = pv->dwNumPrimitives; i; i--)
{
DWORD f1, f2, f3; // vertex clip flags
#ifdef __INDEX_PRIM
DWORD v1, v2, v3; // Current triangle indices
if (dwIndexSize == 2)
{
v1 = *(WORD*)index;
v2 = *(WORD*)(index + 2);
v3 = *(WORD*)(index + 4);
}
else
{
v1 = *(DWORD*)index;
v2 = *(DWORD*)(index + 4);
v3 = *(DWORD*)(index + 8);
}
f1 = clipCode[v1];
f2 = clipCode[v2];
f3 = clipCode[v3];
#else
f1 = clipCode[0];
f2 = clipCode[1];
f3 = clipCode[2];
#endif
BOOL needClip = FALSE;
BOOL offFrustum = FALSE;
if (f1 & f2 & f3)
offFrustum = TRUE;
else
if ((f1 | f2 | f3) & pv->dwClipMaskOffScreen)
needClip = TRUE;
if (offFrustum || needClip)
{// This tri does need clipping
if (primitiveCount)
{ // first draw the ones that didn't need clipping
DWORD vertexCount = primitiveCount*3;
ret = __DRAW(pv, D3DPT_TRIANGLELIST, startVertex,
vertexCount, primitiveCount);
if (ret)
return ret;
}
// reset count and start ptr
primitiveCount = 0;
#ifdef __INDEX_PRIM
startVertex = (WORD*)(index + dwIndexSize3);
#else
pv->pDDI->SkipVertices(3);
startVertex = vertex + vertexSize3;
#endif
// now deal with the single clipped triangle
// first check if it should just be tossed or if it should be clipped
if (!offFrustum)
{
BYTE *p1;
BYTE *p2;
BYTE *p3;
#ifdef __INDEX_PRIM
p1 = vertex + v1*vertexSize;
p2 = vertex + v2*vertexSize;
p3 = vertex + v3*vertexSize;
#else
p1 = vertex;
p2 = vertex + vertexSize;
p3 = p2 + vertexSize;
#endif
MAKE_CLIP_VERTEX_FVF(pv, cv[0], p1, f1, vertexTransformed);
MAKE_CLIP_VERTEX_FVF(pv, cv[1], p2, f2, vertexTransformed);
MAKE_CLIP_VERTEX_FVF(pv, cv[2], p3, f3, vertexTransformed);
#ifdef __INDEX_PRIM
#endif
ret = Clip(pv, &cv[0], &cv[1], &cv[2]);
if (ret) return ret;
}
}
else
primitiveCount++;
#ifdef __INDEX_PRIM
index += dwIndexSize3;
#else
clipCode += 3;
vertex += vertexSize3;
#endif
}
// draw final batch, if any
if (primitiveCount)
{
ret = __DRAW(pv, D3DPT_TRIANGLELIST, startVertex,
primitiveCount*3, primitiveCount);
if (ret)
return ret;
}
return D3D_OK;
}
//------------------------------------------------------------------------------
HRESULT D3DFE_PVFUNCSI::__PROCESS_TRI_STRIP_NAME(D3DFE_PROCESSVERTICES *pv)
{
DWORD lastIndex;
D3DFE_CLIPCODE *clipCode;
DWORD i;
HRESULT ret;
BYTE *vertex;
#ifdef __INDEX_PRIM
DWORD dwIndexSize = pv->dwIndexSize;
LPWORD startVertex = pv->lpwIndices;
LPBYTE index = (LPBYTE)pv->lpwIndices;
#else
BYTE *startVertex = (BYTE*)pv->lpvOut;
#endif
int primitiveCount;
DWORD vertexSize;
ClipVertex cv[3];
BOOL vertexTransformed;
vertexTransformed = pv->dwFlags & D3DPV_TLVCLIP;
clipCode = pv->lpClipFlags;
vertex = (BYTE*)pv->lpvOut;
vertexSize = pv->dwOutputSize;
primitiveCount = 0;
#ifdef __INDEX_PRIM
// Update the address of the vertex array to handle the index base
if (pv->dwIndexOffset != 0)
{
vertex -= pv->dwIndexOffset * vertexSize;
clipCode -= pv->dwIndexOffset;
}
#endif
lastIndex = pv->dwNumPrimitives;
for (i=0; i < lastIndex; i++)
{
DWORD f1, f2, f3; // vertex clip flags
#ifdef __INDEX_PRIM
DWORD v1, v2, v3;
if (dwIndexSize == 2)
{
v1 = *(WORD*)index;
v2 = *(WORD*)(index + 2);
v3 = *(WORD*)(index + 4);
}
else
{
v1 = *(DWORD*)index;
v2 = *(DWORD*)(index + 4);
v3 = *(DWORD*)(index + 8);
}
f1 = clipCode[v1];
f2 = clipCode[v2];
f3 = clipCode[v3];
#else
f1 = clipCode[0];
f2 = clipCode[1];
f3 = clipCode[2];
#endif
BOOL needClip = FALSE;
BOOL offFrustum = FALSE;
if (f1 & f2 & f3)
offFrustum = TRUE;
else
if ((f1 | f2 | f3) & pv->dwClipMaskOffScreen)
needClip = TRUE;
if (offFrustum || needClip)
{ // if this tri does need clipping
if (primitiveCount)
{ // first draw the ones that didn't need clipping
ret = __DRAW(pv, D3DPT_TRIANGLESTRIP, startVertex,
primitiveCount+2, primitiveCount);
if (ret)
return ret;
#ifndef __INDEX_PRIM
// We need to re-use the last vertex of the unclipped primitive
// So we move the PrimitiveBase and startVertex back
pv->pDDI->MovePrimitiveBase(-1);
startVertex = vertex - vertexSize;
#endif
}
else
{
#ifndef __INDEX_PRIM
// Move PrimitiveBase and UsedVertexCount
pv->pDDI->SkipVertices(1);
startVertex = vertex + vertexSize;
#endif
}
// reset count and start ptr
primitiveCount = 0;
#ifdef __INDEX_PRIM
startVertex = (LPWORD)(index + dwIndexSize);
#endif
// now deal with the single clipped triangle
// first check if it should just be tossed or if it should be clipped
if (!offFrustum)
{
BYTE *p1;
BYTE *p2;
BYTE *p3;
#ifdef __INDEX_PRIM
if (i & 1)
{ // For odd triangles we have to change orientation
// First vertex should remain the first, because it defines
// the color in FLAT shade mode
DWORD tmp = f2;
f2 = f3;
f3 = tmp;
p1 = vertex + v1*vertexSize;
p2 = vertex + v3*vertexSize;
p3 = vertex + v2*vertexSize;
}
else
{
p1 = vertex + v1*vertexSize;
p2 = vertex + v2*vertexSize;
p3 = vertex + v3*vertexSize;
}
#else
p1 = vertex;
if (i & 1)
{ // For odd triangles we have to change orientation
DWORD tmp = f2;
f2 = f3;
f3 = tmp;
p3 = vertex + vertexSize;
p2 = p3 + vertexSize;
}
else
{
p2 = vertex + vertexSize;
p3 = p2 + vertexSize;
}
#endif
MAKE_CLIP_VERTEX_FVF(pv, cv[0], p1, f1, vertexTransformed);
MAKE_CLIP_VERTEX_FVF(pv, cv[1], p2, f2, vertexTransformed);
MAKE_CLIP_VERTEX_FVF(pv, cv[2], p3, f3, vertexTransformed);
ret = Clip(pv, &cv[0], &cv[1], &cv[2]);
if (ret) return ret;
}
}
else
{
if (primitiveCount == 0 && i & 1)
{ // Triangle strip can not start from an odd triangle
// Because we use triangle fan, first vertex in the strip
// should be the second in the fan.
// This vertex defines the color in FLAT shading case.
BYTE tmp[__MAX_VERTEX_SIZE*3];
BYTE *p = tmp;
#ifdef __INDEX_PRIM
BYTE *saveVer = (BYTE*)pv->lpvOut;
DWORD numVer = pv->dwNumVertices;
memcpy (p, vertex + v2*vertexSize, vertexSize);
p += vertexSize;
memcpy (p, vertex + v1*vertexSize, vertexSize);
p += vertexSize;
memcpy (p, vertex + v3*vertexSize, vertexSize);
#else
memcpy(p, vertex + vertexSize, vertexSize);
p += vertexSize;
memcpy(p, vertex, vertexSize);
p += vertexSize;
memcpy(p, vertex + vertexSize + vertexSize, vertexSize);
#endif
pv->dwFlags |= D3DPV_NONCLIPPED;
ret = DRAW_CLIPPED_PRIM(pv, D3DPT_TRIANGLEFAN, tmp, 3, 1);
pv->dwFlags &= ~D3DPV_NONCLIPPED;
if (ret)
return ret;
primitiveCount = 0;
#ifdef __INDEX_PRIM
startVertex = (LPWORD)(index + dwIndexSize);
pv->lpvOut = saveVer;
pv->dwNumVertices = numVer;
#else
pv->pDDI->SkipVertices(1);
startVertex = vertex + vertexSize;
#endif
}
else
primitiveCount++;
}
#ifdef __INDEX_PRIM
index += dwIndexSize;
#else
clipCode++;
vertex += vertexSize;
#endif
}
// draw final batch, if any
if (primitiveCount)
{
ret = __DRAW(pv, D3DPT_TRIANGLESTRIP, startVertex,
primitiveCount+2, primitiveCount);
if (ret)
return ret;
}
return D3D_OK;
}
//-----------------------------------------------------------------------------
// The same functions is used for line lists and line strips
//
HRESULT D3DFE_PVFUNCSI::__PROCESS_LINE_NAME(D3DFE_PROCESSVERTICES *pv)
{
DWORD nextLineOffset; // How many vertices to skip, when going to
// next primitive (1 for strips, 2 for lists)
DWORD nextLineOffsetIndex; // Multiplied by the index size
DWORD countAdd; // Used to compute "real" number of vertices
// from the vertexCount
D3DPRIMITIVETYPE primType;
int numPrim = 0;
D3DFE_CLIPCODE *clipCode;
DWORD i;
HRESULT ret;
BYTE *vertex;
#ifdef __INDEX_PRIM
LPWORD startVertex = pv->lpwIndices;
LPBYTE index = (LPBYTE)pv->lpwIndices;
DWORD dwIndexSize = pv->dwIndexSize;
#else
BYTE *startVertex = (BYTE*)pv->lpvOut;
#endif
int vertexCount; // Primitive count for line strips,
// vertex count for line lists
DWORD vertexSize;
ClipVertex cv[3];
BOOL vertexTransformed;
vertexTransformed = pv->dwFlags & D3DPV_TLVCLIP;
clipCode = pv->lpClipFlags;
vertex = (BYTE*)pv->lpvOut;
vertexSize = pv->dwOutputSize;
vertexCount = 0;
#ifdef __INDEX_PRIM
// Update the address of the vertex array to handle the index base
if (pv->dwIndexOffset != 0)
{
vertex -= pv->dwIndexOffset * vertexSize;
clipCode -= pv->dwIndexOffset;
}
#endif
primType = pv->primType;
if (primType == D3DPT_LINESTRIP)
{
#ifdef __INDEX_PRIM
nextLineOffset = 1;
nextLineOffsetIndex = dwIndexSize;
#else
nextLineOffset = 1;
#endif
countAdd = 1;
}
else
{
#ifdef __INDEX_PRIM
nextLineOffset = 2;
nextLineOffsetIndex = dwIndexSize * 2;
#else
nextLineOffset = 2;
#endif
countAdd = 0;
}
for (i = pv->dwNumPrimitives; i; i--)
{
WORD f1, f2;
#ifdef __INDEX_PRIM
DWORD v1, v2;
if (dwIndexSize == 2)
{
v1 = *(WORD*)index;
v2 = *(WORD*)(index + 2);
}
else
{
v1 = *(DWORD*)index;
v2 = *(DWORD*)(index + 4);
}
f1 = clipCode[v1];
f2 = clipCode[v2];
#else
f1 = clipCode[0];
f2 = clipCode[1];
#endif
BOOL needClip = FALSE;
BOOL offFrustum = FALSE;
if (f1 & f2)
offFrustum = TRUE;
else
if ((f1 | f2) & pv->dwClipMaskOffScreen)
needClip = TRUE;
if (offFrustum || needClip)
{ // if this line does need clipping
if (vertexCount)
{ // first draw the ones that didn't need clipping
ret = __DRAW(pv, primType, startVertex, vertexCount+countAdd, numPrim);
if (ret)
return ret;
#ifndef __INDEX_PRIM
// For line strips we have to go one vertex back
pv->pDDI->MovePrimitiveBase(-(int)countAdd);
// Now go to the next primitive
pv->pDDI->MovePrimitiveBase(nextLineOffset);
startVertex = vertex + nextLineOffset*vertexSize;
#endif
}
else
{
#ifndef __INDEX_PRIM
pv->pDDI->SkipVertices(nextLineOffset);
startVertex = vertex + nextLineOffset*vertexSize;
#endif
}
// reset count and start ptr
vertexCount = 0;
numPrim = 0;
#ifdef __INDEX_PRIM
startVertex = (LPWORD)(index + nextLineOffsetIndex);
#endif
// now deal with the single clipped line
// first check if it should just be tossed or if it should be clipped
if (!offFrustum)
{
#ifdef __INDEX_PRIM
BYTE *p1 = vertex + v1*vertexSize;
BYTE *p2 = vertex + v2*vertexSize;
#else
BYTE *p1 = vertex;
BYTE *p2 = vertex + vertexSize;
#endif
MAKE_CLIP_VERTEX_FVF(pv, cv[0], p1, f1, vertexTransformed);
MAKE_CLIP_VERTEX_FVF(pv, cv[1], p2, f2, vertexTransformed);
ret = ClipLine(pv, &cv[0], &cv[1]);
if (ret != D3D_OK)
return ret;
}
}
else
{
vertexCount += nextLineOffset;
numPrim++;
}
#ifdef __INDEX_PRIM
index += nextLineOffsetIndex;
#else
vertex += nextLineOffset*vertexSize;
clipCode += nextLineOffset;
#endif
}
// draw final batch, if any
if (vertexCount)
{
ret = __DRAW(pv, primType, startVertex, vertexCount+countAdd, numPrim);
if (ret)
return ret;
}
return D3D_OK;
}
#undef __DRAW
#undef __INDEX_PRIM
#undef __PROCESS_LINE_NAME
#undef __PROCESS_TRI_LIST_NAME
#undef __PROCESS_TRI_STRIP_NAME