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.
693 lines
22 KiB
693 lines
22 KiB
//----------------------------------------------------------------------------
|
|
//
|
|
// lstp.cpp
|
|
//
|
|
// Line setup methods.
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1997.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
DBG_DECLARE_FILE();
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// LineSetup_Start
|
|
//
|
|
// Starts setup of line attributes.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void FASTCALL
|
|
LineSetup_Start(PSETUPCTX pStpCtx,
|
|
LPD3DTLVERTEX pV0,
|
|
LPD3DTLVERTEX pV1)
|
|
{
|
|
FLOAT fZ0;
|
|
|
|
if (pStpCtx->uFlags & PRIMSF_Z_USED)
|
|
{
|
|
FLOAT fZScale;
|
|
|
|
if (pStpCtx->pCtx->iZBitCount == 16)
|
|
{
|
|
fZScale = Z16_SCALE;
|
|
}
|
|
else
|
|
{
|
|
fZScale = Z32_SCALE;
|
|
}
|
|
|
|
pStpCtx->DAttrDMajor.fZ =
|
|
(pV1->dvSZ - pV0->dvSZ) * fZScale * pStpCtx->fOoLen;
|
|
|
|
// fZ0 may be used later so set if from the vertex Z.
|
|
fZ0 = pV0->dvSZ;
|
|
pStpCtx->Attr.fZ = fZ0 * fZScale +
|
|
pStpCtx->DAttrDMajor.fZ * pStpCtx->fDMajor;
|
|
}
|
|
|
|
if (pStpCtx->uFlags & PRIMSF_TEX_USED)
|
|
{
|
|
FLOAT fUoW1, fVoW1;
|
|
|
|
// Mipmapping doesn't have any meaning.
|
|
RSASSERT((pStpCtx->uFlags & PRIMSF_LOD_USED) == 0);
|
|
|
|
if (pStpCtx->uFlags & PRIMSF_PERSP_USED)
|
|
{
|
|
pStpCtx->DAttrDMajor.fOoW =
|
|
(pV1->dvRHW - pV0->dvRHW) * OOW_SCALE * pStpCtx->fOoLen;
|
|
pStpCtx->Attr.fOoW = pV0->dvRHW * OOW_SCALE +
|
|
pStpCtx->DAttrDMajor.fOoW * pStpCtx->fDMajor;
|
|
|
|
fUoW1 = pV0->dvTU * pV0->dvRHW;
|
|
fVoW1 = pV0->dvTV * pV0->dvRHW;
|
|
|
|
pStpCtx->DAttrDMajor.fUoW1 =
|
|
PERSP_TEXTURE_DELTA(pV1->dvTU, pV1->dvRHW, pV0->dvTU, fUoW1,
|
|
pStpCtx->pCtx->pdwWrap[0] & D3DWRAP_U) *
|
|
TEX_SCALE * pStpCtx->fOoLen;
|
|
pStpCtx->DAttrDMajor.fVoW1 =
|
|
PERSP_TEXTURE_DELTA(pV1->dvTV, pV1->dvRHW, pV0->dvTV, fVoW1,
|
|
pStpCtx->pCtx->pdwWrap[0] & D3DWRAP_V) *
|
|
TEX_SCALE * pStpCtx->fOoLen;
|
|
}
|
|
else
|
|
{
|
|
pStpCtx->DAttrDMajor.fOoW = g_fZero;
|
|
pStpCtx->Attr.fOoW = OOW_SCALE;
|
|
|
|
fUoW1 = pV0->dvTU;
|
|
fVoW1 = pV0->dvTV;
|
|
|
|
pStpCtx->DAttrDMajor.fUoW1 =
|
|
TextureDiff(pV1->dvTU, fUoW1,
|
|
pStpCtx->pCtx->pdwWrap[0] & D3DWRAP_U) *
|
|
TEX_SCALE * pStpCtx->fOoLen;
|
|
pStpCtx->DAttrDMajor.fVoW1 =
|
|
TextureDiff(pV1->dvTV, fVoW1,
|
|
pStpCtx->pCtx->pdwWrap[0] & D3DWRAP_V) *
|
|
TEX_SCALE * pStpCtx->fOoLen;
|
|
}
|
|
|
|
pStpCtx->Attr.fUoW1 = TEX_SCALE * fUoW1 +
|
|
pStpCtx->DAttrDMajor.fUoW1 * pStpCtx->fDMajor;
|
|
pStpCtx->Attr.fVoW1 = TEX_SCALE * fVoW1 +
|
|
pStpCtx->DAttrDMajor.fVoW1 * pStpCtx->fDMajor;
|
|
}
|
|
|
|
if (pStpCtx->uFlags & PRIMSF_TEX2_USED)
|
|
{
|
|
PRAST_GENERIC_VERTEX pVM0 = (PRAST_GENERIC_VERTEX)pV0;
|
|
PRAST_GENERIC_VERTEX pVM1 = (PRAST_GENERIC_VERTEX)pV1;
|
|
FLOAT fUoW2, fVoW2;
|
|
|
|
if (pStpCtx->uFlags & PRIMSF_PERSP_USED)
|
|
{
|
|
fUoW2 = pVM0->dvTU2 * pVM0->dvRHW;
|
|
fVoW2 = pVM0->dvTV2 * pVM0->dvRHW;
|
|
|
|
pStpCtx->DAttrDMajor.fUoW2 =
|
|
PERSP_TEXTURE_DELTA(pVM1->dvTU2, pVM1->dvRHW,
|
|
pVM0->dvTU2, fUoW2,
|
|
pStpCtx->pCtx->pdwWrap[1] & D3DWRAP_U) *
|
|
TEX_SCALE * pStpCtx->fOoLen;
|
|
pStpCtx->DAttrDMajor.fVoW2 =
|
|
PERSP_TEXTURE_DELTA(pVM1->dvTV2, pVM1->dvRHW,
|
|
pVM0->dvTV2, fVoW2,
|
|
pStpCtx->pCtx->pdwWrap[1] & D3DWRAP_V) *
|
|
TEX_SCALE * pStpCtx->fOoLen;
|
|
}
|
|
else
|
|
{
|
|
fUoW2 = pVM0->dvTU2;
|
|
fVoW2 = pVM0->dvTV2;
|
|
|
|
pStpCtx->DAttrDMajor.fUoW2 =
|
|
TextureDiff(pVM1->dvTU2, fUoW2,
|
|
pStpCtx->pCtx->pdwWrap[1] & D3DWRAP_U) *
|
|
TEX_SCALE * pStpCtx->fOoLen;
|
|
pStpCtx->DAttrDMajor.fVoW2 =
|
|
TextureDiff(pVM1->dvTV2, fVoW2,
|
|
pStpCtx->pCtx->pdwWrap[1] & D3DWRAP_V) *
|
|
TEX_SCALE * pStpCtx->fOoLen;
|
|
}
|
|
|
|
pStpCtx->Attr.fUoW2 = fUoW2 +
|
|
pStpCtx->DAttrDMajor.fUoW2 * pStpCtx->fDMajor;
|
|
pStpCtx->Attr.fVoW2 = fVoW2 +
|
|
pStpCtx->DAttrDMajor.fVoW2 * pStpCtx->fDMajor;
|
|
}
|
|
|
|
if (pStpCtx->uFlags & PRIMSF_FLAT_SHADED)
|
|
{
|
|
if (pStpCtx->uFlags & PRIMSF_DIFF_USED)
|
|
{
|
|
UINT uB, uG, uR, uA;
|
|
|
|
SPLIT_COLOR(pStpCtx->pFlatVtx->dcColor, uB, uG, uR, uA);
|
|
|
|
pStpCtx->DAttrDMajor.fB = g_fZero;
|
|
pStpCtx->DAttrDMajor.fG = g_fZero;
|
|
pStpCtx->DAttrDMajor.fR = g_fZero;
|
|
pStpCtx->DAttrDMajor.fA = g_fZero;
|
|
|
|
pStpCtx->Attr.fB = (FLOAT)(uB << COLOR_SHIFT);
|
|
pStpCtx->Attr.fG = (FLOAT)(uG << COLOR_SHIFT);
|
|
pStpCtx->Attr.fR = (FLOAT)(uR << COLOR_SHIFT);
|
|
pStpCtx->Attr.fA = (FLOAT)(uA << COLOR_SHIFT);
|
|
}
|
|
else if (pStpCtx->uFlags & PRIMSF_DIDX_USED)
|
|
{
|
|
pStpCtx->DAttrDMajor.fDIdx = g_fZero;
|
|
pStpCtx->DAttrDMajor.fDIdxA = g_fZero;
|
|
|
|
pStpCtx->Attr.fDIdx =
|
|
(FLOAT)(CI_MASKALPHA(pStpCtx->pFlatVtx->dcColor) <<
|
|
INDEX_COLOR_FIXED_SHIFT);
|
|
pStpCtx->Attr.fDIdxA =
|
|
(FLOAT)(CI_GETALPHA(pStpCtx->pFlatVtx->dcColor) <<
|
|
INDEX_COLOR_SHIFT);
|
|
}
|
|
|
|
if (pStpCtx->uFlags & PRIMSF_SPEC_USED)
|
|
{
|
|
UINT uB, uG, uR, uA;
|
|
|
|
SPLIT_COLOR(pStpCtx->pFlatVtx->dcSpecular, uB, uG, uR, uA);
|
|
|
|
pStpCtx->DAttrDMajor.fBS = g_fZero;
|
|
pStpCtx->DAttrDMajor.fGS = g_fZero;
|
|
pStpCtx->DAttrDMajor.fRS = g_fZero;
|
|
|
|
pStpCtx->Attr.fBS = (FLOAT)(uB << COLOR_SHIFT);
|
|
pStpCtx->Attr.fGS = (FLOAT)(uG << COLOR_SHIFT);
|
|
pStpCtx->Attr.fRS = (FLOAT)(uR << COLOR_SHIFT);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pStpCtx->uFlags & PRIMSF_DIFF_USED)
|
|
{
|
|
UINT uB, uG, uR, uA;
|
|
FLOAT fDB, fDG, fDR, fDA;
|
|
|
|
SPLIT_COLOR(pV0->dcColor, uB, uG, uR, uA);
|
|
COLOR_DELTA(pV1->dcColor, uB, uG, uR, uA, fDB, fDG, fDR, fDA);
|
|
|
|
pStpCtx->DAttrDMajor.fB = fDB * pStpCtx->fOoLen;
|
|
pStpCtx->DAttrDMajor.fG = fDG * pStpCtx->fOoLen;
|
|
pStpCtx->DAttrDMajor.fR = fDR * pStpCtx->fOoLen;
|
|
pStpCtx->DAttrDMajor.fA = fDA * pStpCtx->fOoLen;
|
|
|
|
pStpCtx->Attr.fB = (FLOAT)(uB << COLOR_SHIFT) +
|
|
pStpCtx->DAttrDMajor.fB * pStpCtx->fDMajor;
|
|
pStpCtx->Attr.fG = (FLOAT)(uG << COLOR_SHIFT) +
|
|
pStpCtx->DAttrDMajor.fG * pStpCtx->fDMajor;
|
|
pStpCtx->Attr.fR = (FLOAT)(uR << COLOR_SHIFT) +
|
|
pStpCtx->DAttrDMajor.fR * pStpCtx->fDMajor;
|
|
pStpCtx->Attr.fA = (FLOAT)(uA << COLOR_SHIFT) +
|
|
pStpCtx->DAttrDMajor.fA * pStpCtx->fDMajor;
|
|
}
|
|
else if (pStpCtx->uFlags & PRIMSF_DIDX_USED)
|
|
{
|
|
INT32 iIdx, iA;
|
|
FLOAT fDIdx, fDA;
|
|
|
|
SPLIT_IDX_COLOR(pV0->dcColor, iIdx, iA);
|
|
IDX_COLOR_DELTA(pV1->dcColor, iIdx, iA, fDIdx, fDA);
|
|
|
|
pStpCtx->DAttrDMajor.fDIdx = fDIdx * pStpCtx->fOoLen;
|
|
pStpCtx->DAttrDMajor.fDIdxA = fDA * pStpCtx->fOoLen;
|
|
|
|
pStpCtx->Attr.fDIdx = (FLOAT)(iIdx << INDEX_COLOR_FIXED_SHIFT) +
|
|
pStpCtx->DAttrDMajor.fDIdx * pStpCtx->fDMajor;
|
|
pStpCtx->Attr.fDIdxA = (FLOAT)(iA << INDEX_COLOR_SHIFT) +
|
|
pStpCtx->DAttrDMajor.fDIdxA * pStpCtx->fDMajor;
|
|
}
|
|
|
|
if (pStpCtx->uFlags & PRIMSF_SPEC_USED)
|
|
{
|
|
UINT uB, uG, uR, uA;
|
|
FLOAT fDB, fDG, fDR, fDA;
|
|
|
|
SPLIT_COLOR(pV0->dcSpecular, uB, uG, uR, uA);
|
|
COLOR_DELTA(pV1->dcSpecular, uB, uG, uR, uA, fDB, fDG, fDR, fDA);
|
|
|
|
pStpCtx->DAttrDMajor.fBS = fDB * pStpCtx->fOoLen;
|
|
pStpCtx->DAttrDMajor.fGS = fDG * pStpCtx->fOoLen;
|
|
pStpCtx->DAttrDMajor.fRS = fDR * pStpCtx->fOoLen;
|
|
|
|
pStpCtx->Attr.fBS = (FLOAT)(uB << COLOR_SHIFT) +
|
|
pStpCtx->DAttrDMajor.fBS * pStpCtx->fDMajor;
|
|
pStpCtx->Attr.fGS = (FLOAT)(uG << COLOR_SHIFT) +
|
|
pStpCtx->DAttrDMajor.fGS * pStpCtx->fDMajor;
|
|
pStpCtx->Attr.fRS = (FLOAT)(uR << COLOR_SHIFT) +
|
|
pStpCtx->DAttrDMajor.fRS * pStpCtx->fDMajor;
|
|
}
|
|
}
|
|
|
|
if (pStpCtx->uFlags & PRIMSF_LOCAL_FOG_USED)
|
|
{
|
|
UINT uFog0, uFog1;
|
|
|
|
#ifndef PWL_FOG
|
|
// Check for global-into-local fog. If global fog is on,
|
|
// compute the local fog values from table fog rather than
|
|
// from the vertex.
|
|
if (pStpCtx->uFlags & PRIMSF_GLOBAL_FOG_USED)
|
|
{
|
|
// Make sure Z information is valid.
|
|
RSASSERT(pStpCtx->uFlags & PRIMSF_Z_USED);
|
|
|
|
uFog0 = ComputeTableFog(pStpCtx->pCtx->pdwRenderState, fZ0);
|
|
uFog1 = ComputeTableFog(pStpCtx->pCtx->pdwRenderState,
|
|
pV1->dvSZ);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
uFog0 = (UINT)RGBA_GETALPHA(pV0->dcSpecular) << FOG_SHIFT;
|
|
uFog1 = (UINT)RGBA_GETALPHA(pV1->dcSpecular) << FOG_SHIFT;
|
|
}
|
|
|
|
pStpCtx->DAttrDMajor.fFog =
|
|
(FLOAT)((INT)uFog1 - (INT)uFog0) * pStpCtx->fOoLen;
|
|
pStpCtx->Attr.fFog = (FLOAT)uFog0 +
|
|
pStpCtx->DAttrDMajor.fFog * pStpCtx->fDMajor;
|
|
}
|
|
}
|
|
|
|
// Determine whether any of the given values are less than zero or greater
|
|
// than one. Negative zero counts as less than zero so this check will
|
|
// produce some false positives but that's OK.
|
|
#define NEEDS_NORMALIZE2(fV0, fV1) \
|
|
((ASUINT32(fV0) | ASUINT32(fV1)) > INT32_FLOAT_ONE)
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PrimProcessor::NormalizeLineRHW
|
|
//
|
|
// D3DTLVERTEX.dvRHW can be anything, but our internal structures only
|
|
// allow for it being in the range [0, 1]. This function ensures that
|
|
// the RHWs are in the proper range by finding the largest one and
|
|
// scaling all of them down by it.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void
|
|
PrimProcessor::NormalizeLineRHW(LPD3DTLVERTEX pV0, LPD3DTLVERTEX pV1)
|
|
{
|
|
// Save original values.
|
|
m_dvV0RHW = pV0->dvRHW;
|
|
m_dvV1RHW = pV1->dvRHW;
|
|
|
|
// Produce a warning when a value is out of the desired range.
|
|
#if DBG
|
|
if (FLOAT_LTZ(pV0->dvRHW) || FLOAT_LTZ(pV1->dvRHW))
|
|
{
|
|
RSDPF(("Line RHW out of range %f,%f\n",
|
|
pV0->dvRHW, pV1->dvRHW));
|
|
}
|
|
#endif
|
|
|
|
// Find bounds and compute scale.
|
|
FLOAT fMax;
|
|
|
|
if (pV0->dvRHW < pV1->dvRHW)
|
|
{
|
|
fMax = pV1->dvRHW;
|
|
}
|
|
else
|
|
{
|
|
fMax = pV0->dvRHW;
|
|
}
|
|
|
|
FLOAT fRHWScale = NORMALIZED_RHW_MAX / fMax;
|
|
|
|
// Scale all values by scaling factor.
|
|
pV0->dvRHW = pV0->dvRHW * fRHWScale;
|
|
pV1->dvRHW = pV1->dvRHW * fRHWScale;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// PrimProcessor::PointDiamondCheck
|
|
//
|
|
// Tests if vertex is within diamond of nearest candidate
|
|
// position. The +.5 (lower-right) tests are used because this is
|
|
// pixel-relative test - this corresponds to an upper-left test for
|
|
// a vertex-relative position.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
PrimProcessor::PointDiamondCheck(INT32 iXFrac, INT32 iYFrac,
|
|
BOOL bSlopeIsOne, BOOL bSlopeIsPosOne)
|
|
{
|
|
const INT32 iPosHalf = 0x8;
|
|
const INT32 iNegHalf = -0x8;
|
|
|
|
INT32 iFracAbsSum = labs( iXFrac ) + labs( iYFrac );
|
|
|
|
// return TRUE if point is in fully-exclusive diamond
|
|
if ( iFracAbsSum < iPosHalf )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// else return TRUE if diamond is on left or top extreme of point
|
|
if ( ( iXFrac == ( bSlopeIsPosOne ? iNegHalf : iPosHalf ) ) &&
|
|
( iYFrac == 0 ) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if ( ( iYFrac == iPosHalf ) &&
|
|
( iXFrac == 0 ) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// return true if slope is one, vertex is on edge,
|
|
// and (other conditions...)
|
|
if ( bSlopeIsOne && ( iFracAbsSum == iPosHalf ) )
|
|
{
|
|
if ( bSlopeIsPosOne && ( iXFrac < 0 ) && ( iYFrac > 0 ) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if ( !bSlopeIsPosOne && ( iXFrac > 0 ) && ( iYFrac > 0 ) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PrimProcessor::LineSetup
|
|
//
|
|
// Does attribute setup computations.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
// Line computations are done in n.4 fixed-point to reduce vertex jitter,
|
|
// move more computation to integer and to more easily match the GDI
|
|
// line computations.
|
|
#define LINE_FIX 4
|
|
#define LINE_SNAP FLOAT_TWOPOW4
|
|
#define OO_LINE_SNAP (1.0f / FLOAT_TWOPOW4)
|
|
#define LINE_FIX_HALF (1 << (LINE_FIX - 1))
|
|
#define LINE_FIX_NEAR_HALF (LINE_FIX_HALF - 1)
|
|
|
|
BOOL
|
|
PrimProcessor::LineSetup(LPD3DTLVERTEX pV0,
|
|
LPD3DTLVERTEX pV1)
|
|
{
|
|
// compute fixed point vertex values, with cheap
|
|
// rounding for better accuracy
|
|
INT32 iX0 = FTOI(pV0->dvSX * LINE_SNAP + .5F);
|
|
INT32 iX1 = FTOI(pV1->dvSX * LINE_SNAP + .5F);
|
|
INT32 iY0 = FTOI(pV0->dvSY * LINE_SNAP + .5F);
|
|
INT32 iY1 = FTOI(pV1->dvSY * LINE_SNAP + .5F);
|
|
|
|
// compute x,y extents of the line (fixed point)
|
|
INT32 iXSize = iX1 - iX0;
|
|
INT32 iYSize = iY1 - iY0;
|
|
|
|
// ignore zero length lines
|
|
if ( iXSize == 0 && iYSize == 0 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
INT32 iAbsXSize;
|
|
INT32 iAbsYSize;
|
|
|
|
if ( iXSize < 0 )
|
|
{
|
|
m_StpCtx.iDXCY = -1;
|
|
iAbsXSize = -iXSize;
|
|
}
|
|
else
|
|
{
|
|
m_StpCtx.iDXCY = 1;
|
|
iAbsXSize = iXSize;
|
|
}
|
|
|
|
if ( iYSize < 0 )
|
|
{
|
|
m_StpCtx.iDYCY = -1;
|
|
iAbsYSize = -iYSize;
|
|
}
|
|
else
|
|
{
|
|
m_StpCtx.iDYCY = 1;
|
|
iAbsYSize = iYSize;
|
|
}
|
|
|
|
BOOL bSlopeIsOne = iAbsXSize == iAbsYSize;
|
|
BOOL bSlopeIsPosOne =
|
|
bSlopeIsOne && ((iXSize ^ iYSize) & 0x80000000) == 0;
|
|
|
|
// compute closest pixel for vertices
|
|
//
|
|
// n n
|
|
// O-------* *-------O
|
|
// n-.5 n+.5 n-.5 n+.5
|
|
//
|
|
// Nearest Ceiling Nearest Floor
|
|
//
|
|
// always nearest ceiling for Y; use nearest floor for X for
|
|
// exception (slope == +1) case else use nearest ceiling
|
|
//
|
|
INT32 iXAdjust;
|
|
if (bSlopeIsPosOne)
|
|
{
|
|
iXAdjust = LINE_FIX_HALF;
|
|
}
|
|
else
|
|
{
|
|
iXAdjust = LINE_FIX_NEAR_HALF;
|
|
}
|
|
INT32 iPixX0 = ( iX0 + iXAdjust ) >> LINE_FIX;
|
|
INT32 iPixX1 = ( iX1 + iXAdjust ) >> LINE_FIX;
|
|
INT32 iPixY0 = ( iY0 + LINE_FIX_NEAR_HALF ) >> LINE_FIX;
|
|
INT32 iPixY1 = ( iY1 + LINE_FIX_NEAR_HALF ) >> LINE_FIX;
|
|
|
|
// determine major axis and compute step values
|
|
|
|
// sign of extent from V0 to V1 in major direction
|
|
BOOL bLineMajorNeg;
|
|
|
|
INT32 iLineMajor0;
|
|
INT32 iLineMajor1;
|
|
INT32 iLinePix0;
|
|
INT32 iLinePix1;
|
|
INT32 iLinePixStep;
|
|
|
|
// use GreaterEqual compare here so X major will be used when slope is
|
|
// exactly one - this forces the per-pixel evaluation to be done on the
|
|
// Y axis and thus adheres to the rule of inclusive right (instead of
|
|
// inclusive left) for slope == 1 cases
|
|
if ( iAbsXSize >= iAbsYSize )
|
|
{
|
|
// here for X major
|
|
m_StpCtx.uFlags |= LNF_X_MAJOR;
|
|
iLineMajor0 = iX0;
|
|
iLineMajor1 = iX1;
|
|
iLinePix0 = iPixX0;
|
|
iLinePix1 = iPixX1;
|
|
iLinePixStep = m_StpCtx.iDXCY;
|
|
bLineMajorNeg = iXSize & 0x80000000;
|
|
m_StpCtx.iDXNC = m_StpCtx.iDXCY;
|
|
m_StpCtx.iDYNC = 0;
|
|
}
|
|
else
|
|
{
|
|
// here for Y major
|
|
iLineMajor0 = iY0;
|
|
iLineMajor1 = iY1;
|
|
iLinePix0 = iPixY0;
|
|
iLinePix1 = iPixY1;
|
|
iLinePixStep = m_StpCtx.iDYCY;
|
|
bLineMajorNeg = iYSize & 0x80000000;
|
|
m_StpCtx.iDXNC = 0;
|
|
m_StpCtx.iDYNC = m_StpCtx.iDYCY;
|
|
}
|
|
|
|
// The multiplies here could be traded for sign tests but there'd
|
|
// be four cases. On a PII the multiplies will be faster than
|
|
// the branches.
|
|
m_StpCtx.DAttrCY.ipSurface =
|
|
m_StpCtx.iDYCY * m_StpCtx.pCtx->iSurfaceStride +
|
|
m_StpCtx.iDXCY * m_StpCtx.pCtx->iSurfaceStep;
|
|
m_StpCtx.DAttrNC.ipSurface =
|
|
m_StpCtx.iDYNC * m_StpCtx.pCtx->iSurfaceStride +
|
|
m_StpCtx.iDXNC * m_StpCtx.pCtx->iSurfaceStep;
|
|
if (m_StpCtx.uFlags & PRIMSF_Z_USED)
|
|
{
|
|
m_StpCtx.DAttrCY.ipZ =
|
|
m_StpCtx.iDYCY * m_StpCtx.pCtx->iZStride +
|
|
m_StpCtx.iDXCY * m_StpCtx.pCtx->iZStep;
|
|
m_StpCtx.DAttrNC.ipZ =
|
|
m_StpCtx.iDYNC * m_StpCtx.pCtx->iZStride +
|
|
m_StpCtx.iDXNC * m_StpCtx.pCtx->iZStep;
|
|
}
|
|
|
|
// check for vertices in/out of diamond
|
|
BOOL bV0InDiamond = PointDiamondCheck( iX0 - (iPixX0 << LINE_FIX),
|
|
iY0 - (iPixY0 << LINE_FIX),
|
|
bSlopeIsOne, bSlopeIsPosOne );
|
|
BOOL bV1InDiamond = PointDiamondCheck( iX1 - (iPixX1 << LINE_FIX),
|
|
iY1 - (iPixY1 << LINE_FIX),
|
|
bSlopeIsOne, bSlopeIsPosOne );
|
|
|
|
#define LINEDIR_CMP( _A, _B ) \
|
|
( bLineMajorNeg ? ( (_A) > (_B) ) : ( (_A) < (_B) ) )
|
|
|
|
// do first pixel handling - not in or behind diamond
|
|
if ( !( bV0InDiamond ||
|
|
LINEDIR_CMP( iLineMajor0, iLinePix0 << LINE_FIX ) ) )
|
|
{
|
|
iLinePix0 += iLinePixStep;
|
|
}
|
|
|
|
// do last-pixel handling - don't pull in extent if past diamond
|
|
// (in which case the pixel is always filled) or if in diamond
|
|
// and rendering last pixel
|
|
if ( !( ( !bV1InDiamond &&
|
|
LINEDIR_CMP( iLinePix1 << LINE_FIX, iLineMajor1 ) ||
|
|
( bV1InDiamond &&
|
|
m_StpCtx.pCtx->pdwRenderState[D3DRENDERSTATE_LASTPIXEL] ) ) ) )
|
|
{
|
|
iLinePix1 -= iLinePixStep;
|
|
}
|
|
|
|
// compute extent along major axis
|
|
m_StpCtx.cLinePix =
|
|
bLineMajorNeg ? iLinePix0 - iLinePix1 + 1 : iLinePix1 - iLinePix0 + 1;
|
|
|
|
// return if no major extent
|
|
if ( m_StpCtx.cLinePix <= 0 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
FLOAT fSlope;
|
|
FLOAT fMinor0;
|
|
|
|
// compute final axis-specific line values
|
|
if ( iAbsXSize >= iAbsYSize )
|
|
{
|
|
m_StpCtx.iX = iLinePix0;
|
|
|
|
if (bLineMajorNeg)
|
|
{
|
|
m_StpCtx.fDMajor =
|
|
(iX0 - (m_StpCtx.iX << LINE_FIX)) * OO_LINE_SNAP;
|
|
m_StpCtx.fOoLen = LINE_SNAP / (FLOAT)(iX0 - iX1);
|
|
}
|
|
else
|
|
{
|
|
m_StpCtx.fDMajor =
|
|
((m_StpCtx.iX << LINE_FIX) - iX0) * OO_LINE_SNAP;
|
|
m_StpCtx.fOoLen = LINE_SNAP / (FLOAT)(iX1 - iX0);
|
|
}
|
|
|
|
fSlope = m_StpCtx.fOoLen * (iY1 - iY0) * OO_LINE_SNAP;
|
|
|
|
fMinor0 = (iY0 + LINE_FIX_NEAR_HALF) * OO_LINE_SNAP +
|
|
m_StpCtx.fDMajor * fSlope;
|
|
m_StpCtx.iY = IFLOORF(fMinor0);
|
|
m_StpCtx.iLineFrac = SCALED_FRACTION(fMinor0 - m_StpCtx.iY);
|
|
m_StpCtx.iDLineFrac = SCALED_FRACTION(fSlope);
|
|
}
|
|
else
|
|
{
|
|
m_StpCtx.iY = iLinePix0;
|
|
|
|
if (bLineMajorNeg)
|
|
{
|
|
m_StpCtx.fDMajor =
|
|
(iY0 - (m_StpCtx.iY << LINE_FIX)) * OO_LINE_SNAP;
|
|
m_StpCtx.fOoLen = LINE_SNAP / (FLOAT)(iY0 - iY1);
|
|
}
|
|
else
|
|
{
|
|
m_StpCtx.fDMajor =
|
|
((m_StpCtx.iY << LINE_FIX) - iY0) * OO_LINE_SNAP;
|
|
m_StpCtx.fOoLen = LINE_SNAP / (FLOAT)(iY1 - iY0);
|
|
}
|
|
|
|
fSlope = m_StpCtx.fOoLen * (iX1 - iX0) * OO_LINE_SNAP;
|
|
|
|
fMinor0 = (iX0 + iXAdjust) * OO_LINE_SNAP + m_StpCtx.fDMajor * fSlope;
|
|
m_StpCtx.iX = IFLOORF(fMinor0);
|
|
m_StpCtx.iLineFrac = SCALED_FRACTION(fMinor0 - m_StpCtx.iX);
|
|
m_StpCtx.iDLineFrac = SCALED_FRACTION(fSlope);
|
|
}
|
|
|
|
#ifdef LINE_CORRECTION_BIAS
|
|
// A fudge factor of one-half is thrown into the correction
|
|
// to avoid undershoot due to negative corrections.
|
|
// This shifts all the attributes along the line,
|
|
// introducing error, but it's better than clamping
|
|
// them. This is not done to the coordinates to avoid
|
|
// perturbing them.
|
|
m_StpCtx.fDMajor += g_fHalf;
|
|
#else
|
|
// The correction factor is clamped to positive numbers to
|
|
// avoid undershooting with attribute values. This won't
|
|
// cause overshooting issues because it moves attributes by
|
|
// at most one-half.
|
|
if (FLOAT_LTZ(m_StpCtx.fDMajor))
|
|
{
|
|
m_StpCtx.fDMajor = 0;
|
|
}
|
|
#endif
|
|
|
|
RSDPFM((RSM_LINES, "Line %.2f,%.2f - %.2f,%.2f\n",
|
|
pV0->dvSX, pV0->dvSY, pV1->dvSX, pV1->dvSY));
|
|
RSDPFM((RSM_LINES, " %c major, %d,%d, %d pix\n",
|
|
(m_StpCtx.uFlags & LNF_X_MAJOR) ? 'X' : 'Y',
|
|
m_StpCtx.iX, m_StpCtx.iY, m_StpCtx.cLinePix));
|
|
RSDPFM((RSM_LINES, " slope %f, dmajor %f, minor0 %f\n",
|
|
fSlope, m_StpCtx.fDMajor, fMinor0));
|
|
RSDPFM((RSM_LINES, " frac %d, dfrac %d\n",
|
|
m_StpCtx.iLineFrac, m_StpCtx.iDLineFrac));
|
|
|
|
BOOL bNorm;
|
|
|
|
// USED checks cannot be combined since TEX_USED is a multibit check.
|
|
if ((m_StpCtx.uFlags & PRIMSF_TEX_USED) &&
|
|
(m_StpCtx.uFlags & PRIMSF_PERSP_USED) &&
|
|
(m_uPpFlags & PPF_NORMALIZE_RHW) &&
|
|
NEEDS_NORMALIZE2(pV0->dvRHW, pV1->dvRHW))
|
|
{
|
|
NormalizeLineRHW(pV0, pV1);
|
|
bNorm = TRUE;
|
|
}
|
|
else
|
|
{
|
|
bNorm = FALSE;
|
|
}
|
|
|
|
LineSetup_Start(&m_StpCtx, pV0, pV1);
|
|
|
|
if (bNorm)
|
|
{
|
|
pV0->dvRHW = m_dvV0RHW;
|
|
pV1->dvRHW = m_dvV1RHW;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|