Leaked source code of windows server 2003
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

//----------------------------------------------------------------------------
//
// 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;
}