533 lines
18 KiB
C
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
|