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.
185 lines
7.0 KiB
185 lines
7.0 KiB
///////////////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) Microsoft Corporation, 1998.
|
|
//
|
|
// EdgeFunc.cpp
|
|
//
|
|
// Direct3D Reference Rasterizer - Edge Function Processing
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// ComputeDeterminant - Computes triangle determinant for later use in edge
|
|
// functions. Computed in fixed point but returned as single precision
|
|
// floating point number.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
FLOAT
|
|
ComputeDeterminant(
|
|
FLOAT fX0, FLOAT fY0,
|
|
FLOAT fX1, FLOAT fY1,
|
|
FLOAT fX2, FLOAT fY2 )
|
|
{
|
|
// compute determinant with integer coordinates snapped to n.4 grid
|
|
INT32 iDelX10 =
|
|
AS_INT32( (DOUBLE)(fX1) + DOUBLE_4_SNAP ) -
|
|
AS_INT32( (DOUBLE)(fX0) + DOUBLE_4_SNAP );
|
|
INT32 iDelX02 =
|
|
AS_INT32( (DOUBLE)(fX0) + DOUBLE_4_SNAP ) -
|
|
AS_INT32( (DOUBLE)(fX2) + DOUBLE_4_SNAP );
|
|
INT32 iDelY01 =
|
|
AS_INT32( (DOUBLE)(fY0) + DOUBLE_4_SNAP ) -
|
|
AS_INT32( (DOUBLE)(fY1) + DOUBLE_4_SNAP );
|
|
INT32 iDelY20 =
|
|
AS_INT32( (DOUBLE)(fY2) + DOUBLE_4_SNAP ) -
|
|
AS_INT32( (DOUBLE)(fY0) + DOUBLE_4_SNAP );
|
|
|
|
// iDet is n.8 fixed point value (n.4 * n.4 = n.8)
|
|
INT64 iDet =
|
|
( (INT64)iDelX10 * (INT64)iDelY20 ) -
|
|
( (INT64)iDelX02 * (INT64)iDelY01 );
|
|
|
|
// convert to float for return
|
|
FLOAT fDet = (1./(FLOAT)(1<<8)) * (FLOAT)iDet;
|
|
|
|
return fDet;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Set - Computes edge function and associated information.
|
|
//
|
|
// Fragment processing boolean is passed to enable use of better techniques
|
|
// than the simple but not particularly good subpixel point sample done here.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RREdgeFunc::Set(
|
|
FLOAT fX0, FLOAT fY0, FLOAT fX1, FLOAT fY1,
|
|
FLOAT fDet, BOOL bFragProcEnable )
|
|
{
|
|
// compute fixed point x,y coords snapped to n.4 with nearest-even round
|
|
INT32 iX0 = AS_INT32( (DOUBLE)fX0 + DOUBLE_4_SNAP );
|
|
INT32 iY0 = AS_INT32( (DOUBLE)fY0 + DOUBLE_4_SNAP );
|
|
INT32 iX1 = AS_INT32( (DOUBLE)fX1 + DOUBLE_4_SNAP );
|
|
INT32 iY1 = AS_INT32( (DOUBLE)fY1 + DOUBLE_4_SNAP );
|
|
|
|
// compute A,B (gradient) terms - these are n.4 fixed point
|
|
m_iA = iY0 - iY1;
|
|
m_iB = iX1 - iX0;
|
|
|
|
// flip gradient signs if backfacing so functions are consistently
|
|
// greater than zero outside of primitive
|
|
if ( fDet > 0. ) { m_iA = -m_iA; m_iB = -m_iB; }
|
|
|
|
// compute C term
|
|
//
|
|
// function is by definition zero at the vertices, so:
|
|
// 0 = A*Xv + B*Yv + C => C = - A*Xv - B*Yv
|
|
//
|
|
// A*Xv & B*Yv are n.4 * n.4 = n.8, so C is n.8 fixed point
|
|
m_iC = - ( (INT64)iX0 * (INT64)m_iA ) - ( (INT64)iY0 * (INT64)m_iB );
|
|
|
|
// compute edge function sign flags - must be done consistently for vertical
|
|
// and horizontal cases to adhere to point sample fill rules and avoid
|
|
// under- and over-coverage for antialiasing
|
|
BOOL bEdgeAEQZero = ( m_iA == 0. );
|
|
BOOL bEdgeBEQZero = ( m_iB == 0. );
|
|
BOOL bEdgeAGTZero = ( m_iA > 0. );
|
|
BOOL bEdgeBGTZero = ( m_iB > 0. );
|
|
m_bAPos = bEdgeAEQZero ? bEdgeBGTZero : bEdgeAGTZero;
|
|
m_bBPos = bEdgeBEQZero ? bEdgeAGTZero : bEdgeBGTZero;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// PSTest - Point sampling test, returns coverage mask of all zero's if point
|
|
// is outside the edge, all 1's if point is inside. Supports the Direct3D
|
|
// left-top fill rule.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
RRCvgMask
|
|
RREdgeFunc::PSTest( INT16 iX, INT16 iY )
|
|
{
|
|
// evaluate edge distance function (n.8 fixed point)
|
|
INT64 iEdgeDist =
|
|
( (INT64)m_iA * (INT64)(iX<<4) ) + // n.4 * n.4 = n.8
|
|
( (INT64)m_iB * (INT64)(iY<<4) ) + // n.4 * n.4 = n.8
|
|
(INT64)m_iC; // n.8
|
|
|
|
// pixel sample position is outside edge if distance is > zero
|
|
//
|
|
// This implements the D3D left-top fill rule
|
|
//
|
|
// For exactly-on-edge case (distance == zero), the sign of the Y gradient
|
|
// is used to determine if the pixel is to be considered inside or outside
|
|
// of the edge. For the non-horizontal case, the m_bAPos bit is based
|
|
// simply on the sign of the Y slope. This implements the 'left' part of
|
|
// the 'left-top' rule.
|
|
//
|
|
// For the horizontal case, the sign of the B gradient (X slope) is taken
|
|
// into account in the computation of the m_bAPos bit when the A gradient
|
|
// is exactly zero, which forces a pixel exactly on a 'top' edge to be
|
|
// considered in and a pixel exactly on a 'bottom' edge to be considered out.
|
|
//
|
|
if ( ( iEdgeDist > 0 ) || ( ( iEdgeDist == 0 ) && m_bAPos ) )
|
|
{
|
|
// pixel is out
|
|
return 0x0000;
|
|
}
|
|
// pixel is in
|
|
return 0xFFFF;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// AATest - Anti alias edge test, returns coverage mask of all zero's if point
|
|
// is outside the edge, all 1's if point is inside, and partial if point is on
|
|
// or near the edge.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
RRCvgMask
|
|
RREdgeFunc::AATest( INT16 iX, INT16 iY )
|
|
{
|
|
RRCvgMask Mask = 0;
|
|
|
|
// n.4 integer representation of pixel center
|
|
INT64 iX64Center = (INT64)(iX<<4);
|
|
INT64 iY64Center = (INT64)(iY<<4);
|
|
|
|
// step across 4x4 subpixel sample points and point sample 16 locations
|
|
// to form coverage mask; area is split into eights to center samples
|
|
// around pixel center (for example, the two inner sample positions are
|
|
// each 1/8 of a pixel distance from the pixel center, and thus 1/4 of
|
|
// a pixel distance apart)
|
|
INT32 iYSub, iYEightths, iXSub, iXEightths;
|
|
for (iYSub = 0, iYEightths = -3; iYSub < 4; iYSub++, iYEightths += 2)
|
|
{
|
|
for (iXSub = 0, iXEightths = -3; iXSub < 4; iXSub++, iXEightths += 2)
|
|
{
|
|
// compute sample location, which is some n/8 offset from the
|
|
// pixel center (+/- 3/8 or 1/8)
|
|
INT64 iX64 = iX64Center + (iXEightths<<1);
|
|
INT64 iY64 = iY64Center + (iYEightths<<1);
|
|
INT64 iEdgeDist =
|
|
( (INT64)m_iA * iX64 ) + // n.4 * n.4 = n.8
|
|
( (INT64)m_iB * iY64 ) + // n.4 * n.4 = n.8
|
|
(INT64)m_iC; // n.8
|
|
|
|
// if the center is in (same left-top rule as in point sample)
|
|
if (!( ( iEdgeDist > 0 ) || ( ( iEdgeDist == 0 ) && m_bAPos ) ))
|
|
{
|
|
// pixel is in
|
|
Mask |= 1 << (iXSub + iYSub*4);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Mask;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// end
|