898 lines
28 KiB
C++
898 lines
28 KiB
C++
|
/*==========================================================================;
|
||
|
*
|
||
|
* Copyright (C) 1997 Microsoft Corporation. All Rights Reserved.
|
||
|
*
|
||
|
* File: clipper.c
|
||
|
* Content: Clipper
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
|
||
|
#include "pch.cpp"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#define GET_NEW_CLIP_VERTEX \
|
||
|
&pv->ClipperState.clip_vertices[pv->ClipperState.clip_vertices_used++];
|
||
|
//---------------------------------------------------------------------
|
||
|
__inline void
|
||
|
InterpolateColor(DWORD* p, // Output
|
||
|
DWORD p1,
|
||
|
DWORD p2,
|
||
|
D3DVALUE num_denom )
|
||
|
{
|
||
|
float r1, g1, b1, a1;
|
||
|
float r2, g2, b2, a2;
|
||
|
|
||
|
r1 = (float)(RGBA_GETRED(p1));
|
||
|
g1 = (float)(RGBA_GETGREEN(p1));
|
||
|
b1 = (float)(RGBA_GETBLUE(p1));
|
||
|
a1 = (float)(RGBA_GETALPHA(p1));
|
||
|
r2 = (float)(RGBA_GETRED(p2));
|
||
|
g2 = (float)(RGBA_GETGREEN(p2));
|
||
|
b2 = (float)(RGBA_GETBLUE(p2));
|
||
|
a2 = (float)(RGBA_GETALPHA(p2));
|
||
|
DWORD r = FTOI(r1 + (r2 - r1) * num_denom);
|
||
|
DWORD g = FTOI(g1 + (g2 - g1) * num_denom);
|
||
|
DWORD b = FTOI(b1 + (b2 - b1) * num_denom);
|
||
|
DWORD a = FTOI(a1 + (a2 - a1) * num_denom);
|
||
|
*p = RGBA_MAKE(r, g, b, a);
|
||
|
}
|
||
|
//---------------------------------------------------------------------
|
||
|
__inline D3DVALUE
|
||
|
InterpolateTexture(D3DVALUE t1,
|
||
|
D3DVALUE t2,
|
||
|
D3DVALUE num_denom,
|
||
|
DWORD bWrap)
|
||
|
{
|
||
|
if (!bWrap)
|
||
|
return ((t2 - t1) * num_denom + t1);
|
||
|
else
|
||
|
{
|
||
|
D3DVALUE t = (TextureDiff(t2, t1, 1) * num_denom + t1);
|
||
|
if (t > 1.0f)
|
||
|
t -= 1.0f;
|
||
|
return t;
|
||
|
}
|
||
|
}
|
||
|
//---------------------------------------------------------------------
|
||
|
void
|
||
|
Interpolate(D3DFE_PROCESSVERTICES *pv,
|
||
|
ClipVertex *p,
|
||
|
ClipVertex *p1,
|
||
|
ClipVertex *p2,
|
||
|
int code,
|
||
|
D3DVALUE num, D3DVALUE denom)
|
||
|
{
|
||
|
D3DVALUE num_denom = num / denom;
|
||
|
|
||
|
p->clip = (((int)p1->clip & (int)p2->clip) & ~CLIPPED_ENABLE) | code;
|
||
|
p->hx = p1->hx + (p2->hx - p1->hx) * num_denom;
|
||
|
p->hy = p1->hy + (p2->hy - p1->hy) * num_denom;
|
||
|
p->hz = p1->hz + (p2->hz - p1->hz) * num_denom;
|
||
|
p->hw = p1->hw + (p2->hw - p1->hw) * num_denom;
|
||
|
|
||
|
// Note: for the flat shade mode we assigned the same color (except fog
|
||
|
// factor) to all vertices when we prepared the triangle (line) for
|
||
|
// clipping
|
||
|
if (pv->dwVIDOut & D3DFVF_DIFFUSE)
|
||
|
{
|
||
|
if (!(pv->dwDeviceFlags & D3DDEV_FLATSHADEMODE))
|
||
|
InterpolateColor(&p->color, p1->color, p2->color, num_denom);
|
||
|
else
|
||
|
p->color = p1->color;
|
||
|
}
|
||
|
|
||
|
if (pv->dwVIDOut & D3DFVF_SPECULAR)
|
||
|
{
|
||
|
if (!(pv->dwDeviceFlags & D3DDEV_FLATSHADEMODE))
|
||
|
InterpolateColor(&p->specular, p1->specular, p2->specular, num_denom);
|
||
|
else
|
||
|
{
|
||
|
float a1 = (float)(RGBA_GETALPHA(p1->specular));
|
||
|
float a2 = (float)(RGBA_GETALPHA(p2->specular));
|
||
|
DWORD a = FTOI(a1 + (a2 - a1) * num_denom);
|
||
|
p->specular = (p1->specular & 0xFFFFFF) + ((a & 0xFF) << 24);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Assume that D3DRENDERSTATE_WRAPi are sequential
|
||
|
D3DVALUE *pTexture1 = p1->tex;
|
||
|
D3DVALUE *pTexture2 = p2->tex;
|
||
|
D3DVALUE *pTexture = p->tex;
|
||
|
for (DWORD i = 0; i < pv->nOutTexCoord; i++)
|
||
|
{
|
||
|
DWORD wrapState = pv->lpdwRStates[D3DRENDERSTATE_WRAP0 + i];
|
||
|
DWORD n = (DWORD)(pv->dwTextureCoordSize[i] >> 2);
|
||
|
DWORD dwWrapBit = 1;
|
||
|
for (DWORD j=0; j < n; j++)
|
||
|
{
|
||
|
*pTexture = InterpolateTexture(*pTexture1, *pTexture2,
|
||
|
num_denom, wrapState & dwWrapBit);
|
||
|
dwWrapBit <<= 1;
|
||
|
pTexture ++;
|
||
|
pTexture1++;
|
||
|
pTexture2++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//------------------------------------------------------------------------------
|
||
|
// Functions for clipping by frustum window
|
||
|
//
|
||
|
#define __CLIP_NAME ClipLeft
|
||
|
#define __CLIP_LINE_NAME ClipLineLeft
|
||
|
#define __CLIP_FLAG CLIPPED_LEFT
|
||
|
#define __CLIP_COORD hx
|
||
|
#include "clip.h"
|
||
|
|
||
|
#define __CLIP_NAME ClipRight
|
||
|
#define __CLIP_LINE_NAME ClipLineRight
|
||
|
#define __CLIP_W
|
||
|
#define __CLIP_FLAG CLIPPED_RIGHT
|
||
|
#define __CLIP_COORD hx
|
||
|
#include "clip.h"
|
||
|
|
||
|
#define __CLIP_NAME ClipBottom
|
||
|
#define __CLIP_LINE_NAME ClipLineBottom
|
||
|
#define __CLIP_FLAG CLIPPED_BOTTOM
|
||
|
#define __CLIP_COORD hy
|
||
|
#include "clip.h"
|
||
|
|
||
|
#define __CLIP_NAME ClipTop
|
||
|
#define __CLIP_LINE_NAME ClipLineTop
|
||
|
#define __CLIP_W
|
||
|
#define __CLIP_FLAG CLIPPED_TOP
|
||
|
#define __CLIP_COORD hy
|
||
|
#include "clip.h"
|
||
|
|
||
|
#define __CLIP_NAME ClipBack
|
||
|
#define __CLIP_LINE_NAME ClipLineBack
|
||
|
#define __CLIP_W
|
||
|
#define __CLIP_FLAG CLIPPED_BACK
|
||
|
#define __CLIP_COORD hz
|
||
|
#include "clip.h"
|
||
|
|
||
|
#define __CLIP_NAME ClipFront
|
||
|
#define __CLIP_LINE_NAME ClipLineFront
|
||
|
#define __CLIP_FLAG CLIPPED_FRONT
|
||
|
#define __CLIP_COORD hz
|
||
|
#include "clip.h"
|
||
|
//------------------------------------------------------------------------------
|
||
|
// Functions for guard band clipping
|
||
|
//
|
||
|
#define __CLIP_GUARDBAND
|
||
|
#define __CLIP_NAME ClipLeftGB
|
||
|
#define __CLIP_LINE_NAME ClipLineLeftGB
|
||
|
#define __CLIP_FLAG CLIPPED_LEFT
|
||
|
#define __CLIP_COORD hx
|
||
|
#define __CLIP_SIGN -
|
||
|
#define __CLIP_GBCOEF Kgbx1
|
||
|
#include "clip.h"
|
||
|
|
||
|
#define __CLIP_NAME ClipRightGB
|
||
|
#define __CLIP_LINE_NAME ClipLineRightGB
|
||
|
#define __CLIP_FLAG CLIPPED_RIGHT
|
||
|
#define __CLIP_COORD hx
|
||
|
#define __CLIP_GBCOEF Kgbx2
|
||
|
#define __CLIP_SIGN +
|
||
|
#include "clip.h"
|
||
|
|
||
|
#define __CLIP_NAME ClipBottomGB
|
||
|
#define __CLIP_LINE_NAME ClipLineBottomGB
|
||
|
#define __CLIP_FLAG CLIPPED_BOTTOM
|
||
|
#define __CLIP_COORD hy
|
||
|
#define __CLIP_SIGN -
|
||
|
#define __CLIP_GBCOEF Kgby1
|
||
|
#include "clip.h"
|
||
|
|
||
|
#define __CLIP_NAME ClipTopGB
|
||
|
#define __CLIP_LINE_NAME ClipLineTopGB
|
||
|
#define __CLIP_FLAG CLIPPED_TOP
|
||
|
#define __CLIP_COORD hy
|
||
|
#define __CLIP_GBCOEF Kgby2
|
||
|
#define __CLIP_SIGN +
|
||
|
#include "clip.h"
|
||
|
|
||
|
#undef __CLIP_GUARDBAND
|
||
|
//
|
||
|
// Clipping a triangle by a plane
|
||
|
//
|
||
|
// Returns number of vertices in the clipped triangle
|
||
|
//
|
||
|
int ClipByPlane (D3DFE_PROCESSVERTICES *pv,
|
||
|
ClipVertex **inv,
|
||
|
ClipVertex **outv,
|
||
|
D3DVECTORH *plane,
|
||
|
DWORD dwClipFlag,
|
||
|
int count)
|
||
|
{
|
||
|
int i;
|
||
|
int out_count = 0;
|
||
|
ClipVertex *curr, *prev;
|
||
|
D3DVALUE curr_inside;
|
||
|
D3DVALUE prev_inside;
|
||
|
|
||
|
prev = inv[count-1];
|
||
|
curr = *inv++;
|
||
|
prev_inside = prev->hx*plane->x + prev->hy*plane->y +
|
||
|
prev->hz*plane->z + prev->hw*plane->w;
|
||
|
for (i = count; i; i--)
|
||
|
{
|
||
|
curr_inside = curr->hx*plane->x + curr->hy*plane->y +
|
||
|
curr->hz*plane->z + curr->hw*plane->w;
|
||
|
// We interpolate always from the inside vertex to the outside vertex
|
||
|
// to reduce precision problems
|
||
|
if (FLOAT_LTZ(prev_inside))
|
||
|
{ // first point is outside
|
||
|
if (FLOAT_GEZ(curr_inside))
|
||
|
{ // second point is inside
|
||
|
// Find intersection and insert in into the output buffer
|
||
|
outv[out_count] = GET_NEW_CLIP_VERTEX;
|
||
|
Interpolate(pv,
|
||
|
outv[out_count],
|
||
|
curr, prev,
|
||
|
(prev->clip & CLIPPED_ENABLE) | dwClipFlag,
|
||
|
curr_inside, curr_inside - prev_inside);
|
||
|
out_count++;
|
||
|
}
|
||
|
} else
|
||
|
{ // first point is inside - put it to the output buffer first
|
||
|
outv[out_count++] = prev;
|
||
|
if (FLOAT_LTZ(curr_inside))
|
||
|
{ // second point is outside
|
||
|
// Find intersection and put it to the output buffer
|
||
|
outv[out_count] = GET_NEW_CLIP_VERTEX;
|
||
|
Interpolate(pv,
|
||
|
outv[out_count],
|
||
|
prev, curr,
|
||
|
dwClipFlag,
|
||
|
prev_inside, prev_inside - curr_inside);
|
||
|
out_count++;
|
||
|
}
|
||
|
}
|
||
|
prev = curr;
|
||
|
curr = *inv++;
|
||
|
prev_inside = curr_inside;
|
||
|
}
|
||
|
return out_count;
|
||
|
}
|
||
|
//-------------------------------------------------------------------------
|
||
|
// Clips a line by a plane
|
||
|
//
|
||
|
// Returns 1 if the line is outside the frustum, 0 otherwise
|
||
|
//
|
||
|
int ClipLineByPlane(D3DFE_PROCESSVERTICES *pv,
|
||
|
ClipTriangle *line,
|
||
|
D3DVECTORH *plane,
|
||
|
DWORD dwClipBit)
|
||
|
{
|
||
|
D3DVALUE in1, in2;
|
||
|
ClipVertex outv;
|
||
|
in1 = line->v[0]->hx * plane->x +
|
||
|
line->v[0]->hy * plane->y +
|
||
|
line->v[0]->hz * plane->z +
|
||
|
line->v[0]->hw * plane->w;
|
||
|
in2 = line->v[1]->hx * plane->x +
|
||
|
line->v[1]->hy * plane->y +
|
||
|
line->v[1]->hz * plane->z +
|
||
|
line->v[1]->hw * plane->w;
|
||
|
if (in1 < 0)
|
||
|
{
|
||
|
if (in2 < 0)
|
||
|
return 1;
|
||
|
Interpolate(pv, &outv, line->v[0], line->v[1],
|
||
|
dwClipBit, in1, in1 - in2);
|
||
|
*line->v[0] = outv;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (in2 < 0)
|
||
|
{
|
||
|
Interpolate(pv, &outv, line->v[0], line->v[1],
|
||
|
dwClipBit, in1, in1 - in2);
|
||
|
*line->v[1] = outv;
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
/*------------------------------------------------------------------------
|
||
|
* Calculate the screen coords for any new vertices
|
||
|
* introduced into the polygon.
|
||
|
*/
|
||
|
void ComputeScreenCoordinates(D3DFE_PROCESSVERTICES *pv,
|
||
|
ClipVertex **inv,
|
||
|
int count)
|
||
|
{
|
||
|
int i;
|
||
|
D3DFE_VIEWPORTCACHE& VPORT = pv->vcache;
|
||
|
|
||
|
for (i = 0; i < count; i++)
|
||
|
{
|
||
|
ClipVertex *p;
|
||
|
p = inv[i];
|
||
|
|
||
|
/*
|
||
|
* Catch any vertices that need screen co-ordinates generated.
|
||
|
* There are two possibilities
|
||
|
* 1) Vertices generated during interpolation
|
||
|
* 2) Vertices marked for clipping by the transform but
|
||
|
* not clipped here due to the finite precision
|
||
|
* of the floating point unit.
|
||
|
*/
|
||
|
|
||
|
if (p->clip & ~CLIPPED_ENABLE)
|
||
|
{
|
||
|
D3DVALUE w;
|
||
|
|
||
|
w = D3DVAL(1.0)/p->hw;
|
||
|
switch ((int)p->clip & (CLIPPED_LEFT|CLIPPED_RIGHT))
|
||
|
{
|
||
|
case CLIPPED_LEFT: p->sx = VPORT.minXgb; break;
|
||
|
case CLIPPED_RIGHT: p->sx = VPORT.maxXgb; break;
|
||
|
default:
|
||
|
p->sx = p->hx * VPORT.scaleX * w + VPORT.offsetX;
|
||
|
if (p->sx < VPORT.minXgb)
|
||
|
p->sx = VPORT.minXgb;
|
||
|
if (p->sx > VPORT.maxXgb)
|
||
|
p->sx = VPORT.maxXgb;
|
||
|
}
|
||
|
switch ((int)p->clip & (CLIPPED_TOP|CLIPPED_BOTTOM))
|
||
|
{
|
||
|
case CLIPPED_BOTTOM: p->sy = VPORT.maxYgb; break;
|
||
|
case CLIPPED_TOP: p->sy = VPORT.minYgb; break;
|
||
|
default:
|
||
|
p->sy = p->hy * VPORT.scaleY * w + VPORT.offsetY;
|
||
|
if (p->sy < VPORT.minYgb)
|
||
|
p->sy = VPORT.minYgb;
|
||
|
if (p->sy > VPORT.maxYgb)
|
||
|
p->sy = VPORT.maxYgb;
|
||
|
}
|
||
|
p->sz = p->hz * w * pv->vcache.scaleZ + pv->vcache.offsetZ;
|
||
|
p->rhw = w;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//---------------------------------------------------------------------
|
||
|
inline DWORD ComputeClipCodeUserPlanes(D3DFE_PROCESSVERTICES *pv, ClipVertex *p)
|
||
|
{
|
||
|
DWORD clip = 0;
|
||
|
DWORD dwClipBit = D3DCS_PLANE0;
|
||
|
for (DWORD i=0; i < pv->dwMaxUserClipPlanes; i++)
|
||
|
{
|
||
|
if ((p->hx*pv->userClipPlane[i].x +
|
||
|
p->hy*pv->userClipPlane[i].y +
|
||
|
p->hz*pv->userClipPlane[i].z +
|
||
|
p->hw*pv->userClipPlane[i].w) < 0)
|
||
|
{
|
||
|
clip |= dwClipBit;
|
||
|
}
|
||
|
dwClipBit <<= 1;
|
||
|
}
|
||
|
return clip;
|
||
|
}
|
||
|
//---------------------------------------------------------------------
|
||
|
inline DWORD ComputeClipCodeGB(D3DFE_PROCESSVERTICES *pv, ClipVertex *p)
|
||
|
{
|
||
|
DWORD clip = 0;
|
||
|
if (p->hx < p->hw * pv->vcache.Kgbx1)
|
||
|
clip |= __D3DCLIPGB_LEFT;
|
||
|
if (p->hx > p->hw * pv->vcache.Kgbx2)
|
||
|
clip |= __D3DCLIPGB_RIGHT;
|
||
|
if (p->hy < p->hw * pv->vcache.Kgby1)
|
||
|
clip |= __D3DCLIPGB_BOTTOM;
|
||
|
if (p->hy > p->hw * pv->vcache.Kgby2)
|
||
|
clip |= __D3DCLIPGB_TOP;
|
||
|
if (p->hz > p->hw)
|
||
|
clip |= D3DCS_BACK;
|
||
|
clip |= ComputeClipCodeUserPlanes(pv, p);
|
||
|
p->clip = (p->clip & (CLIPPED_ENABLE | CLIPPED_FRONT)) | clip;
|
||
|
return clip;
|
||
|
}
|
||
|
//---------------------------------------------------------------------
|
||
|
inline DWORD ComputeClipCode(D3DFE_PROCESSVERTICES *pv, ClipVertex *p)
|
||
|
{
|
||
|
DWORD clip = 0;
|
||
|
if (FLOAT_LTZ(p->hx))
|
||
|
clip |= D3DCS_LEFT;
|
||
|
if (p->hx > p->hw)
|
||
|
clip |= D3DCS_RIGHT;
|
||
|
if (FLOAT_LTZ(p->hy))
|
||
|
clip |= D3DCS_BOTTOM;
|
||
|
if (p->hy > p->hw)
|
||
|
clip |= D3DCS_TOP;
|
||
|
if (p->hz > p->hw)
|
||
|
clip |= D3DCS_BACK;
|
||
|
clip |= ComputeClipCodeUserPlanes(pv, p);
|
||
|
p->clip = (p->clip & (CLIPPED_ENABLE | CLIPPED_FRONT)) | clip;
|
||
|
return clip;
|
||
|
}
|
||
|
//***********************************************************************
|
||
|
//
|
||
|
// Returns 0, if triangle is clipped. Number of vertices otherwise.
|
||
|
//
|
||
|
// Original vertices should not be modified inside the function
|
||
|
//
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "ClipSingleTriangle"
|
||
|
|
||
|
int D3DFE_PVFUNCSI::ClipSingleTriangle(D3DFE_PROCESSVERTICES *pv,
|
||
|
ClipTriangle *tri,
|
||
|
ClipVertex ***clipVertexPointer)
|
||
|
{
|
||
|
int accept;
|
||
|
int i;
|
||
|
int count;
|
||
|
ClipVertex **inv;
|
||
|
ClipVertex **outv;
|
||
|
ClipVertex *p;
|
||
|
ULONG_PTR swapv;
|
||
|
|
||
|
CD3DFPstate D3DFPstate; // Sets optimal FPU state for D3D.
|
||
|
|
||
|
accept = (tri->v[0]->clip | tri->v[1]->clip | tri->v[2]->clip);
|
||
|
|
||
|
inv = tri->v;
|
||
|
|
||
|
count = 3;
|
||
|
outv = pv->ClipperState.clip_vbuf1;
|
||
|
pv->ClipperState.clip_color = tri->v[0]->color;
|
||
|
pv->ClipperState.clip_specular = tri->v[0]->specular;
|
||
|
|
||
|
/*
|
||
|
* XXX assumes sizeof(void*) == sizeof(unsigned long)
|
||
|
*/
|
||
|
{
|
||
|
ULONG_PTR tmp1;
|
||
|
ULONG_PTR tmp2;
|
||
|
|
||
|
tmp1 = (ULONG_PTR)pv->ClipperState.clip_vbuf1;
|
||
|
tmp2 = (ULONG_PTR)pv->ClipperState.clip_vbuf2;
|
||
|
|
||
|
swapv = tmp1 + tmp2;
|
||
|
}
|
||
|
pv->ClipperState.clip_vertices_used = 0;
|
||
|
|
||
|
#define SWAP(inv, outv) \
|
||
|
inv = outv; \
|
||
|
outv = (ClipVertex**) (swapv - (ULONG_PTR) outv)
|
||
|
|
||
|
if (accept & D3DCS_FRONT)
|
||
|
{
|
||
|
count = ClipFront(pv, inv, outv, count);
|
||
|
if (count < 3)
|
||
|
goto out_of_here;
|
||
|
SWAP(inv, outv);
|
||
|
}
|
||
|
if (pv->dwDeviceFlags & D3DDEV_GUARDBAND)
|
||
|
{
|
||
|
// If there was clipping by the front plane it is better to
|
||
|
// compute clip code for new vertices and re-compute accept.
|
||
|
// Otherwise we will try to clip by sides when it is not necessary
|
||
|
if (accept & D3DCS_FRONT)
|
||
|
{
|
||
|
accept = 0;
|
||
|
for (i = 0; i < count; i++)
|
||
|
{
|
||
|
ClipVertex *p;
|
||
|
p = inv[i];
|
||
|
if (p->clip & CLIPPED_FRONT)
|
||
|
accept |= ComputeClipCodeGB(pv, p);
|
||
|
else
|
||
|
accept |= p->clip;
|
||
|
}
|
||
|
}
|
||
|
if (accept & D3DCS_BACK)
|
||
|
{
|
||
|
count = ClipBack(pv, inv, outv, count);
|
||
|
if (count < 3)
|
||
|
goto out_of_here;
|
||
|
SWAP(inv, outv);
|
||
|
}
|
||
|
if (accept & __D3DCLIPGB_LEFT)
|
||
|
{
|
||
|
count = ClipLeftGB(pv, inv, outv, count);
|
||
|
if (count < 3)
|
||
|
goto out_of_here;
|
||
|
SWAP(inv, outv);
|
||
|
}
|
||
|
if (accept & __D3DCLIPGB_RIGHT)
|
||
|
{
|
||
|
count = ClipRightGB(pv, inv, outv, count);
|
||
|
if (count < 3)
|
||
|
goto out_of_here;
|
||
|
SWAP(inv, outv);
|
||
|
}
|
||
|
if (accept & __D3DCLIPGB_BOTTOM)
|
||
|
{
|
||
|
count = ClipBottomGB(pv, inv, outv, count);
|
||
|
if (count < 3)
|
||
|
goto out_of_here;
|
||
|
SWAP(inv, outv);
|
||
|
}
|
||
|
if (accept & __D3DCLIPGB_TOP)
|
||
|
{
|
||
|
count = ClipTopGB(pv, inv, outv, count);
|
||
|
if (count < 3)
|
||
|
goto out_of_here;
|
||
|
SWAP(inv, outv);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// If there was clipping by the front plane it is better to
|
||
|
// compute clip code for new vertices and re-compute accept.
|
||
|
// Otherwise we will try to clip by sides when it is not necessary
|
||
|
if (accept & D3DCS_FRONT)
|
||
|
{
|
||
|
accept = 0;
|
||
|
for (i = 0; i < count; i++)
|
||
|
{
|
||
|
ClipVertex *p;
|
||
|
p = inv[i];
|
||
|
if (p->clip & (CLIPPED_FRONT))
|
||
|
accept |= ComputeClipCode(pv, p);
|
||
|
else
|
||
|
accept |= p->clip;
|
||
|
}
|
||
|
}
|
||
|
if (accept & D3DCS_BACK)
|
||
|
{
|
||
|
count = ClipBack(pv, inv, outv, count);
|
||
|
if (count < 3)
|
||
|
goto out_of_here;
|
||
|
SWAP(inv, outv);
|
||
|
}
|
||
|
if (accept & D3DCS_LEFT)
|
||
|
{
|
||
|
count = ClipLeft(pv, inv, outv, count);
|
||
|
if (count < 3)
|
||
|
goto out_of_here;
|
||
|
SWAP(inv, outv);
|
||
|
}
|
||
|
if (accept & D3DCS_RIGHT)
|
||
|
{
|
||
|
count = ClipRight(pv, inv, outv, count);
|
||
|
if (count < 3)
|
||
|
goto out_of_here;
|
||
|
SWAP(inv, outv);
|
||
|
}
|
||
|
if (accept & D3DCS_BOTTOM)
|
||
|
{
|
||
|
count = ClipBottom(pv, inv, outv, count);
|
||
|
if (count < 3)
|
||
|
goto out_of_here;
|
||
|
SWAP(inv, outv);
|
||
|
}
|
||
|
if (accept & D3DCS_TOP)
|
||
|
{
|
||
|
count = ClipTop(pv, inv, outv, count);
|
||
|
if (count < 3)
|
||
|
goto out_of_here;
|
||
|
SWAP(inv, outv);
|
||
|
}
|
||
|
}
|
||
|
if (pv->dwMaxUserClipPlanes)
|
||
|
{
|
||
|
DWORD dwClipBit = D3DCS_PLANE0;
|
||
|
DWORD dwClippedBit = CLIPPED_PLANE0;
|
||
|
for (DWORD i=0; i < pv->dwMaxUserClipPlanes; i++)
|
||
|
{
|
||
|
if (accept & dwClipBit)
|
||
|
{
|
||
|
count = ClipByPlane(pv, inv, outv, &pv->userClipPlane[i],
|
||
|
dwClippedBit, count);
|
||
|
if (count < 3)
|
||
|
goto out_of_here;
|
||
|
SWAP(inv, outv);
|
||
|
}
|
||
|
dwClipBit <<= 1;
|
||
|
dwClippedBit <<= 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#undef SWAP
|
||
|
|
||
|
ComputeScreenCoordinates(pv, inv, count);
|
||
|
|
||
|
*clipVertexPointer = inv;
|
||
|
pv->ClipperState.current_vbuf = inv;
|
||
|
return count;
|
||
|
|
||
|
out_of_here:
|
||
|
|
||
|
*clipVertexPointer = NULL;
|
||
|
return 0;
|
||
|
}
|
||
|
//*************************************************************************
|
||
|
//
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "ClipSingleLine"
|
||
|
|
||
|
int D3DFE_PVFUNCSI::ClipSingleLine(D3DFE_PROCESSVERTICES *pv,
|
||
|
ClipTriangle *line)
|
||
|
{
|
||
|
int accept;
|
||
|
D3DVALUE in1, in2;
|
||
|
|
||
|
CD3DFPstate D3DFPstate; // Sets optimal FPU state for D3D.
|
||
|
|
||
|
accept = (line->v[0]->clip | line->v[1]->clip);
|
||
|
|
||
|
pv->ClipperState.clip_color = line->v[0]->color;
|
||
|
pv->ClipperState.clip_specular = line->v[0]->specular;
|
||
|
|
||
|
if (accept & D3DCS_FRONT)
|
||
|
if (ClipLineFront(pv, line))
|
||
|
goto out_of_here;
|
||
|
if (pv->dwDeviceFlags & D3DDEV_GUARDBAND)
|
||
|
{
|
||
|
// If there was clipping by the front plane it is better to
|
||
|
// compute clip code for new vertices and re-compute accept.
|
||
|
// Otherwise we will try to clip by sides when it is not necessary
|
||
|
if (accept & D3DCS_FRONT)
|
||
|
{
|
||
|
ClipVertex * p;
|
||
|
accept = 0;
|
||
|
p = line->v[0];
|
||
|
if (p->clip & CLIPPED_FRONT)
|
||
|
accept |= ComputeClipCodeGB(pv, p);
|
||
|
else
|
||
|
accept |= p->clip;
|
||
|
p = line->v[1];
|
||
|
if (p->clip & CLIPPED_FRONT)
|
||
|
accept |= ComputeClipCodeGB(pv, p);
|
||
|
else
|
||
|
accept |= p->clip;
|
||
|
}
|
||
|
if (accept & D3DCS_BACK)
|
||
|
if (ClipLineBack(pv, line))
|
||
|
goto out_of_here;
|
||
|
if (accept & __D3DCLIPGB_LEFT)
|
||
|
if (ClipLineLeftGB(pv, line))
|
||
|
goto out_of_here;
|
||
|
if (accept & __D3DCLIPGB_RIGHT)
|
||
|
if (ClipLineRightGB(pv, line))
|
||
|
goto out_of_here;
|
||
|
if (accept & __D3DCLIPGB_TOP)
|
||
|
if (ClipLineTopGB(pv, line))
|
||
|
goto out_of_here;
|
||
|
if (accept & __D3DCLIPGB_BOTTOM)
|
||
|
if (ClipLineBottomGB(pv, line))
|
||
|
goto out_of_here;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// If there was clipping by the front plane it is better to
|
||
|
// compute clip code for new vertices and re-compute accept.
|
||
|
// Otherwise we will try to clip by sides when it is not necessary
|
||
|
if (accept & D3DCS_FRONT)
|
||
|
{
|
||
|
ClipVertex * p;
|
||
|
accept = 0;
|
||
|
p = line->v[0];
|
||
|
if (p->clip & CLIPPED_FRONT)
|
||
|
accept |= ComputeClipCode(pv, p);
|
||
|
else
|
||
|
accept |= p->clip;
|
||
|
p = line->v[1];
|
||
|
if (p->clip & CLIPPED_FRONT)
|
||
|
accept |= ComputeClipCode(pv, p);
|
||
|
else
|
||
|
accept |= p->clip;
|
||
|
}
|
||
|
if (accept & D3DCS_BACK)
|
||
|
if (ClipLineBack(pv, line))
|
||
|
goto out_of_here;
|
||
|
if (accept & D3DCS_LEFT)
|
||
|
if (ClipLineLeft(pv, line))
|
||
|
goto out_of_here;
|
||
|
if (accept & D3DCS_RIGHT)
|
||
|
if (ClipLineRight(pv, line))
|
||
|
goto out_of_here;
|
||
|
if (accept & D3DCS_TOP)
|
||
|
if (ClipLineTop(pv, line))
|
||
|
goto out_of_here;
|
||
|
if (accept & D3DCS_BOTTOM)
|
||
|
if (ClipLineBottom(pv, line))
|
||
|
goto out_of_here;
|
||
|
}
|
||
|
if (pv->dwMaxUserClipPlanes)
|
||
|
{
|
||
|
DWORD dwClipBit = D3DCS_PLANE0;
|
||
|
DWORD dwClippedBit = CLIPPED_PLANE0;
|
||
|
for (DWORD i=0; i < pv->dwMaxUserClipPlanes; i++)
|
||
|
{
|
||
|
if (accept & dwClipBit)
|
||
|
{
|
||
|
if (ClipLineByPlane(pv, line, &pv->userClipPlane[i],
|
||
|
dwClippedBit))
|
||
|
goto out_of_here;
|
||
|
}
|
||
|
dwClipBit <<= 1;
|
||
|
dwClippedBit <<= 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ComputeScreenCoordinates(pv, line->v, 2);
|
||
|
|
||
|
return 1;
|
||
|
out_of_here:
|
||
|
return 0;
|
||
|
} // ClipSingleLine
|
||
|
//----------------------------------------------------------------------
|
||
|
// GenClipFlags() Generates clip flags for a set of FVF
|
||
|
//
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "GenClipFlags"
|
||
|
|
||
|
DWORD D3DFE_GenClipFlags(D3DFE_PROCESSVERTICES *pv)
|
||
|
{
|
||
|
DWORD clip_intersection, clip_union;
|
||
|
float left = pv->vcache.minX;
|
||
|
float top = pv->vcache.minY;
|
||
|
float right = pv->vcache.maxX;
|
||
|
float bottom = pv->vcache.maxY;
|
||
|
float leftgb ; // Guard band window
|
||
|
float topgb ;
|
||
|
float rightgb ;
|
||
|
float bottomgb;
|
||
|
DWORD clipZF, clipZB;
|
||
|
DWORD stride = pv->position.dwStride;
|
||
|
|
||
|
clipZF = pv->lpdwRStates[D3DRENDERSTATE_ZENABLE] ? D3DCS_FRONT : 0;
|
||
|
clipZB = pv->lpdwRStates[D3DRENDERSTATE_ZENABLE] ? D3DCS_BACK : 0;
|
||
|
|
||
|
clip_intersection = (DWORD)~0;
|
||
|
clip_union = (DWORD)0;
|
||
|
|
||
|
if (pv->dwDeviceFlags & D3DDEV_GUARDBAND)
|
||
|
{
|
||
|
leftgb = pv->vcache.minXgb;
|
||
|
topgb = pv->vcache.minYgb;
|
||
|
rightgb = pv->vcache.maxXgb;
|
||
|
bottomgb = pv->vcache.maxYgb;
|
||
|
}
|
||
|
/* Only generate clip flags */
|
||
|
D3DTLVERTEX *lpVertices = (D3DTLVERTEX*)pv->position.lpvData;
|
||
|
D3DFE_CLIPCODE *clipCode = pv->lpClipFlags;
|
||
|
DWORD i;
|
||
|
|
||
|
// Point sprites are clipped only by Z planes. Clipping by X and Y planes
|
||
|
// will be done when we expand point sprites
|
||
|
if (pv->primType == D3DPT_POINTLIST &&
|
||
|
pv->dwDeviceFlags & D3DDEV_DOPOINTSPRITEEMULATION)
|
||
|
{
|
||
|
for (i = pv->dwNumVertices; i; i--)
|
||
|
{
|
||
|
DWORD clip = 0;
|
||
|
D3DVALUE x,y,z;
|
||
|
if (lpVertices->rhw < 0)
|
||
|
{
|
||
|
x = -lpVertices->sx;
|
||
|
y = -lpVertices->sy;
|
||
|
z = -lpVertices->sz;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
x = lpVertices->sx;
|
||
|
y = lpVertices->sy;
|
||
|
z = lpVertices->sz;
|
||
|
}
|
||
|
|
||
|
if (z < 0.0f)
|
||
|
clip |= clipZF;
|
||
|
else
|
||
|
if (z >= 1.0f)
|
||
|
clip |= clipZB;
|
||
|
|
||
|
clip_intersection &= clip;
|
||
|
clip_union |= clip;
|
||
|
*clipCode++ = (D3DFE_CLIPCODE)clip;
|
||
|
lpVertices = (D3DTLVERTEX*)((char*)lpVertices + stride);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
for (i = pv->dwNumVertices; i; i--)
|
||
|
{
|
||
|
DWORD clip = 0;
|
||
|
D3DVALUE x,y,z;
|
||
|
if (lpVertices->rhw < 0)
|
||
|
{
|
||
|
x = -lpVertices->sx;
|
||
|
y = -lpVertices->sy;
|
||
|
z = -lpVertices->sz;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
x = lpVertices->sx;
|
||
|
y = lpVertices->sy;
|
||
|
z = lpVertices->sz;
|
||
|
}
|
||
|
|
||
|
if (x < left)
|
||
|
clip |= D3DCS_LEFT;
|
||
|
else
|
||
|
if (x >= right)
|
||
|
clip |= D3DCS_RIGHT;
|
||
|
|
||
|
if (y < top)
|
||
|
clip |= D3DCS_TOP;
|
||
|
else
|
||
|
if (y >= bottom)
|
||
|
clip |= D3DCS_BOTTOM;
|
||
|
|
||
|
if (z < 0.0f)
|
||
|
clip |= clipZF;
|
||
|
else
|
||
|
if (z >= 1.0f)
|
||
|
clip |= clipZB;
|
||
|
|
||
|
if (pv->dwDeviceFlags & D3DDEV_GUARDBAND && clip)
|
||
|
{
|
||
|
if (x < leftgb)
|
||
|
clip |= __D3DCLIPGB_LEFT;
|
||
|
else
|
||
|
if (x >= rightgb)
|
||
|
clip |= __D3DCLIPGB_RIGHT;
|
||
|
|
||
|
if (y < topgb)
|
||
|
clip |= __D3DCLIPGB_TOP;
|
||
|
else
|
||
|
if (y >= bottomgb)
|
||
|
clip |= __D3DCLIPGB_BOTTOM;
|
||
|
}
|
||
|
|
||
|
clip_intersection &= clip;
|
||
|
clip_union |= clip;
|
||
|
*clipCode++ = (D3DFE_CLIPCODE)clip;
|
||
|
lpVertices = (D3DTLVERTEX*)((char*)lpVertices + stride);
|
||
|
}
|
||
|
pv->dwClipIntersection = clip_intersection;
|
||
|
pv->dwClipUnion = clip_union;
|
||
|
|
||
|
return clip_intersection;
|
||
|
} // end of GenClipFlags()
|
||
|
//---------------------------------------------------------------------
|
||
|
// Make clip vertex from D3D vertex
|
||
|
//
|
||
|
// device - CD3DHal *
|
||
|
// pp1 - clipVertex
|
||
|
// p1 - TL vertex
|
||
|
//
|
||
|
void MAKE_CLIP_VERTEX_FVF(D3DFE_PROCESSVERTICES *pv, ClipVertex& pp1, BYTE* p1,
|
||
|
DWORD clipFlag, BOOL transformed)
|
||
|
{
|
||
|
D3DFE_VIEWPORTCACHE& VPORT = pv->vcache;
|
||
|
BYTE *v = (BYTE*)p1;
|
||
|
if (transformed || !(clipFlag & pv->dwClipMaskOffScreen))
|
||
|
{
|
||
|
pp1.sx = ((D3DVALUE*)v)[0];
|
||
|
pp1.sy = ((D3DVALUE*)v)[1];
|
||
|
pp1.sz = ((D3DVALUE*)v)[2];
|
||
|
pp1.rhw = ((D3DVALUE*)v)[3];
|
||
|
pp1.hw = 1.0f / ((D3DVALUE*)v)[3];
|
||
|
pp1.hx = (pp1.sx - VPORT.offsetX) * pp1.hw * VPORT.scaleXi;
|
||
|
pp1.hy = (pp1.sy - VPORT.offsetY) * pp1.hw * VPORT.scaleYi;
|
||
|
pp1.hz = (pp1.sz - VPORT.offsetZ) * pp1.hw * VPORT.scaleZi;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pp1.hx = ((D3DVALUE*)v)[0];
|
||
|
pp1.hy = ((D3DVALUE*)v)[1];
|
||
|
pp1.hz = ((D3DVALUE*)v)[2];
|
||
|
pp1.hw = ((D3DVALUE*)v)[3];
|
||
|
}
|
||
|
v += sizeof(D3DVALUE) * 4;
|
||
|
if (pv->dwVIDOut & D3DFVF_DIFFUSE)
|
||
|
{
|
||
|
pp1.color = *(DWORD*)v;
|
||
|
v += sizeof(D3DVALUE);
|
||
|
|
||
|
}
|
||
|
if (pv->dwVIDOut & D3DFVF_SPECULAR)
|
||
|
{
|
||
|
pp1.specular= *(DWORD*)v;
|
||
|
v += sizeof(DWORD);
|
||
|
}
|
||
|
memcpy(pp1.tex, v, pv->dwTextureCoordSizeTotal);
|
||
|
pp1.clip = clipFlag;
|
||
|
}
|