604 lines
19 KiB
C++
604 lines
19 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) Microsoft Corporation, 2000.
|
|
//
|
|
// rastprim.cpp
|
|
//
|
|
// Direct3D Reference Device - Rasterizer Primitive Routines
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
RefRast::~RefRast()
|
|
{
|
|
delete m_pLegacyPixelShader;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void RefRast::Init( RefDev* pRD )
|
|
{
|
|
m_pRD = pRD;
|
|
m_bIsLine = FALSE;
|
|
m_iFlatVtx = 0;
|
|
|
|
// initialize attributes xD Persp Clamp
|
|
m_Attr[RDATTR_DEPTH ].Init( this, 1, FALSE, TRUE );
|
|
m_Attr[RDATTR_FOG ].Init( this, 1, TRUE, TRUE );
|
|
m_Attr[RDATTR_COLOR ].Init( this, 4, TRUE, TRUE );
|
|
m_Attr[RDATTR_SPECULAR].Init( this, 4, TRUE, TRUE );
|
|
m_Attr[RDATTR_TEXTURE0].Init( this, 4, TRUE, FALSE );
|
|
m_Attr[RDATTR_TEXTURE1].Init( this, 4, TRUE, FALSE );
|
|
m_Attr[RDATTR_TEXTURE2].Init( this, 4, TRUE, FALSE );
|
|
m_Attr[RDATTR_TEXTURE3].Init( this, 4, TRUE, FALSE );
|
|
m_Attr[RDATTR_TEXTURE4].Init( this, 4, TRUE, FALSE );
|
|
m_Attr[RDATTR_TEXTURE5].Init( this, 4, TRUE, FALSE );
|
|
m_Attr[RDATTR_TEXTURE6].Init( this, 4, TRUE, FALSE );
|
|
m_Attr[RDATTR_TEXTURE7].Init( this, 4, TRUE, FALSE );
|
|
|
|
m_iPix = 0;
|
|
memset( m_bPixelIn, 0, sizeof(m_bPixelIn) );
|
|
memset( m_bSampleCovered, 0, sizeof(m_bSampleCovered) );
|
|
m_bLegacyPixelShade = TRUE;
|
|
m_pCurrentPixelShader = NULL;
|
|
m_CurrentPSInst = 0;
|
|
#if DBG
|
|
{
|
|
DWORD v = 0;
|
|
if( GetD3DRefRegValue(REG_DWORD, "VerboseCreatePixelShader", &v, sizeof(DWORD)) && v != 0 )
|
|
m_bDebugPrintTranslatedPixelShaderTokens = TRUE;
|
|
else
|
|
m_bDebugPrintTranslatedPixelShaderTokens = FALSE;
|
|
}
|
|
#endif
|
|
|
|
// default value registers
|
|
UINT i, j;
|
|
for( i = 0 ; i < 4; i++ )
|
|
{
|
|
for( j = 0; j < 4; j++ )
|
|
{
|
|
m_ZeroReg[i][j] = 0.0f;
|
|
m_OneReg[i][j] = 1.0f;
|
|
m_TwoReg[i][j] = 2.0f;
|
|
}
|
|
}
|
|
|
|
m_bLegacyPixelShade = TRUE;
|
|
m_pLegacyPixelShader = NULL;
|
|
|
|
memset( m_bPixelDiscard, 0, sizeof(m_bPixelDiscard) );
|
|
|
|
// multi-sample stuff
|
|
m_CurrentSample = 0;
|
|
m_SampleMask = 0xffffffff;
|
|
SetSampleMode( 1, TRUE );
|
|
m_bSampleCovered[0][0] =
|
|
m_bSampleCovered[0][1] =
|
|
m_bSampleCovered[0][2] =
|
|
m_bSampleCovered[0][3] = TRUE;
|
|
|
|
memset( m_TexCvg, 0, sizeof(m_TexCvg) );
|
|
memset( m_TexFlt, 0, sizeof(m_TexFlt) );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// SampleAndInvertRHW - Sample 1/W at current given location, invert, return
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
FLOAT RefRast::SampleAndInvertRHW( FLOAT fX, FLOAT fY )
|
|
{
|
|
FLOAT fPixelRHW = fX*m_fRHWA + fY*m_fRHWB + m_fRHWC;
|
|
FLOAT fPixelW = ( 0. != fPixelRHW ) ? ( 1./fPixelRHW ) : ( 0. );
|
|
return fPixelW;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
RefRast::EvalPixelPosition( int iPix )
|
|
{
|
|
BOOL bPixelIn;
|
|
|
|
if (m_SampleCount > 1)
|
|
{
|
|
bPixelIn = FALSE; // assume out, then set if any in
|
|
|
|
// generating multiple samples, so must evaluate all
|
|
// sample positions for in/out
|
|
do
|
|
{
|
|
BOOL bPixelSampleIn = GetCurrentSampleMask();
|
|
if (!bPixelSampleIn) continue;
|
|
|
|
// get sample location
|
|
INT32 iX = GetCurrentSampleX(iPix);
|
|
INT32 iY = GetCurrentSampleY(iPix);
|
|
|
|
// test each edge
|
|
for ( int iEdge=0; iEdge<m_iEdgeCount; iEdge++ )
|
|
{
|
|
bPixelSampleIn &= m_Edge[iEdge].Test( iX, iY );
|
|
if (!bPixelSampleIn) break;
|
|
}
|
|
|
|
m_bSampleCovered[m_CurrentSample][iPix] = bPixelSampleIn;
|
|
|
|
// accumulate per-sample test into per-pixel test
|
|
bPixelIn |= bPixelSampleIn;
|
|
|
|
} while (NextSample());
|
|
}
|
|
else
|
|
{
|
|
bPixelIn = TRUE; // assume pixel is inside all edges
|
|
|
|
// single sample, so just test pixel center
|
|
for ( int iEdge=0; iEdge<m_iEdgeCount; iEdge++ )
|
|
{
|
|
bPixelIn &= m_Edge[iEdge].Test( m_iX[iPix]<<4, m_iY[iPix]<<4 );
|
|
if (!bPixelIn) break;
|
|
}
|
|
}
|
|
return bPixelIn;
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Triangle (& Point) Setup
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// PerTriangleSetup - Per-triangle portion of triangle setup excluding any
|
|
// per-edge or per-attribute work. Includes snapping of x,y coords to n.4
|
|
// grid to enable subsequent edge computations to be exact fixed point;
|
|
// computation of determinant; culling; computation and intersection tests
|
|
// of scan area; and setup of perspective correction function.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL RefRast::PerTriangleSetup(
|
|
FLOAT* pVtx0, FLOAT* pVtx1, FLOAT* pVtx2,
|
|
DWORD CullMode,
|
|
RECT* pClip)
|
|
{
|
|
m_bIsLine = FALSE;
|
|
|
|
FLOAT fX0 = *(pVtx0+0);
|
|
FLOAT fY0 = *(pVtx0+1);
|
|
FLOAT fX1 = *(pVtx1+0);
|
|
FLOAT fY1 = *(pVtx1+1);
|
|
FLOAT fX2 = *(pVtx2+0);
|
|
FLOAT fY2 = *(pVtx2+1);
|
|
|
|
// compute fixed point x,y coords snapped to n.4 with nearest-even round
|
|
m_iX0 = FloatToNdot4(fX0);
|
|
m_iY0 = FloatToNdot4(fY0);
|
|
m_iX1 = FloatToNdot4(fX1);
|
|
m_iY1 = FloatToNdot4(fY1);
|
|
m_iX2 = FloatToNdot4(fX2);
|
|
m_iY2 = FloatToNdot4(fY2);
|
|
|
|
// compute integer deltas
|
|
INT32 iDelX10 = m_iX1 - m_iX0;
|
|
INT32 iDelX02 = m_iX0 - m_iX2;
|
|
INT32 iDelY01 = m_iY0 - m_iY1;
|
|
INT32 iDelY20 = m_iY2 - m_iY0;
|
|
|
|
// compute determinant in n.8 fixed point (n.4 * n.4 = n.8)
|
|
m_iDet =
|
|
( (INT64)iDelX10 * (INT64)iDelY20 ) -
|
|
( (INT64)iDelX02 * (INT64)iDelY01 );
|
|
|
|
// check for degeneracy (no area)
|
|
if ( 0 == m_iDet ) { return TRUE; }
|
|
|
|
// do culling
|
|
switch ( CullMode )
|
|
{
|
|
case D3DCULL_NONE: break;
|
|
case D3DCULL_CW: if ( m_iDet > 0 ) { return TRUE; } break;
|
|
case D3DCULL_CCW: if ( m_iDet < 0 ) { return TRUE; } break;
|
|
}
|
|
|
|
// compute bounding box for scan area
|
|
FLOAT fXMin = MIN( fX0, MIN( fX1, fX2 ) );
|
|
FLOAT fXMax = MAX( fX0, MAX( fX1, fX2 ) );
|
|
FLOAT fYMin = MIN( fY0, MIN( fY1, fY2 ) );
|
|
FLOAT fYMax = MAX( fY0, MAX( fY1, fY2 ) );
|
|
// convert to integer (round to +inf)
|
|
m_iXMin = (INT32)(fXMin+.5);
|
|
m_iXMax = (INT32)(fXMax+.5);
|
|
m_iYMin = (INT32)(fYMin+.5);
|
|
m_iYMax = (INT32)(fYMax+.5);
|
|
|
|
// clip bbox to rendering surface
|
|
m_iXMin = MAX( m_iXMin, pClip->left );
|
|
m_iXMax = MIN( m_iXMax, pClip->right );
|
|
m_iYMin = MAX( m_iYMin, pClip->top );
|
|
m_iYMax = MIN( m_iYMax, pClip->bottom );
|
|
|
|
// reject if no coverage
|
|
if ( ( m_iXMin < pClip->left ) ||
|
|
( m_iXMax > pClip->right ) ||
|
|
( m_iYMin < pClip->top ) ||
|
|
( m_iYMax > pClip->bottom ) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// compute float versions of snapped coord data
|
|
m_fX0 = (FLOAT)m_iX0 * 1.0F/16.0F;
|
|
m_fY0 = (FLOAT)m_iY0 * 1.0F/16.0F;
|
|
m_fDelX10 = (FLOAT)iDelX10 * 1.0F/16.0F;
|
|
m_fDelX02 = (FLOAT)iDelX02 * 1.0F/16.0F;
|
|
m_fDelY01 = (FLOAT)iDelY01 * 1.0F/16.0F;
|
|
m_fDelY20 = (FLOAT)iDelY20 * 1.0F/16.0F;
|
|
|
|
// compute inverse determinant
|
|
FLOAT fDet = (1./(FLOAT)(1<<8)) * (FLOAT)m_iDet;
|
|
m_fTriOODet = 1.f/fDet;
|
|
|
|
// compute linear function for 1/W (for perspective correction)
|
|
m_fRHW0 = *(pVtx0+3);
|
|
m_fRHW1 = *(pVtx1+3);
|
|
m_fRHW2 = *(pVtx2+3);
|
|
|
|
// compute linear deltas along two edges
|
|
FLOAT fDelAttrib10 = m_fRHW1 - m_fRHW0;
|
|
FLOAT fDelAttrib20 = m_fRHW2 - m_fRHW0;
|
|
|
|
// compute A & B terms (dVdX and dVdY)
|
|
m_fRHWA = m_fTriOODet * ( fDelAttrib10 * m_fDelY20 + fDelAttrib20 * m_fDelY01 );
|
|
m_fRHWB = m_fTriOODet * ( fDelAttrib20 * m_fDelX10 + fDelAttrib10 * m_fDelX02 );
|
|
|
|
// compute C term (Fv = A*Xv + B*Yv + C => C = Fv - A*Xv - B*Yv)
|
|
m_fRHWC = m_fRHW0 - ( m_fRHWA * m_fX0 ) - ( m_fRHWB * m_fY0 );
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Line Setup & Evaluate
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// 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.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
static BOOL
|
|
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;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// PerLineSetup - Does per-line setup including scan conversion
|
|
//
|
|
// This implements the Grid Intersect Quanization (GIQ) convention (which is
|
|
// also used in Windows).
|
|
//
|
|
// Returns: TRUE if line is discarded; FALSE if line to be drawn
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
RefRast::PerLineSetup(
|
|
FLOAT* pVtx0, FLOAT* pVtx1,
|
|
BOOL bLastPixel,
|
|
RECT* pClip)
|
|
{
|
|
m_bIsLine = TRUE;
|
|
|
|
FLOAT fX0 = *(pVtx0+0);
|
|
FLOAT fY0 = *(pVtx0+1);
|
|
FLOAT fX1 = *(pVtx1+0);
|
|
FLOAT fY1 = *(pVtx1+1);
|
|
|
|
// compute fixed point x,y coords snapped to n.4 with nearest-even round
|
|
m_iX0 = FloatToNdot4( fX0 );
|
|
m_iY0 = FloatToNdot4( fY0 );
|
|
m_iX1 = FloatToNdot4( fX1 );
|
|
m_iY1 = FloatToNdot4( fY1 );
|
|
|
|
// compute x,y extents of the line (fixed point)
|
|
INT32 iXSize = m_iX1 - m_iX0;
|
|
INT32 iYSize = m_iY1 - m_iY0;
|
|
|
|
if ( ( iXSize == 0 ) && ( iYSize == 0 ) ) { return TRUE; }
|
|
|
|
// determine major direction and compute line function
|
|
// 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 ( labs( iXSize ) >= labs( iYSize ) )
|
|
{
|
|
// here for X major
|
|
m_bLineXMajor = TRUE;
|
|
m_fLineMajorLength = (FLOAT)iXSize * (1./16.);
|
|
|
|
// line function: y = F(x) = ( [0]*x + [1] ) / [2]
|
|
m_iLineEdgeFunc[0] = iYSize;
|
|
m_iLineEdgeFunc[1] = (INT64)m_iY0*(INT64)m_iX1 - (INT64)m_iY1*(INT64)m_iX0;
|
|
m_iLineEdgeFunc[2] = iXSize;
|
|
}
|
|
else
|
|
{
|
|
// here for Y major
|
|
m_bLineXMajor = FALSE;
|
|
m_fLineMajorLength = (FLOAT)iYSize * (1./16.);
|
|
|
|
// line function: x = F(y) = ( [0]*y + [1] ) / [2]
|
|
m_iLineEdgeFunc[0] = iXSize;
|
|
m_iLineEdgeFunc[1] = (INT64)m_iX0*(INT64)m_iY1 - (INT64)m_iX1*(INT64)m_iY0;
|
|
m_iLineEdgeFunc[2] = iYSize;
|
|
}
|
|
|
|
BOOL bSlopeIsOne = ( labs( iXSize ) == labs( iYSize ) );
|
|
BOOL bSlopeIsPosOne =
|
|
bSlopeIsOne &&
|
|
( ( (FLOAT)m_iLineEdgeFunc[0]/(FLOAT)m_iLineEdgeFunc[2] ) > 0. );
|
|
|
|
// compute candidate pixel location for line endpoints
|
|
//
|
|
// 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
|
|
//
|
|
// nearest ceiling of Y is ceil( Y - .5), and is done by converting to floor via:
|
|
//
|
|
// ceil( A/B ) = floor( (A+B-1)/B )
|
|
//
|
|
// where A is coordinate - .5, and B is 0x10 (thus A/B is an n.4 fixed point number)
|
|
//
|
|
// A+B-1 = ( (Y - half) + B - 1 = ( (Y-0x8) + 0x10 - 0x1 = Y + 0x7
|
|
// since B is 2**4, divide by B is right shift by 4
|
|
//
|
|
INT32 iPixX0 = ( m_iX0 + ( bSlopeIsPosOne ? 0x8 : 0x7 ) ) >> 4;
|
|
INT32 iPixX1 = ( m_iX1 + ( bSlopeIsPosOne ? 0x8 : 0x7 ) ) >> 4;
|
|
INT32 iPixY0 = ( m_iY0 + 0x7 ) >> 4;
|
|
INT32 iPixY1 = ( m_iY1 + 0x7 ) >> 4;
|
|
|
|
|
|
// check for vertices in/out of diamond
|
|
BOOL bV0InDiamond = PointDiamondCheck( m_iX0 - (iPixX0<<4), m_iY0 - (iPixY0<<4), bSlopeIsOne, bSlopeIsPosOne );
|
|
BOOL bV1InDiamond = PointDiamondCheck( m_iX1 - (iPixX1<<4), m_iY1 - (iPixY1<<4), bSlopeIsOne, bSlopeIsPosOne );
|
|
|
|
// compute step value
|
|
m_iLineStep = ( m_fLineMajorLength > 0 ) ? ( +1 ) : ( -1 );
|
|
|
|
// compute float and integer major start (V0) and end (V1) positions
|
|
INT32 iLineMajor0 = ( m_bLineXMajor ) ? ( m_iX0 ) : ( m_iY0 );
|
|
INT32 iLineMajor1 = ( m_bLineXMajor ) ? ( m_iX1 ) : ( m_iY1 );
|
|
m_iLineMin = ( m_bLineXMajor ) ? ( iPixX0 ) : ( iPixY0 );
|
|
m_iLineMax = ( m_bLineXMajor ) ? ( iPixX1 ) : ( iPixY1 );
|
|
|
|
// need to do lots of compares which are flipped if major direction is negative
|
|
#define LINEDIR_CMP( _A, _B ) \
|
|
( ( m_fLineMajorLength > 0 ) ? ( (_A) < (_B) ) : ( (_A) > (_B) ) )
|
|
|
|
// do first pixel handling - keep first pixel if not in or behind diamond
|
|
if ( !( bV0InDiamond || LINEDIR_CMP( iLineMajor0, (m_iLineMin<<4) ) ) )
|
|
{
|
|
m_iLineMin += m_iLineStep;
|
|
}
|
|
|
|
// do last-pixel handling - keep last pixel if past diamond (in which case
|
|
// the pixel is always filled) or if in diamond and rendering last pixel
|
|
if ( !( ( !bV1InDiamond && LINEDIR_CMP( (m_iLineMax<<4), iLineMajor1 ) ) ||
|
|
( bV1InDiamond && bLastPixel ) ) )
|
|
{
|
|
m_iLineMax -= m_iLineStep;
|
|
}
|
|
|
|
// return if no (major) extent (both before and after clamping to render buffer)
|
|
if ( LINEDIR_CMP( m_iLineMax, m_iLineMin ) ) return TRUE;
|
|
|
|
// snap major extent to render buffer
|
|
INT16 iRendBufMajorMin = m_bLineXMajor ? pClip->left : pClip->top;
|
|
INT16 iRendBufMajorMax = m_bLineXMajor ? pClip->right : pClip->bottom;
|
|
if ( ( ( m_iLineMin < iRendBufMajorMin ) &&
|
|
( m_iLineMax < iRendBufMajorMin ) ) ||
|
|
( ( m_iLineMin > iRendBufMajorMax ) &&
|
|
( m_iLineMax > iRendBufMajorMax ) ) ) { return TRUE; }
|
|
m_iLineMin = MAX( 0, MIN( iRendBufMajorMax, m_iLineMin ) );
|
|
m_iLineMax = MAX( 0, MIN( iRendBufMajorMax, m_iLineMax ) );
|
|
|
|
// return if no (major) extent
|
|
if ( LINEDIR_CMP( m_iLineMax, m_iLineMin ) ) return TRUE;
|
|
|
|
// number of steps to iterate
|
|
m_cLineSteps = abs( m_iLineMax - m_iLineMin );
|
|
|
|
// initial state for per-pixel line iterator
|
|
m_iMajorCoord = m_iLineMin;
|
|
|
|
// compute float versions of snapped coord data
|
|
m_fX0 = (FLOAT)m_iX0 * 1.0F/16.0F;
|
|
m_fY0 = (FLOAT)m_iY0 * 1.0F/16.0F;
|
|
|
|
// compute linear function for 1/W (for perspective correction)
|
|
m_fRHW0 = *(pVtx0+3);
|
|
m_fRHW1 = *(pVtx1+3);
|
|
|
|
FLOAT fDelta = ( m_fRHW1 - m_fRHW0 ) / m_fLineMajorLength;
|
|
m_fRHWA = ( m_bLineXMajor ) ? ( fDelta ) : ( 0. );
|
|
m_fRHWB = ( m_bLineXMajor ) ? ( 0. ) : ( fDelta );
|
|
m_fRHWC = m_fRHW0 - ( m_fRHWA * m_fX0 ) - ( m_fRHWB * m_fY0 );
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// DivRoundDown(A,B) = ceiling(A/B - 1/2)
|
|
//
|
|
// ceiling(A/B - 1/2) == floor(A/B + 1/2 - epsilon)
|
|
// == floor( (A + (B/2 - epsilon))/B )
|
|
//
|
|
// Does correct thing for all sign combinations of A and B.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
static INT64
|
|
DivRoundDown(INT64 iA, INT32 iB)
|
|
{
|
|
INT32 i = 0;
|
|
static const INT32 iEps[3] =
|
|
{
|
|
1, // iA > 0, iB > 0
|
|
0, // iA < 0, iB > 0 OR iA > 0, iB < 0
|
|
1 // iA < 0, iB < 0
|
|
};
|
|
if (iA < 0)
|
|
{
|
|
i++;
|
|
iA = -iA;
|
|
}
|
|
if (iB < 0)
|
|
{
|
|
i++;
|
|
iB = -iB;
|
|
}
|
|
iA += (iB-iEps[i]) >> 1;
|
|
iA /= iB;
|
|
if (iEps[i] == 0)
|
|
iA = -iA;
|
|
return(iA);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// DoScanCnvLine - Walks the line major axis, computes the appropriate minor
|
|
// axis coordinate, and generates pixels.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefRast::StepLine( void )
|
|
{
|
|
// evaluate line function to compute minor coord for this major
|
|
INT64 iMinorCoord =
|
|
( ( m_iLineEdgeFunc[0] * (INT64)(m_iMajorCoord<<4) ) + m_iLineEdgeFunc[1] );
|
|
iMinorCoord = DivRoundDown(iMinorCoord, m_iLineEdgeFunc[2]<<4);
|
|
|
|
// grab x,y
|
|
m_iX[0] = m_bLineXMajor ? m_iMajorCoord : iMinorCoord;
|
|
m_iY[0] = m_bLineXMajor ? iMinorCoord : m_iMajorCoord;
|
|
|
|
// step major for next evaluation
|
|
m_iMajorCoord += m_iLineStep;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Multi-Sample Controls
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define _SetSampleDelta( _SampleNumber, _XOffset, _YOffset ) \
|
|
{ \
|
|
m_SampleDelta[_SampleNumber][0] = ((INT32)((_XOffset)*16.F)); \
|
|
m_SampleDelta[_SampleNumber][1] = ((INT32)((_YOffset)*16.F)); \
|
|
}
|
|
|
|
void
|
|
RefRast::SetSampleMode( UINT MultiSamples, BOOL bAntialias )
|
|
{
|
|
switch (MultiSamples)
|
|
{
|
|
default:
|
|
case 1:
|
|
m_SampleCount = 1;
|
|
_SetSampleDelta( 0, 0., 0. );
|
|
break;
|
|
|
|
case 4:
|
|
m_SampleCount = 4;
|
|
_SetSampleDelta( 0, -.25, -.25 );
|
|
_SetSampleDelta( 1, +.25, -.25 );
|
|
_SetSampleDelta( 2, +.25, +.25 );
|
|
_SetSampleDelta( 3, -.25, +.25 );
|
|
break;
|
|
|
|
case 9:
|
|
m_SampleCount = 9;
|
|
_SetSampleDelta( 0, -.333, -.333 );
|
|
_SetSampleDelta( 1, -.333, 0.0 );
|
|
_SetSampleDelta( 2, -.333, +.333 );
|
|
_SetSampleDelta( 3, 0.0, -.333 );
|
|
_SetSampleDelta( 4, 0.0, 0.0 );
|
|
_SetSampleDelta( 5, 0.0, +.333 );
|
|
_SetSampleDelta( 6, +.333, -.333 );
|
|
_SetSampleDelta( 7, +.333, 0.0 );
|
|
_SetSampleDelta( 8, +.333, +.333 );
|
|
break;
|
|
}
|
|
|
|
// if not FSAA then sample all at pixel center
|
|
if (!bAntialias)
|
|
{
|
|
for (UINT Sample=0; Sample<m_SampleCount; Sample++)
|
|
{
|
|
_SetSampleDelta( Sample, 0., 0. );
|
|
}
|
|
}
|
|
|
|
m_CurrentSample = 0;
|
|
m_bSampleCovered[0][0] =
|
|
m_bSampleCovered[0][1] =
|
|
m_bSampleCovered[0][2] =
|
|
m_bSampleCovered[0][3] = TRUE;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// end
|