//---------------------------------------------------------------------------- // // lstp.cpp // // Line setup methods. // // Copyright (C) Microsoft Corporation, 1997. // //---------------------------------------------------------------------------- #include "rgb_pch.h" #pragma hdrstop #include "d3dutil.h" #include "setup.hpp" #include "attrs_mh.h" #include "tstp_mh.h" #include "walk_mh.h" #include "rsdbg.hpp" 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 fUoW, fVoW; 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; fUoW = pV0->dvTU * pV0->dvRHW; fVoW = pV0->dvTV * pV0->dvRHW; pStpCtx->DAttrDMajor.fUoW[0] = PERSP_TEXTURE_DELTA(pV1->dvTU, pV1->dvRHW, pV0->dvTU, fUoW, pStpCtx->pCtx->pdwRenderState[D3DRS_WRAP0] & D3DWRAP_U) * TEX_SCALE * pStpCtx->fOoLen; pStpCtx->DAttrDMajor.fVoW[0] = PERSP_TEXTURE_DELTA(pV1->dvTV, pV1->dvRHW, pV0->dvTV, fVoW, pStpCtx->pCtx->pdwRenderState[D3DRS_WRAP0] & D3DWRAP_V) * TEX_SCALE * pStpCtx->fOoLen; } else { pStpCtx->DAttrDMajor.fOoW = g_fZero; pStpCtx->Attr.fOoW = OOW_SCALE; fUoW = pV0->dvTU; fVoW = pV0->dvTV; pStpCtx->DAttrDMajor.fUoW[0] = TextureDiff(pV1->dvTU, fUoW, pStpCtx->pCtx->pdwRenderState[D3DRS_WRAP0] & D3DWRAP_U) * TEX_SCALE * pStpCtx->fOoLen; pStpCtx->DAttrDMajor.fVoW[0] = TextureDiff(pV1->dvTV, fVoW, pStpCtx->pCtx->pdwRenderState[D3DRS_WRAP0] & D3DWRAP_V) * TEX_SCALE * pStpCtx->fOoLen; } pStpCtx->Attr.fUoW[0] = TEX_SCALE * fUoW + pStpCtx->DAttrDMajor.fUoW[0] * pStpCtx->fDMajor; pStpCtx->Attr.fVoW[0] = TEX_SCALE * fVoW + pStpCtx->DAttrDMajor.fVoW[0] * 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 fUoW, fVoW; for (INT32 i = 1; i < (INT32)pStpCtx->pCtx->cActTex; i++) { if (pStpCtx->uFlags & PRIMSF_PERSP_USED) { fUoW = pVM0->texCoord[i].dvTU * pVM0->dvRHW; fVoW = pVM0->texCoord[i].dvTV * pVM0->dvRHW; pStpCtx->DAttrDMajor.fUoW[i] = PERSP_TEXTURE_DELTA(pVM1->texCoord[i].dvTU, pVM1->dvRHW, pVM0->texCoord[i].dvTU, fUoW, pStpCtx->pCtx->pdwRenderState[D3DRS_WRAP0+i] & D3DWRAP_U) * TEX_SCALE * pStpCtx->fOoLen; pStpCtx->DAttrDMajor.fVoW[i] = PERSP_TEXTURE_DELTA(pVM1->texCoord[i].dvTV, pVM1->dvRHW, pVM0->texCoord[i].dvTV, fVoW, pStpCtx->pCtx->pdwRenderState[D3DRS_WRAP0+i] & D3DWRAP_V) * TEX_SCALE * pStpCtx->fOoLen; } else { fUoW = pVM0->texCoord[i].dvTU; fVoW = pVM0->texCoord[i].dvTV; pStpCtx->DAttrDMajor.fUoW[i] = TextureDiff(pVM1->texCoord[i].dvTU, fUoW, pStpCtx->pCtx->pdwRenderState[D3DRS_WRAP0+i] & D3DWRAP_U) * TEX_SCALE * pStpCtx->fOoLen; pStpCtx->DAttrDMajor.fVoW[i] = TextureDiff(pVM1->texCoord[i].dvTV, fVoW, pStpCtx->pCtx->pdwRenderState[D3DRS_WRAP0+i] & D3DWRAP_V) * TEX_SCALE * pStpCtx->fOoLen; } pStpCtx->Attr.fUoW[i] = TEX_SCALE * fUoW + pStpCtx->DAttrDMajor.fUoW[i] * pStpCtx->fDMajor; pStpCtx->Attr.fVoW[i] = TEX_SCALE * fVoW + pStpCtx->DAttrDMajor.fVoW[i] * 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[D3DRS_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; }