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.
1521 lines
51 KiB
1521 lines
51 KiB
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
#define GET_NEW_CLIP_VERTEX \
|
|
&m_clipping.clip_vertices[m_clipping.clip_vertices_used++];
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
inline void
|
|
InterpolateColor(RRCLIPVTX *out,
|
|
RRCLIPVTX *p1,
|
|
RRCLIPVTX *p2,
|
|
D3DVALUE num_denom )
|
|
{
|
|
int r1, g1, b1, a1;
|
|
int r2, g2, b2, a2;
|
|
|
|
r1 = RGBA_GETRED(p1->color);
|
|
g1 = RGBA_GETGREEN(p1->color);
|
|
b1 = RGBA_GETBLUE(p1->color);
|
|
a1 = RGBA_GETALPHA(p1->color);
|
|
r2 = RGBA_GETRED(p2->color);
|
|
g2 = RGBA_GETGREEN(p2->color);
|
|
b2 = RGBA_GETBLUE(p2->color);
|
|
a2 = RGBA_GETALPHA(p2->color);
|
|
out->color = RGBA_MAKE((WORD)(r1 + (r2 - r1) * num_denom),
|
|
(WORD)(g1 + (g2 - g1) * num_denom),
|
|
(WORD)(b1 + (b2 - b1) * num_denom),
|
|
(WORD)(a1 + (a2 - a1) * num_denom));
|
|
}
|
|
//---------------------------------------------------------------------
|
|
inline void
|
|
InterpolateSpecular(RRCLIPVTX *out,
|
|
RRCLIPVTX *p1,
|
|
RRCLIPVTX *p2,
|
|
D3DVALUE num_denom )
|
|
{
|
|
int r1, g1, b1, a1;
|
|
int r2, g2, b2, a2;
|
|
|
|
r1 = RGBA_GETRED(p1->specular);
|
|
g1 = RGBA_GETGREEN(p1->specular);
|
|
b1 = RGBA_GETBLUE(p1->specular);
|
|
a1 = RGBA_GETALPHA(p1->specular);
|
|
r2 = RGBA_GETRED(p2->specular);
|
|
g2 = RGBA_GETGREEN(p2->specular);
|
|
b2 = RGBA_GETBLUE(p2->specular);
|
|
a2 = RGBA_GETALPHA(p2->specular);
|
|
out->specular = RGBA_MAKE((WORD)(r1 + (r2 - r1) * num_denom),
|
|
(WORD)(g1 + (g2 - g1) * num_denom),
|
|
(WORD)(b1 + (b2 - b1) * num_denom),
|
|
(WORD)(a1 + (a2 - a1) * num_denom));
|
|
}
|
|
//---------------------------------------------------------------------
|
|
// Inline texture coordinate difference.
|
|
__inline FLOAT
|
|
TextureDiff(FLOAT fTb, FLOAT fTa, INT iMode)
|
|
{
|
|
FLOAT fDiff1 = fTb - fTa;
|
|
|
|
if (iMode == 0)
|
|
{
|
|
// Wrap not set, return plain difference.
|
|
return fDiff1;
|
|
}
|
|
else
|
|
{
|
|
FLOAT fDiff2;
|
|
|
|
// Wrap set, compute shortest distance of plain difference
|
|
// and wrap difference.
|
|
|
|
fDiff2 = fDiff1;
|
|
if (FLOAT_LTZ(fDiff1))
|
|
{
|
|
fDiff2 += g_fOne;
|
|
}
|
|
else if (FLOAT_GTZ(fDiff1))
|
|
{
|
|
fDiff2 -= g_fOne;
|
|
}
|
|
if (ABSF(fDiff1) < ABSF(fDiff2))
|
|
{
|
|
return fDiff1;
|
|
}
|
|
else
|
|
{
|
|
return fDiff2;
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
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;
|
|
}
|
|
}
|
|
//
|
|
// Clipping a triangle by a plane
|
|
//
|
|
// Returns number of vertices in the clipped triangle
|
|
//
|
|
int
|
|
RRProcessVertices::ClipByPlane( RRCLIPVTX **inv,
|
|
RRCLIPVTX **outv,
|
|
RRVECTOR4 *plane,
|
|
DWORD dwClipFlag,
|
|
int count )
|
|
{
|
|
int i;
|
|
int out_count = 0;
|
|
RRCLIPVTX *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( 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( 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
|
|
RRProcessVertices::ClipLineByPlane(RRCLIPTRIANGLE *line,
|
|
RRVECTOR4 *plane,
|
|
DWORD dwClipBit)
|
|
{
|
|
D3DVALUE in1, in2;
|
|
RRCLIPVTX 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( &outv, line->v[0], line->v[1],
|
|
dwClipBit, in1, in1 - in2);
|
|
*line->v[0] = outv;
|
|
}
|
|
else
|
|
{
|
|
if (in2 < 0)
|
|
{
|
|
Interpolate( &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(const RRVIEWPORTDATA& VData,
|
|
RRCLIPVTX **inv, int count)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
RRCLIPVTX *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 = VData.minXgb; break;
|
|
case CLIPPED_RIGHT: p->sx = VData.maxXgb; break;
|
|
default:
|
|
p->sx = p->hx * VData.scaleX * w + VData.offsetX;
|
|
if (p->sx < VData.minXgb)
|
|
p->sx = VData.minXgb;
|
|
if (p->sx > VData.maxXgb)
|
|
p->sx = VData.maxXgb;
|
|
}
|
|
switch ((int)p->clip & (CLIPPED_TOP|CLIPPED_BOTTOM))
|
|
{
|
|
case CLIPPED_BOTTOM: p->sy = VData.maxYgb; break;
|
|
case CLIPPED_TOP: p->sy = VData.minYgb; break;
|
|
default:
|
|
p->sy = p->hy * VData.scaleY * w + VData.offsetY;
|
|
if (p->sy < VData.minYgb)
|
|
p->sy = VData.minYgb;
|
|
if (p->sy > VData.maxYgb)
|
|
p->sy = VData.maxYgb;
|
|
}
|
|
p->sz = p->hz * VData.scaleZ * w + VData.offsetZ;
|
|
p->rhw = w;
|
|
}
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------
|
|
void
|
|
RRProcessVertices::Interpolate(RRCLIPVTX *out,
|
|
RRCLIPVTX *p1,
|
|
RRCLIPVTX *p2,
|
|
int code,
|
|
D3DVALUE num,
|
|
D3DVALUE denom)
|
|
{
|
|
DWORD dwInterpolate = m_clipping.dwInterpolate;
|
|
D3DVALUE num_denom = num / denom;
|
|
|
|
out->clip = (((int)p1->clip & (int)p2->clip) & ~CLIPPED_ENABLE) | code;
|
|
out->hx = p1->hx + (p2->hx - p1->hx) * num_denom;
|
|
out->hy = p1->hy + (p2->hy - p1->hy) * num_denom;
|
|
out->hz = p1->hz + (p2->hz - p1->hz) * num_denom;
|
|
out->hw = p1->hw + (p2->hw - p1->hw) * num_denom;
|
|
out->color = m_clipping.clip_color;
|
|
out->specular = m_clipping.clip_specular;
|
|
|
|
/*
|
|
* Interpolate any other color model or quality dependent values.
|
|
*/
|
|
if (dwInterpolate & RRCLIP_INTERPOLATE_COLOR)
|
|
{
|
|
InterpolateColor(out, p1, p2, num_denom);
|
|
}
|
|
|
|
if (dwInterpolate & RRCLIP_INTERPOLATE_SPECULAR)
|
|
{
|
|
InterpolateSpecular(out, p1, p2, num_denom);
|
|
}
|
|
|
|
if (dwInterpolate & RRCLIP_INTERPOLATE_TEXTURE)
|
|
{
|
|
// Assume that D3DRENDERSTATE_WRAPi are sequential
|
|
D3DVALUE *pTexture1 = p1->tex;
|
|
D3DVALUE *pTexture2 = p2->tex;
|
|
D3DVALUE *pTexture = out->tex;
|
|
for (DWORD i = 0; i < m_dwNumTexCoords; i++)
|
|
{
|
|
DWORD wrapState = ((ReferenceRasterizer *)this)->GetRenderState()[D3DRENDERSTATE_WRAP0 + i];
|
|
DWORD n = (DWORD)(m_dwTexCoordSize[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++;
|
|
}
|
|
}
|
|
}
|
|
if (dwInterpolate & RRCLIP_INTERPOLATE_S)
|
|
{
|
|
out->s = p1->s + (p2->s - p1->s) * num_denom;
|
|
}
|
|
if (dwInterpolate & RRCLIP_INTERPOLATE_EYENORMAL)
|
|
{
|
|
out->eyenx = p1->eyenx + (p2->eyenx - p1->eyenx) * num_denom;
|
|
out->eyeny = p1->eyeny + (p2->eyeny - p1->eyeny) * num_denom;
|
|
out->eyenz = p1->eyenz + (p2->eyenz - p1->eyenz) * num_denom;
|
|
}
|
|
if (dwInterpolate & RRCLIP_INTERPOLATE_EYEXYZ)
|
|
{
|
|
out->eyex = p1->eyex + (p2->eyex - p1->eyex) * num_denom;
|
|
out->eyey = p1->eyey + (p2->eyey - p1->eyey) * num_denom;
|
|
out->eyez = p1->eyez + (p2->eyez - p1->eyez) * num_denom;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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
|
|
|
|
//---------------------------------------------------------------------
|
|
inline DWORD ComputeClipCodeUserPlanes( RRUSERCLIPPLANE *UserPlanes,
|
|
RRCLIPVTX *p)
|
|
{
|
|
DWORD clip = 0;
|
|
DWORD dwClipBit = RRCLIP_USERCLIPPLANE0;
|
|
for( DWORD j=0; j<RRMAX_USER_CLIPPLANES; j++)
|
|
{
|
|
if( UserPlanes[j].bActive )
|
|
{
|
|
RRVECTOR4& plane = UserPlanes[j].plane;
|
|
if( (p->hx*plane.x +
|
|
p->hy*plane.y +
|
|
p->hz*plane.z +
|
|
p->hw*plane.w) < 0 )
|
|
{
|
|
clip |= dwClipBit;
|
|
}
|
|
}
|
|
dwClipBit <<= 1;
|
|
}
|
|
return clip;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
inline DWORD ComputeClipCodeGB(const RRVIEWPORTDATA& VData,
|
|
RRUSERCLIPPLANE *UserPlanes, RRCLIPVTX *p)
|
|
{
|
|
DWORD clip = 0;
|
|
if (p->hx < p->hw * VData.Kgbx1)
|
|
clip |= RRCLIPGB_LEFT;
|
|
if (p->hx > p->hw * VData.Kgbx2)
|
|
clip |= RRCLIPGB_RIGHT;
|
|
if (p->hy < p->hw * VData.Kgby1)
|
|
clip |= RRCLIPGB_BOTTOM;
|
|
if (p->hy > p->hw * VData.Kgby2)
|
|
clip |= RRCLIPGB_TOP;
|
|
if (p->hz > p->hw)
|
|
clip |= RRCLIP_BACK;
|
|
clip |= ComputeClipCodeUserPlanes(UserPlanes, p);
|
|
p->clip = (p->clip & (CLIPPED_ENABLE | CLIPPED_FRONT)) | clip;
|
|
return clip;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
inline DWORD ComputeClipCode(RRUSERCLIPPLANE *UserPlanes, RRCLIPVTX *p)
|
|
{
|
|
DWORD clip = 0;
|
|
if (FLOAT_LTZ(p->hx))
|
|
clip |= RRCLIP_LEFT;
|
|
if (p->hx > p->hw)
|
|
clip |= RRCLIP_RIGHT;
|
|
if (FLOAT_LTZ(p->hy))
|
|
clip |= RRCLIP_BOTTOM;
|
|
if (p->hy > p->hw)
|
|
clip |= RRCLIP_TOP;
|
|
if (p->hz > p->hw)
|
|
clip |= RRCLIP_BACK;
|
|
clip |= ComputeClipCodeUserPlanes(UserPlanes, p);
|
|
p->clip = (p->clip & (CLIPPED_ENABLE | CLIPPED_FRONT)) | clip;
|
|
return clip;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// RRProcessVertices::UpdateClippingData
|
|
// Updates clipping data used by ProcessVertices
|
|
//---------------------------------------------------------------------
|
|
HRESULT
|
|
RRProcessVertices::UpdateClippingData( DWORD dwClipPlanesEnable )
|
|
{
|
|
HRESULT hr = D3D_OK;
|
|
|
|
// Update the user defined clip plane data
|
|
for( DWORD i=0; i<RRMAX_USER_CLIPPLANES; i++ )
|
|
{
|
|
// Figure out if it is active
|
|
m_xfmUserClipPlanes[i].bActive = (BOOL)(dwClipPlanesEnable & 0x1);
|
|
dwClipPlanesEnable >>= 1;
|
|
|
|
// If it is active, transform it into eye-space using the
|
|
// view transform. The clip planes are defined in the
|
|
// world space.
|
|
if( m_xfmUserClipPlanes[i].bActive )
|
|
{
|
|
XformPlaneBy4x4Transposed( &m_userClipPlanes[i],
|
|
&m_TransformData.m_VPSInv,
|
|
&m_xfmUserClipPlanes[i].plane );
|
|
}
|
|
}
|
|
m_dwDirtyFlags &= ~(RRPV_DIRTY_CLIPPLANES);
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// DrawOneClippedPrimitive
|
|
//
|
|
// Draw one clipped primitive.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
RRProcessVertices::DrawOneClippedPrimitive()
|
|
{
|
|
INT i;
|
|
PUINT8 pV0, pV1, pV2;
|
|
HRESULT hr;
|
|
PUINT8 pVtx = (PUINT8) m_pvOut;
|
|
RRCLIPCODE *pClip = m_pClipBuf;
|
|
RRCLIPCODE c0, c1, c2;
|
|
|
|
switch (m_primType)
|
|
{
|
|
case D3DPT_POINTLIST:
|
|
for (i = (INT)m_dwNumVertices; i > 0; i--)
|
|
{
|
|
c0 = *pClip++;
|
|
((ReferenceRasterizer *)this)->DrawClippedPoint(pVtx, c0);
|
|
pVtx += m_dwOutputVtxSize;
|
|
}
|
|
break;
|
|
|
|
case D3DPT_LINELIST:
|
|
for (i = (INT)m_dwNumVertices / 2; i > 0; i--)
|
|
{
|
|
pV0 = pVtx;
|
|
pVtx += m_dwOutputVtxSize;
|
|
c0 = *pClip++;
|
|
pV1 = pVtx;
|
|
pVtx += m_dwOutputVtxSize;
|
|
c1 = *pClip++;
|
|
((ReferenceRasterizer *)this)->DrawClippedLine(pV0, c0,
|
|
pV1, c1);
|
|
}
|
|
break;
|
|
case D3DPT_LINESTRIP:
|
|
{
|
|
pV1 = pVtx;
|
|
c1 = *pClip;
|
|
|
|
// Disable last-pixel setting for shared verties and store prestate.
|
|
((ReferenceRasterizer *)this)->StoreLastPixelState(TRUE);
|
|
|
|
// Initial pV0.
|
|
for (i = (INT)m_dwNumVertices - 1; i > 1; i--)
|
|
{
|
|
pV0 = pV1;
|
|
c0 = c1;
|
|
pVtx += m_dwOutputVtxSize;
|
|
pV1 = pVtx;
|
|
c1 = *(++pClip);
|
|
((ReferenceRasterizer *)this)->DrawClippedLine(pV0, c0,
|
|
pV1, c1);
|
|
}
|
|
|
|
// Restore last-pixel setting.
|
|
((ReferenceRasterizer *)this)->StoreLastPixelState(FALSE);
|
|
|
|
// Draw last line with last-pixel setting from state.
|
|
if (i == 1)
|
|
{
|
|
pV0 = pVtx + m_dwOutputVtxSize;
|
|
c0 = *(++pClip);
|
|
((ReferenceRasterizer *)this)->DrawClippedLine(pV1, c1,
|
|
pV0, c0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case D3DPT_TRIANGLELIST:
|
|
for (i = (INT)m_dwNumVertices; i > 0; i -= 3)
|
|
{
|
|
pV0 = pVtx;
|
|
pVtx += m_dwOutputVtxSize;
|
|
c0 = *pClip++;
|
|
|
|
pV1 = pVtx;
|
|
pVtx += m_dwOutputVtxSize;
|
|
c1 = *pClip++;
|
|
|
|
pV2 = pVtx;
|
|
pVtx += m_dwOutputVtxSize;
|
|
c2 = *pClip++;
|
|
|
|
((ReferenceRasterizer *)this)->DrawClippedTriangle(pV0, c0,
|
|
pV1, c1,
|
|
pV2, c2);
|
|
}
|
|
break;
|
|
case D3DPT_TRIANGLESTRIP:
|
|
{
|
|
// Get initial vertex values.
|
|
pV1 = pVtx;
|
|
pVtx += m_dwOutputVtxSize;
|
|
c1 = *pClip++;
|
|
pV2 = pVtx;
|
|
pVtx += m_dwOutputVtxSize;
|
|
c2 = *pClip++;
|
|
|
|
for (i = (INT)m_dwNumVertices - 2; i > 1; i -= 2)
|
|
{
|
|
pV0 = pV1; c0 = c1;
|
|
pV1 = pV2; c1 = c2;
|
|
pV2 = pVtx;
|
|
pVtx += m_dwOutputVtxSize;
|
|
c2 = *pClip++;
|
|
((ReferenceRasterizer *)this)->DrawClippedTriangle(pV0, c0,
|
|
pV1, c1,
|
|
pV2, c2);
|
|
|
|
pV0 = pV1; c0 = c1;
|
|
pV1 = pV2; c1 = c2;
|
|
pV2 = pVtx;
|
|
pVtx += m_dwOutputVtxSize;
|
|
c2 = *pClip++;
|
|
((ReferenceRasterizer *)this)->DrawClippedTriangle(pV0, c0,
|
|
pV2, c2,
|
|
pV1, c1);
|
|
}
|
|
|
|
if (i > 0)
|
|
{
|
|
pV0 = pV1; c0 = c1;
|
|
pV1 = pV2; c1 = c2;
|
|
pV2 = pVtx; c2 = *pClip;
|
|
((ReferenceRasterizer *)this)->DrawClippedTriangle(pV0, c0,
|
|
pV1, c1,
|
|
pV2, c2);
|
|
}
|
|
}
|
|
break;
|
|
case D3DPT_TRIANGLEFAN:
|
|
{
|
|
RRCLIPCODE c0, c1, c2;
|
|
|
|
pV2 = pVtx;
|
|
pVtx += m_dwOutputVtxSize;
|
|
c2 = *pClip++;
|
|
// Preload initial pV0.
|
|
pV1 = pVtx;
|
|
pVtx += m_dwOutputVtxSize;
|
|
c1 = *pClip++;
|
|
for (i = (INT)m_dwNumVertices - 2; i > 0; i--)
|
|
{
|
|
pV0 = pV1; c0 = c1;
|
|
pV1 = pVtx;
|
|
pVtx += m_dwOutputVtxSize;
|
|
c1 = *pClip++;
|
|
((ReferenceRasterizer *)this)->DrawClippedTriangle(pV0, c0,
|
|
pV1, c1,
|
|
pV2, c2);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
DPFM(0, DRV, ("Refrast Error: Unknown or unsupported primitive type "
|
|
"requested of DrawOnePrimitive"));
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// DrawOneClippedIndexedPrimitive
|
|
//
|
|
// Draw one list of clipped indexed primitives.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
RRProcessVertices::DrawOneClippedIndexedPrimitive()
|
|
{
|
|
INT i;
|
|
PUINT8 pVtx = (PUINT8) m_pvOut;
|
|
LPWORD puIndices = m_pIndices;
|
|
PUINT8 pV0, pV1, pV2;
|
|
RRCLIPCODE *pClip = m_pClipBuf;
|
|
RRCLIPCODE c0, c1, c2;
|
|
HRESULT hr;
|
|
|
|
switch(m_primType)
|
|
{
|
|
case D3DPT_POINTLIST:
|
|
for (i = (INT)m_dwNumIndices; i > 0; i--)
|
|
{
|
|
c0 = pClip[*puIndices];
|
|
pV0 = pVtx + m_dwOutputVtxSize * (*puIndices++);
|
|
((ReferenceRasterizer *)this)->DrawClippedPoint(pV0, c0);
|
|
}
|
|
break;
|
|
|
|
case D3DPT_LINELIST:
|
|
for (i = (INT)m_dwNumIndices / 2; i > 0; i--)
|
|
{
|
|
c0 = pClip[*puIndices];
|
|
pV0 = pVtx + m_dwOutputVtxSize * (*puIndices++);
|
|
c1 = pClip[*puIndices];
|
|
pV1 = pVtx + m_dwOutputVtxSize * (*puIndices++);
|
|
((ReferenceRasterizer *)this)->DrawClippedLine(pV0, c0,
|
|
pV1, c1);
|
|
}
|
|
break;
|
|
case D3DPT_LINESTRIP:
|
|
{
|
|
// Disable last-pixel setting for shared verties and store prestate.
|
|
((ReferenceRasterizer *)this)->StoreLastPixelState(TRUE);
|
|
// Initial pV1.
|
|
c1 = pClip[*puIndices];
|
|
pV1 = pVtx + m_dwOutputVtxSize * (*puIndices++);
|
|
for (i = (INT)m_dwNumIndices - 1; i > 1; i--)
|
|
{
|
|
c0 = c1;
|
|
pV0 = pV1;
|
|
c1 = pClip[*puIndices];
|
|
pV1 = pVtx + m_dwOutputVtxSize * (*puIndices++);
|
|
((ReferenceRasterizer *)this)->DrawClippedLine(pV0, c0,
|
|
pV1, c1);
|
|
}
|
|
// Restore last-pixel setting.
|
|
((ReferenceRasterizer *)this)->StoreLastPixelState(FALSE);
|
|
|
|
// Draw last line with last-pixel setting from state.
|
|
if (i == 1)
|
|
{
|
|
c0 = pClip[*puIndices];
|
|
pV0 = pVtx + m_dwOutputVtxSize * (*puIndices);
|
|
((ReferenceRasterizer *)this)->DrawClippedLine(pV1, c1,
|
|
pV0, c0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case D3DPT_TRIANGLELIST:
|
|
for (i = (INT)m_dwNumIndices; i > 0; i -= 3)
|
|
{
|
|
c0 = pClip[*puIndices];
|
|
pV0 = pVtx + m_dwOutputVtxSize * (*puIndices++);
|
|
c1 = pClip[*puIndices];
|
|
pV1 = pVtx + m_dwOutputVtxSize * (*puIndices++);
|
|
c2 = pClip[*puIndices];
|
|
pV2 = pVtx + m_dwOutputVtxSize * (*puIndices++);
|
|
((ReferenceRasterizer *)this)->DrawClippedTriangle(pV0, c0,
|
|
pV1, c1,
|
|
pV2, c2);
|
|
}
|
|
break;
|
|
case D3DPT_TRIANGLESTRIP:
|
|
{
|
|
// Get initial vertex values.
|
|
c1 = pClip[*puIndices];
|
|
pV1 = pVtx + m_dwOutputVtxSize * (*puIndices++);
|
|
c2 = pClip[*puIndices];
|
|
pV2 = pVtx + m_dwOutputVtxSize * (*puIndices++);
|
|
|
|
for (i = (INT)m_dwNumIndices - 2; i > 1; i -= 2)
|
|
{
|
|
c0 = c1; pV0 = pV1;
|
|
c1 = c2; pV1 = pV2;
|
|
c2 = pClip[*puIndices];
|
|
pV2 = pVtx + m_dwOutputVtxSize * (*puIndices++);
|
|
((ReferenceRasterizer *)this)->DrawClippedTriangle(pV0, c0,
|
|
pV1, c1,
|
|
pV2, c2);
|
|
|
|
c0 = c1; pV0 = pV1;
|
|
c1 = c2; pV1 = pV2;
|
|
c2 = pClip[*puIndices];
|
|
pV2 = pVtx + m_dwOutputVtxSize * (*puIndices++);
|
|
((ReferenceRasterizer *)this)->DrawClippedTriangle(pV0, c0,
|
|
pV2, c2,
|
|
pV1, c1);
|
|
}
|
|
|
|
if (i > 0)
|
|
{
|
|
c0 = c1; pV0 = pV1;
|
|
c1 = c2; pV1 = pV2;
|
|
c2 = pClip[*puIndices];
|
|
pV2 = pVtx + m_dwOutputVtxSize * (*puIndices++);
|
|
((ReferenceRasterizer *)this)->DrawClippedTriangle(pV0, c0,
|
|
pV1, c1,
|
|
pV2, c2);
|
|
}
|
|
}
|
|
break;
|
|
case D3DPT_TRIANGLEFAN:
|
|
{
|
|
c2 = pClip[*puIndices];
|
|
pV2 = pVtx + m_dwOutputVtxSize * (*puIndices++);
|
|
// Preload initial pV0.
|
|
c1 = pClip[*puIndices];
|
|
pV1 = pVtx + m_dwOutputVtxSize * (*puIndices++);
|
|
for (i = (INT)m_dwNumIndices - 2; i > 0; i--)
|
|
{
|
|
c0 = c1; pV0 = pV1;
|
|
c1 = pClip[*puIndices];
|
|
pV1 = pVtx + m_dwOutputVtxSize * (*puIndices++);
|
|
((ReferenceRasterizer *)this)->DrawClippedTriangle(pV0, c0,
|
|
pV1, c1,
|
|
pV2, c2);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
DPFM(0, DRV, ("Refrast Error: Unknown or unsupported primitive type "
|
|
"requested of DrawOneClippedIndexedPrimitive"));
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void
|
|
ReferenceRasterizer::DrawClippedTriangle( void* pvV0, RRCLIPCODE c0,
|
|
void* pvV1, RRCLIPCODE c1,
|
|
void* pvV2, RRCLIPCODE c2,
|
|
WORD wFlags )
|
|
{
|
|
DWORD dwInter = (c0 & c1 & c2);
|
|
DWORD dwUnion = (c0 | c1 | c2);
|
|
DWORD dwMask = (m_dwTLState & RRPV_GUARDBAND) ? RRCLIPGB_ALL : RRCLIP_ALL;
|
|
|
|
// All vertices outside the frustum or guardband,
|
|
// return without drawing
|
|
if (dwInter)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// If all the vertices are in, draw and return
|
|
if ((dwUnion & dwMask) == 0)
|
|
{
|
|
DrawTriangle( pvV0, pvV1, pvV2, wFlags );
|
|
return;
|
|
}
|
|
|
|
// Do Clipping
|
|
RRCLIPTRIANGLE newtri;
|
|
RRCLIPVTX cv[3];
|
|
|
|
MakeClipVertexFromFVF( cv[0], pvV0, m_ViewData,
|
|
m_dwTextureCoordSizeTotal, m_qwFVFOut, c0,
|
|
dwMask);
|
|
MakeClipVertexFromFVF( cv[1], pvV1, m_ViewData,
|
|
m_dwTextureCoordSizeTotal, m_qwFVFOut, c1,
|
|
dwMask);
|
|
MakeClipVertexFromFVF( cv[2], pvV2, m_ViewData,
|
|
m_dwTextureCoordSizeTotal, m_qwFVFOut, c2,
|
|
dwMask);
|
|
|
|
newtri.v[0] = &cv[0]; cv[0].next = &cv[1];
|
|
newtri.v[1] = &cv[1]; cv[1].next = &cv[2];
|
|
newtri.v[2] = &cv[2]; cv[2].next = NULL;
|
|
|
|
int count;
|
|
RRCLIPVTX **ver;
|
|
cv[0].clip |= CLIPPED_ENABLE;
|
|
cv[1].clip |= CLIPPED_ENABLE;
|
|
cv[2].clip |= CLIPPED_ENABLE;
|
|
|
|
if (count = ClipSingleTriangle( &newtri, &ver ))
|
|
{
|
|
int i;
|
|
|
|
// Temporary Byte Array
|
|
if (m_clipping.ClipBuf.GetSize() < m_dwOutputVtxSize*count)
|
|
{
|
|
m_clipping.ClipBuf.Grow( m_dwOutputVtxSize*count );
|
|
}
|
|
LPBYTE pTLV = (LPBYTE)m_clipping.ClipBuf.GetAddress();
|
|
LPBYTE p = pTLV;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
MakeFVFVertexFromClip( p, ver[i], m_qwFVFOut,
|
|
m_dwTextureCoordSizeTotal);
|
|
p += m_dwOutputVtxSize;
|
|
}
|
|
|
|
// If it is in wireframe mode, convert the clipper output to
|
|
// a line list.
|
|
if (!m_bPointSprite && (GetRenderState()[D3DRENDERSTATE_FILLMODE] == D3DFILL_WIREFRAME))
|
|
{
|
|
DWORD dwEdgeFlags = 0;
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
if (ver[i]->clip & CLIPPED_ENABLE) dwEdgeFlags |= (1 << i);
|
|
p += m_dwOutputVtxSize;
|
|
}
|
|
|
|
DoDrawOneEdgeFlagTriangleFan( this, m_dwOutputVtxSize,
|
|
(PUINT8) pTLV, count,
|
|
dwEdgeFlags );
|
|
}
|
|
else
|
|
{
|
|
DoDrawOnePrimitive( this, m_dwOutputVtxSize, (PUINT8) pTLV,
|
|
D3DPT_TRIANGLEFAN, count);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ReferenceRasterizer::DrawClippedLine( void* pvV0, RRCLIPCODE c0,
|
|
void* pvV1, RRCLIPCODE c1,
|
|
void* pvVFlat )
|
|
{
|
|
DWORD dwInter = (c0 & c1);
|
|
DWORD dwUnion = (c0 | c1);
|
|
DWORD dwMask = (m_dwTLState & RRPV_GUARDBAND) ? RRCLIPGB_ALL : RRCLIP_ALL;
|
|
|
|
// All vertices outside the frustum or guardband,
|
|
// return without drawing
|
|
if (dwInter)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// If all the vertices are in, draw and return
|
|
if ((dwUnion & dwMask) == 0)
|
|
{
|
|
DrawLine( pvV0, pvV1, pvVFlat );
|
|
return;
|
|
}
|
|
|
|
RRCLIPTRIANGLE newline;
|
|
RRCLIPVTX cv[2];
|
|
|
|
MakeClipVertexFromFVF( cv[0], pvV0, m_ViewData,
|
|
m_dwTextureCoordSizeTotal, m_qwFVFOut, c0,
|
|
dwMask);
|
|
MakeClipVertexFromFVF( cv[1], pvV1, m_ViewData,
|
|
m_dwTextureCoordSizeTotal, m_qwFVFOut, c1,
|
|
dwMask);
|
|
|
|
newline.v[0] = &cv[0];
|
|
newline.v[1] = &cv[1];
|
|
|
|
if (ClipSingleLine( &newline ))
|
|
{
|
|
// Temporary Byte Array
|
|
if (m_clipping.ClipBuf.GetSize() < m_dwOutputVtxSize*2)
|
|
{
|
|
m_clipping.ClipBuf.Grow( m_dwOutputVtxSize*3 );
|
|
}
|
|
|
|
LPBYTE pTLV = (LPBYTE)m_clipping.ClipBuf.GetAddress();
|
|
LPBYTE p = pTLV;
|
|
MakeFVFVertexFromClip( p, newline.v[0], m_qwFVFOut,
|
|
m_dwTextureCoordSizeTotal);
|
|
p += m_dwOutputVtxSize;
|
|
MakeFVFVertexFromClip( p, newline.v[1], m_qwFVFOut,
|
|
m_dwTextureCoordSizeTotal);
|
|
|
|
DrawLine( pTLV, p, pvVFlat );
|
|
}
|
|
}
|
|
|
|
void
|
|
ReferenceRasterizer::DrawClippedPoint( void* pvV0, RRCLIPCODE c0,
|
|
void* pvVFlat )
|
|
{
|
|
// if definitely out
|
|
if (c0 & (RRCLIP_FRONT | RRCLIP_BACK | (1<<RRCLIPGB_LEFTBIT) | (1<<RRCLIPGB_RIGHTBIT) |
|
|
(1<<RRCLIPGB_TOPBIT) | (1<<RRCLIPGB_BOTTOMBIT)))
|
|
return;
|
|
|
|
// otherwise, could be in
|
|
if (c0 == 0)
|
|
{
|
|
// is completely in, just draw it
|
|
DrawPoint( pvV0, pvVFlat );
|
|
}
|
|
else
|
|
{
|
|
// use per vertex S if it exists, otherwise use D3DRENDERSTATE_POINTSIZE
|
|
BOOL bAlreadyXfmd = FVF_TRANSFORMED( m_dwFVFIn );
|
|
RRFVFExtractor Vtx0( pvV0, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
|
|
|
|
FLOAT fS = 1.0f;
|
|
#ifdef __POINTSPRITES
|
|
if (m_qwFVFControl & D3DFVF_S)
|
|
{
|
|
fS = Vtx0.GetS();
|
|
}
|
|
else if( m_dwDriverType > RRTYPE_DP2HAL )
|
|
{
|
|
fS = m_fRenderState[D3DRENDERSTATE_POINTSIZE];
|
|
}
|
|
#endif
|
|
|
|
if (fS <= 1.0f)
|
|
{
|
|
// too small and out
|
|
return;
|
|
}
|
|
|
|
#ifdef __POINTSPRITES
|
|
if (c0 & (RRCLIP_USERCLIPPLANE0 | RRCLIP_USERCLIPPLANE1 | RRCLIP_USERCLIPPLANE2 |
|
|
RRCLIP_USERCLIPPLANE3 | RRCLIP_USERCLIPPLANE4 | RRCLIP_USERCLIPPLANE5))
|
|
{
|
|
// large and potentially clipped, expand point sprite to quad and clip traditionally
|
|
fS *= 0.5f; // turn size into screen space offset to quad points from center
|
|
FLOAT w_clip = Vtx0.GetRHW(); // not really the reciprocal
|
|
FLOAT x_clip_size = fS*w_clip/m_ViewData.scaleX;
|
|
FLOAT y_clip_size = fS*w_clip/m_ViewData.scaleY;
|
|
|
|
UINT64 qwFVFControlSave = m_qwFVFControl;
|
|
UINT64 qwFVFOutSave = m_qwFVFOut;
|
|
DWORD dwOutputVtxSizeSave = m_dwOutputVtxSize;
|
|
DWORD dwTextureCoordSizeTotalSave = m_dwTextureCoordSizeTotal;
|
|
DWORD dwTexCoordSizeSave[D3DDP_MAXTEXCOORD];
|
|
memcpy(dwTexCoordSizeSave, m_dwTexCoordSize, sizeof(DWORD)*D3DDP_MAXTEXCOORD);
|
|
DWORD dwInterpolateSave = m_clipping.dwInterpolate;
|
|
DWORD dwNumTexCoordsSave = m_dwNumTexCoords;
|
|
|
|
INT32 iTexCount = 0;
|
|
if (m_dwRenderState[D3DRENDERSTATE_POINTSPRITEENABLE] && m_cActiveTextureStages)
|
|
{
|
|
// look through texture stages to see how many texture indices are needed
|
|
// since for POINTSPRITE mode, the input vertices don't even have to have any
|
|
// texture coordinates. Since this is an important advantage of using point
|
|
// sprites, we have to deal with it.
|
|
for ( INT32 iStage=0; iStage<m_cActiveTextureStages; iStage++ )
|
|
{
|
|
if (m_pTexture[iStage])
|
|
{
|
|
INT32 iCoordSet = m_pTexture[iStage]->m_pStageState[iStage].m_dwVal[D3DTSS_TEXCOORDINDEX];
|
|
iCoordSet &= 0xffff;
|
|
iTexCount = max(iCoordSet+1, iTexCount);
|
|
m_clipping.dwInterpolate |= RRCLIP_INTERPOLATE_TEXTURE;
|
|
}
|
|
}
|
|
}
|
|
m_qwFVFOut &= ~(D3DFVF_TEXCOUNT_MASK | 0xffff0000);
|
|
m_qwFVFOut |= (iTexCount << D3DFVF_TEXCOUNT_SHIFT) & D3DFVF_TEXCOUNT_MASK;
|
|
m_qwFVFControl = m_qwFVFOut;
|
|
m_dwNumTexCoords = FVF_TEXCOORD_NUMBER((DWORD)m_qwFVFOut);
|
|
m_dwOutputVtxSize = GetFVFVertexSize( m_qwFVFOut );
|
|
m_dwTextureCoordSizeTotal = 0;
|
|
ComputeTextureCoordSize((DWORD)m_qwFVFOut, m_dwTexCoordSize,
|
|
&m_dwTextureCoordSizeTotal);
|
|
|
|
void *pvVT0, *pvVT1, *pvVT2, *pvVT3;
|
|
{
|
|
pvVT0 = MEMALLOC( m_dwOutputVtxSize );
|
|
pvVT1 = MEMALLOC( m_dwOutputVtxSize );
|
|
pvVT2 = MEMALLOC( m_dwOutputVtxSize );
|
|
pvVT3 = MEMALLOC( m_dwOutputVtxSize );
|
|
|
|
_ASSERTa( ( NULL != pvVT0 ) && ( NULL != pvVT1 ) && ( NULL != pvVT2) && (NULL != pvVT2),
|
|
"malloc failure on ReferenceRasterizer::DrawClippedPoint", return; );
|
|
|
|
// only copy as much data as we have
|
|
DWORD dwStride = GetFVFVertexSize(qwFVFControlSave);
|
|
memcpy(pvVT0, pvV0, dwStride);
|
|
memcpy(pvVT1, pvV0, dwStride);
|
|
memcpy(pvVT2, pvV0, dwStride);
|
|
memcpy(pvVT3, pvV0, dwStride);
|
|
}
|
|
|
|
// encase FVF vertex pointer and control in class to extract fields
|
|
RRFVFExtractor VtxT0( pvVT0, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
|
|
RRFVFExtractor VtxT1( pvVT1, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
|
|
RRFVFExtractor VtxT2( pvVT2, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
|
|
RRFVFExtractor VtxT3( pvVT3, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
|
|
|
|
|
|
FLOAT *pXY = VtxT0.GetPtrXYZ();
|
|
pXY[0] += -x_clip_size;
|
|
pXY[1] += -y_clip_size;
|
|
|
|
pXY = VtxT1.GetPtrXYZ();
|
|
pXY[0] += x_clip_size;
|
|
pXY[1] += -y_clip_size;
|
|
|
|
pXY = VtxT2.GetPtrXYZ();
|
|
pXY[0] += -x_clip_size;
|
|
pXY[1] += y_clip_size;
|
|
|
|
pXY = VtxT3.GetPtrXYZ();
|
|
pXY[0] += x_clip_size;
|
|
pXY[1] += y_clip_size;
|
|
|
|
if (m_dwRenderState[D3DRENDERSTATE_POINTSPRITEENABLE] && m_cActiveTextureStages)
|
|
{
|
|
// compute functions for texture coordinates
|
|
if (m_cActiveTextureStages)
|
|
{
|
|
for ( INT32 iStage=0; iStage<m_cActiveTextureStages; iStage++ )
|
|
{
|
|
if (m_pTexture[iStage])
|
|
{
|
|
INT32 iCoordSet = m_pTexture[iStage]->m_pStageState[iStage].m_dwVal[D3DTSS_TEXCOORDINDEX];
|
|
iCoordSet &= 0xffff;
|
|
FLOAT *pUV = VtxT0.GetPtrTexCrd(0, iCoordSet);
|
|
pUV[0] = 0.0f;
|
|
pUV[1] = 0.0f;
|
|
pUV = VtxT1.GetPtrTexCrd(0, iCoordSet);
|
|
pUV[0] = SPRITETEXCOORDMAX;
|
|
pUV[1] = 0.0f;
|
|
pUV = VtxT2.GetPtrTexCrd(0, iCoordSet);
|
|
pUV[0] = 0.0f;
|
|
pUV[1] = SPRITETEXCOORDMAX;
|
|
pUV = VtxT3.GetPtrTexCrd(0, iCoordSet);
|
|
pUV[0] = SPRITETEXCOORDMAX;
|
|
pUV[1] = SPRITETEXCOORDMAX;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
RRCLIPCODE clipIntersection, clipUnion;
|
|
RRCLIPCODE c[4];
|
|
RRFVFExtractor* pVtxTs[4] = {&VtxT0, &VtxT1, &VtxT2, &VtxT3};
|
|
for ( INT32 i= 0; i < 4; i++)
|
|
{
|
|
FLOAT x_clip = pVtxTs[i]->GetX();
|
|
FLOAT y_clip = pVtxTs[i]->GetY();
|
|
FLOAT z_clip = pVtxTs[i]->GetZ();
|
|
FLOAT w_clip = pVtxTs[i]->GetRHW();
|
|
c[i] = ComputeClipCodes(&clipIntersection, &clipUnion, x_clip, y_clip,
|
|
z_clip, w_clip, 0.0f);
|
|
if (c[i] == 0 || ((m_dwTLState & RRPV_GUARDBAND) && ((c[i] & ~RRCLIP_INGUARDBAND) == 0)))
|
|
{
|
|
// need to compute screen coordinates
|
|
FLOAT inv_w_clip = 1.0f/w_clip;
|
|
FLOAT *pXYZW = pVtxTs[i]->GetPtrXYZ();
|
|
pXYZW[0] = x_clip * inv_w_clip * m_ViewData.scaleX +
|
|
m_ViewData.offsetX;
|
|
pXYZW[1] = y_clip * inv_w_clip * m_ViewData.scaleY +
|
|
m_ViewData.offsetY;
|
|
pXYZW[2] = z_clip * inv_w_clip * m_ViewData.scaleZ +
|
|
m_ViewData.offsetZ;
|
|
pXYZW[3] = inv_w_clip;
|
|
}
|
|
}
|
|
// set point sprite mode in rasterizer
|
|
m_bPointSprite = TRUE;
|
|
|
|
DrawClippedTriangle(pvVT0, c[0], pvVT1, c[1], pvVT2, c[2], 0);
|
|
DrawClippedTriangle(pvVT1, c[1], pvVT3, c[3], pvVT2, c[2], 0);
|
|
|
|
// clear point sprite mode in rasterizer
|
|
m_bPointSprite = FALSE;
|
|
|
|
m_qwFVFControl = qwFVFControlSave;
|
|
m_dwOutputVtxSize = dwOutputVtxSizeSave;
|
|
m_qwFVFOut = qwFVFOutSave;
|
|
m_dwTextureCoordSizeTotal = dwTextureCoordSizeTotalSave;
|
|
memcpy(m_dwTexCoordSize, dwTexCoordSizeSave, sizeof(DWORD)*D3DDP_MAXTEXCOORD);
|
|
m_clipping.dwInterpolate = dwInterpolateSave;
|
|
m_dwNumTexCoords = dwNumTexCoordsSave;
|
|
|
|
MEMFREE( pvVT0 );
|
|
MEMFREE( pvVT1 );
|
|
MEMFREE( pvVT2 );
|
|
MEMFREE( pvVT3 );
|
|
}
|
|
else
|
|
{
|
|
// Just x y clipped. Let bounding box handle it
|
|
DrawPoint( pvV0, pvVFlat );
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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
|
|
ReferenceRasterizer::ClipSingleTriangle(RRCLIPTRIANGLE *tri,
|
|
RRCLIPVTX ***clipVertexPointer)
|
|
{
|
|
int accept;
|
|
int i, j;
|
|
int count;
|
|
RRCLIPVTX **inv;
|
|
RRCLIPVTX **outv;
|
|
RRCLIPVTX *p;
|
|
ULONG_PTR swapv;
|
|
D3DCOLOR diffuse1; // Original colors
|
|
D3DCOLOR specular1;
|
|
D3DCOLOR diffuse2;
|
|
D3DCOLOR specular2;
|
|
DWORD dwClipBit;
|
|
DWORD dwClippedBit;
|
|
|
|
if (GetRenderState()[D3DRENDERSTATE_SHADEMODE] == D3DSHADE_FLAT)
|
|
{
|
|
// It is easier to set all vertices to the same color here
|
|
D3DCOLOR diffuse = tri->v[0]->color;
|
|
D3DCOLOR specular = tri->v[0]->specular;
|
|
|
|
//Save original colors
|
|
diffuse1 = tri->v[1]->color;
|
|
specular1 = tri->v[1]->specular;
|
|
diffuse2 = tri->v[2]->color;
|
|
specular2 = tri->v[2]->specular;
|
|
|
|
// copy all but fog intensity
|
|
tri->v[1]->color= diffuse;
|
|
tri->v[1]->specular &= 0xFF000000; tri->v[1]->specular |= (0x00FFFFFF & specular);
|
|
tri->v[2]->color = diffuse;
|
|
tri->v[2]->specular &= 0xFF000000; tri->v[2]->specular |= (0x00FFFFFF & specular);
|
|
}
|
|
accept = (tri->v[0]->clip | tri->v[1]->clip | tri->v[2]->clip);
|
|
|
|
inv = tri->v;
|
|
count = 3;
|
|
outv = m_clipping.clip_vbuf1;
|
|
m_clipping.clip_color = tri->v[0]->color;
|
|
m_clipping.clip_specular = tri->v[0]->specular;
|
|
|
|
/*
|
|
* XXX assumes sizeof(void*) == sizeof(unsigned long)
|
|
*/
|
|
{
|
|
ULONG_PTR tmp1;
|
|
ULONG_PTR tmp2;
|
|
|
|
tmp1 = (ULONG_PTR)m_clipping.clip_vbuf1;
|
|
tmp2 = (ULONG_PTR)m_clipping.clip_vbuf2;
|
|
|
|
swapv = tmp1 + tmp2;
|
|
}
|
|
m_clipping.clip_vertices_used = 0;
|
|
|
|
#define SWAP(inv, outv) \
|
|
inv = outv; \
|
|
outv = (RRCLIPVTX**) (swapv - (ULONG_PTR) outv)
|
|
|
|
if (accept & RRCLIP_FRONT)
|
|
{
|
|
count = ClipFront( inv, outv, count );
|
|
if (count < 3)
|
|
goto out_of_here;
|
|
SWAP(inv, outv);
|
|
}
|
|
if (m_dwTLState & RRPV_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 & RRCLIP_FRONT)
|
|
{
|
|
accept = 0;
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
RRCLIPVTX *p;
|
|
p = inv[i];
|
|
if (p->clip & CLIPPED_FRONT)
|
|
accept |= ComputeClipCodeGB(m_ViewData,
|
|
m_xfmUserClipPlanes, p);
|
|
else
|
|
accept |= p->clip;
|
|
}
|
|
}
|
|
if (accept & RRCLIP_BACK)
|
|
{
|
|
count = ClipBack( inv, outv, count );
|
|
if (count < 3)
|
|
goto out_of_here;
|
|
SWAP(inv, outv);
|
|
}
|
|
if (accept & RRCLIPGB_LEFT)
|
|
{
|
|
count = ClipLeftGB( inv, outv, count );
|
|
if (count < 3)
|
|
goto out_of_here;
|
|
SWAP(inv, outv);
|
|
}
|
|
if (accept & RRCLIPGB_RIGHT)
|
|
{
|
|
count = ClipRightGB( inv, outv, count );
|
|
if (count < 3)
|
|
goto out_of_here;
|
|
SWAP(inv, outv);
|
|
}
|
|
if (accept & RRCLIPGB_BOTTOM)
|
|
{
|
|
count = ClipBottomGB( inv, outv, count );
|
|
if (count < 3)
|
|
goto out_of_here;
|
|
SWAP(inv, outv);
|
|
}
|
|
if (accept & RRCLIPGB_TOP)
|
|
{
|
|
count = ClipTopGB( 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 & RRCLIP_FRONT)
|
|
{
|
|
accept = 0;
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
RRCLIPVTX *p;
|
|
p = inv[i];
|
|
if (p->clip & (CLIPPED_FRONT))
|
|
accept |= ComputeClipCode( m_xfmUserClipPlanes, p );
|
|
else
|
|
accept |= p->clip;
|
|
}
|
|
}
|
|
if (accept & RRCLIP_BACK)
|
|
{
|
|
count = ClipBack( inv, outv, count );
|
|
if (count < 3)
|
|
goto out_of_here;
|
|
SWAP(inv, outv);
|
|
}
|
|
if (accept & RRCLIP_LEFT)
|
|
{
|
|
count = ClipLeft( inv, outv, count );
|
|
if (count < 3)
|
|
goto out_of_here;
|
|
SWAP(inv, outv);
|
|
}
|
|
if (accept & RRCLIP_RIGHT)
|
|
{
|
|
count = ClipRight( inv, outv, count );
|
|
if (count < 3)
|
|
goto out_of_here;
|
|
SWAP(inv, outv);
|
|
}
|
|
if (accept & RRCLIP_BOTTOM)
|
|
{
|
|
count = ClipBottom( inv, outv, count );
|
|
if (count < 3)
|
|
goto out_of_here;
|
|
SWAP(inv, outv);
|
|
}
|
|
if (accept & RRCLIP_TOP)
|
|
{
|
|
count = ClipTop( inv, outv, count );
|
|
if (count < 3)
|
|
goto out_of_here;
|
|
SWAP(inv, outv);
|
|
}
|
|
}
|
|
|
|
dwClipBit = RRCLIP_USERCLIPPLANE0;
|
|
dwClippedBit = CLIPPED_USERCLIPPLANE0;
|
|
// User Clip Planes
|
|
for( j=0; j<RRMAX_USER_CLIPPLANES; j++)
|
|
{
|
|
if (accept & dwClipBit)
|
|
{
|
|
count = ClipByPlane( inv, outv, &m_xfmUserClipPlanes[j].plane,
|
|
dwClippedBit, count);
|
|
if (count < 3)
|
|
goto out_of_here;
|
|
SWAP(inv, outv);
|
|
}
|
|
dwClipBit <<= 1;
|
|
dwClippedBit <<= 1;
|
|
}
|
|
|
|
#undef SWAP
|
|
|
|
ComputeScreenCoordinates( m_ViewData, inv, count );
|
|
|
|
*clipVertexPointer = inv;
|
|
m_clipping.current_vbuf = inv;
|
|
return count;
|
|
|
|
out_of_here:
|
|
|
|
*clipVertexPointer = NULL;
|
|
return 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
int
|
|
ReferenceRasterizer::ClipSingleLine( RRCLIPTRIANGLE *line )
|
|
{
|
|
int accept;
|
|
int j;
|
|
D3DVALUE in1, in2;
|
|
DWORD dwClipBit;
|
|
DWORD dwClippedBit;
|
|
|
|
accept = (line->v[0]->clip | line->v[1]->clip);
|
|
|
|
m_clipping.clip_color = line->v[0]->color;
|
|
m_clipping.clip_specular = line->v[0]->specular;
|
|
|
|
if (accept & D3DCLIP_FRONT)
|
|
if (ClipLineFront(line))
|
|
goto out_of_here;
|
|
if (m_dwTLState & RRPV_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 & D3DCLIP_FRONT)
|
|
{
|
|
RRCLIPVTX * p;
|
|
accept = 0;
|
|
p = line->v[0];
|
|
if (p->clip & CLIPPED_FRONT)
|
|
accept |= ComputeClipCodeGB(m_ViewData, m_xfmUserClipPlanes, p);
|
|
else
|
|
accept |= p->clip;
|
|
p = line->v[1];
|
|
if (p->clip & CLIPPED_FRONT)
|
|
accept |= ComputeClipCodeGB(m_ViewData, m_xfmUserClipPlanes, p);
|
|
else
|
|
accept |= p->clip;
|
|
}
|
|
if (accept & D3DCLIP_BACK)
|
|
if (ClipLineBack( line ))
|
|
goto out_of_here;
|
|
if (accept & RRCLIPGB_LEFT)
|
|
if (ClipLineLeftGB( line ))
|
|
goto out_of_here;
|
|
if (accept & RRCLIPGB_RIGHT)
|
|
if (ClipLineRightGB( line ))
|
|
goto out_of_here;
|
|
if (accept & RRCLIPGB_TOP)
|
|
if (ClipLineTopGB( line ))
|
|
goto out_of_here;
|
|
if (accept & RRCLIPGB_BOTTOM)
|
|
if (ClipLineBottomGB( 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 & D3DCLIP_FRONT)
|
|
{
|
|
RRCLIPVTX * p;
|
|
accept = 0;
|
|
p = line->v[0];
|
|
if (p->clip & CLIPPED_FRONT)
|
|
accept |= ComputeClipCode( m_xfmUserClipPlanes, p );
|
|
else
|
|
accept |= p->clip;
|
|
p = line->v[1];
|
|
if (p->clip & CLIPPED_FRONT)
|
|
accept |= ComputeClipCode( m_xfmUserClipPlanes, p );
|
|
else
|
|
accept |= p->clip;
|
|
}
|
|
if (accept & D3DCLIP_BACK)
|
|
if (ClipLineBack( line ))
|
|
goto out_of_here;
|
|
if (accept & D3DCLIP_LEFT)
|
|
if (ClipLineLeft( line ))
|
|
goto out_of_here;
|
|
if (accept & D3DCLIP_RIGHT)
|
|
if (ClipLineRight( line ))
|
|
goto out_of_here;
|
|
if (accept & D3DCLIP_TOP)
|
|
if (ClipLineTop( line ))
|
|
goto out_of_here;
|
|
if (accept & D3DCLIP_BOTTOM)
|
|
if (ClipLineBottom( line ))
|
|
goto out_of_here;
|
|
}
|
|
|
|
// User Clip Planes
|
|
dwClipBit = RRCLIP_USERCLIPPLANE0;
|
|
dwClippedBit = CLIPPED_USERCLIPPLANE0;
|
|
for( j=0; j<RRMAX_USER_CLIPPLANES; j++)
|
|
{
|
|
if (accept & dwClipBit)
|
|
{
|
|
if( ClipLineByPlane( line, &m_xfmUserClipPlanes[j].plane,
|
|
dwClippedBit ))
|
|
goto out_of_here;
|
|
}
|
|
dwClipBit <<= 1;
|
|
dwClippedBit <<= 1;
|
|
}
|
|
|
|
ComputeScreenCoordinates(m_ViewData, line->v, 2);
|
|
|
|
return 1;
|
|
out_of_here:
|
|
return 0;
|
|
}
|