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.
527 lines
19 KiB
527 lines
19 KiB
/*==========================================================================;
|
|
*
|
|
* 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 __PROCESS_TRI_LIST_NAME(D3DFE_PROCESSVERTICES *pv)
|
|
{
|
|
int vertexSize3;
|
|
DWORD clipMaskOffScreen;
|
|
D3DFE_CLIPCODE *clipCode;
|
|
DWORD i;
|
|
int interpolate;
|
|
HRESULT ret;
|
|
BYTE *vertex;
|
|
#ifdef __INDEX_PRIM
|
|
LPWORD startVertex = pv->lpwIndices;
|
|
LPWORD index = pv->lpwIndices;
|
|
DWORD triangleSize; // 3 for DrawPrimitives,
|
|
// 4 for ExecuteBuffers (include wFlags)
|
|
if (pv->dwFlags & D3DPV_INSIDEEXECUTE)
|
|
triangleSize = 4;
|
|
else
|
|
triangleSize = 3;
|
|
#else
|
|
BYTE *startVertex = (BYTE*)pv->lpvOut;
|
|
#endif
|
|
int primitiveCount;
|
|
DWORD vertexSize;
|
|
ClipVertex cv[3];
|
|
BOOL vertexTransformed;
|
|
|
|
vertexTransformed = pv->dwFlags & D3DPV_TLVCLIP;
|
|
clipCode = pv->lpClipFlags;
|
|
interpolate = SetInterpolationFlags(pv);
|
|
vertex = (BYTE*)pv->lpvOut;
|
|
vertexSize = pv->dwOutputSize;
|
|
primitiveCount = 0;
|
|
if (pv->dwDeviceFlags & D3DDEV_GUARDBAND)
|
|
{
|
|
clipMaskOffScreen = ~__D3DCLIP_INGUARDBAND;
|
|
}
|
|
else
|
|
{
|
|
clipMaskOffScreen = 0xFFFFFFFF;
|
|
}
|
|
|
|
vertexSize3 = vertexSize*3;
|
|
for (i = pv->dwNumPrimitives; i; i--)
|
|
{
|
|
DWORD f1, f2, f3; // vertex clip flags
|
|
#ifdef __INDEX_PRIM
|
|
DWORD v1, v2, v3;
|
|
v1 = index[0];
|
|
v2 = index[1];
|
|
v3 = index[2];
|
|
f1 = clipCode[v1];
|
|
f2 = clipCode[v2];
|
|
f3 = clipCode[v3];
|
|
// PSGP implementation should not implement INSIDEEXECUTE
|
|
if (pv->dwFlags & D3DPV_INSIDEEXECUTE)
|
|
// Offset to the current triangle in the execute buffer
|
|
((LPDIRECT3DDEVICEI)pv)->dwClipIns_offset =
|
|
(DWORD)((BYTE*)index - (BYTE*)((LPDIRECT3DDEVICEI)pv)->lpbClipIns_base);
|
|
#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) & clipMaskOffScreen)
|
|
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;
|
|
#ifndef __INDEX_PRIM
|
|
pv->dwVertexBase += vertexCount;
|
|
#endif
|
|
}
|
|
// reset count and start ptr
|
|
primitiveCount = 0;
|
|
#ifdef __INDEX_PRIM
|
|
startVertex = index + triangleSize;
|
|
#else
|
|
pv->dwVertexBase += 3;
|
|
D3D_INFO(7, "VertexBase:%08lx", pv->dwVertexBase);
|
|
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, clipMaskOffScreen);
|
|
MAKE_CLIP_VERTEX_FVF(pv, cv[1], p2, f2, vertexTransformed, clipMaskOffScreen);
|
|
MAKE_CLIP_VERTEX_FVF(pv, cv[2], p3, f3, vertexTransformed, clipMaskOffScreen);
|
|
|
|
#ifdef __INDEX_PRIM
|
|
if (pv->dwFlags & D3DPV_INSIDEEXECUTE)
|
|
// Pass triangle flags for execute buffers
|
|
ret = Clip(pv, interpolate, cv, index[3]);
|
|
else
|
|
#endif
|
|
ret = Clip(pv, interpolate, cv);
|
|
if (ret) return ret;
|
|
}
|
|
}
|
|
else
|
|
primitiveCount++;
|
|
#ifdef __INDEX_PRIM
|
|
index += triangleSize;
|
|
#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 __PROCESS_TRI_STRIP_NAME(D3DFE_PROCESSVERTICES *pv)
|
|
{
|
|
DWORD lastIndex;
|
|
DWORD clipMaskOffScreen;
|
|
D3DFE_CLIPCODE *clipCode;
|
|
DWORD i;
|
|
int interpolate;
|
|
HRESULT ret;
|
|
BYTE *vertex;
|
|
#ifdef __INDEX_PRIM
|
|
LPWORD startVertex = pv->lpwIndices;
|
|
LPWORD index = 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;
|
|
interpolate = SetInterpolationFlags(pv);
|
|
vertex = (BYTE*)pv->lpvOut;
|
|
vertexSize = pv->dwOutputSize;
|
|
primitiveCount = 0;
|
|
if (pv->dwDeviceFlags & D3DDEV_GUARDBAND)
|
|
{
|
|
clipMaskOffScreen = ~__D3DCLIP_INGUARDBAND;
|
|
}
|
|
else
|
|
{
|
|
clipMaskOffScreen = 0xFFFFFFFF;
|
|
}
|
|
|
|
lastIndex = pv->dwNumPrimitives;
|
|
for (i=0; i < lastIndex; i++)
|
|
{
|
|
DWORD f1, f2, f3; // vertex clip flags
|
|
#ifdef __INDEX_PRIM
|
|
DWORD v1, v2, v3;
|
|
v1 = index[0];
|
|
v2 = index[1];
|
|
v3 = index[2];
|
|
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) & clipMaskOffScreen)
|
|
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
|
|
pv->dwVertexBase += primitiveCount;
|
|
#endif
|
|
}
|
|
// reset count and start ptr
|
|
primitiveCount = 0;
|
|
#ifdef __INDEX_PRIM
|
|
startVertex = &index[1];
|
|
#else
|
|
pv->dwVertexBase++;
|
|
D3D_INFO(7, "VertexBase:%08lx", pv->dwVertexBase);
|
|
startVertex = vertex + vertexSize;
|
|
#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, clipMaskOffScreen);
|
|
MAKE_CLIP_VERTEX_FVF(pv, cv[1], p2, f2, vertexTransformed, clipMaskOffScreen);
|
|
MAKE_CLIP_VERTEX_FVF(pv, cv[2], p3, f3, vertexTransformed, clipMaskOffScreen);
|
|
|
|
ret = Clip(pv, interpolate, cv);
|
|
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_CLIPPERPRIM | D3DPV_NONCLIPPED; // Mark this call as gen by clipper
|
|
ret = DRAW_PRIM(pv, D3DPT_TRIANGLEFAN, tmp, 3, 1);
|
|
pv->dwFlags &= ~(D3DPV_CLIPPERPRIM | D3DPV_NONCLIPPED);
|
|
if (ret)
|
|
return ret;
|
|
primitiveCount = 0;
|
|
#ifdef __INDEX_PRIM
|
|
startVertex = &index[1];
|
|
pv->lpvOut = saveVer;
|
|
pv->dwNumVertices = numVer;
|
|
#else
|
|
pv->dwVertexBase++;
|
|
D3D_INFO(7, "VertexBase:%08lx", pv->dwVertexBase);
|
|
startVertex = vertex + vertexSize;
|
|
#endif
|
|
}
|
|
else
|
|
primitiveCount++;
|
|
}
|
|
#ifdef __INDEX_PRIM
|
|
index++;
|
|
#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;
|
|
#ifndef __INDEX_PRIM
|
|
pv->dwVertexBase += primitiveCount;
|
|
#endif
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
// The same functions is used for line lists and line strips
|
|
//
|
|
HRESULT __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 countAdd; // Used to compute "real" number of vertices
|
|
// from the vertexCount
|
|
D3DPRIMITIVETYPE primType;
|
|
int numPrim = 0;
|
|
DWORD clipMaskOffScreen;
|
|
D3DFE_CLIPCODE *clipCode;
|
|
DWORD i;
|
|
int interpolate;
|
|
HRESULT ret;
|
|
BYTE *vertex;
|
|
#ifdef __INDEX_PRIM
|
|
LPWORD startVertex = pv->lpwIndices;
|
|
LPWORD index = pv->lpwIndices;
|
|
#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;
|
|
interpolate = SetInterpolationFlags(pv);
|
|
vertex = (BYTE*)pv->lpvOut;
|
|
vertexSize = pv->dwOutputSize;
|
|
vertexCount = 0;
|
|
if (pv->dwDeviceFlags & D3DDEV_GUARDBAND)
|
|
{
|
|
clipMaskOffScreen = ~__D3DCLIP_INGUARDBAND;
|
|
}
|
|
else
|
|
{
|
|
clipMaskOffScreen = 0xFFFFFFFF;
|
|
}
|
|
|
|
primType = pv->primType;
|
|
if (primType == D3DPT_LINESTRIP)
|
|
{
|
|
nextLineOffset = 1;
|
|
countAdd = 1;
|
|
}
|
|
else
|
|
{
|
|
nextLineOffset = 2;
|
|
countAdd = 0;
|
|
}
|
|
for (i = pv->dwNumPrimitives; i; i--)
|
|
{
|
|
WORD f1, f2;
|
|
#ifdef __INDEX_PRIM
|
|
WORD v1, v2;
|
|
v1 = index[0];
|
|
v2 = index[1];
|
|
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) & clipMaskOffScreen)
|
|
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
|
|
pv->dwVertexBase += vertexCount;
|
|
#endif
|
|
}
|
|
// reset count and start ptr
|
|
vertexCount = 0;
|
|
numPrim = 0;
|
|
#ifdef __INDEX_PRIM
|
|
startVertex = &index[nextLineOffset];
|
|
#else
|
|
pv->dwVertexBase += nextLineOffset;
|
|
D3D_INFO(7, "VertexBase:%08lx", pv->dwVertexBase);
|
|
startVertex = vertex + nextLineOffset*vertexSize;
|
|
#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
|
|
ClipTriangle newline;
|
|
|
|
MAKE_CLIP_VERTEX_FVF(pv, cv[0], p1, f1, vertexTransformed, clipMaskOffScreen);
|
|
MAKE_CLIP_VERTEX_FVF(pv, cv[1], p2, f2, vertexTransformed, clipMaskOffScreen);
|
|
|
|
newline.v[0] = &cv[0];
|
|
newline.v[1] = &cv[1];
|
|
|
|
if (ClipSingleLine(pv, &newline, &pv->rExtents, interpolate))
|
|
{
|
|
BYTE *pTLV = (BYTE*)pv->ClipperState.clipBuf.GetAddress();
|
|
BYTE *p = pTLV;
|
|
#ifdef __INDEX_PRIM
|
|
BYTE *saveVer = (BYTE*)pv->lpvOut;
|
|
DWORD numVer = pv->dwNumVertices;
|
|
#endif
|
|
MAKE_TL_VERTEX_FVF(pv, p, newline.v[0]);
|
|
p += vertexSize;
|
|
MAKE_TL_VERTEX_FVF(pv, p, newline.v[1]);
|
|
pv->dwFlags |= D3DPV_CLIPPERPRIM; // Mark this call as gen by clipper
|
|
ret = DRAW_PRIM(pv, D3DPT_LINELIST, pTLV, 2, 1);
|
|
pv->dwFlags &= ~D3DPV_CLIPPERPRIM;
|
|
if (ret)
|
|
return ret;
|
|
|
|
#ifdef __INDEX_PRIM
|
|
pv->lpvOut = saveVer;
|
|
pv->dwNumVertices = numVer;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vertexCount += nextLineOffset;
|
|
numPrim++;
|
|
}
|
|
#ifdef __INDEX_PRIM
|
|
index += nextLineOffset;
|
|
#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
|