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.
342 lines
11 KiB
342 lines
11 KiB
///////////////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) Microsoft Corporation, 1998.
|
|
//
|
|
// cvgmask.cpp
|
|
//
|
|
// Direct3D Reference Rasterizer - Antialiasing Coverage Mask Generation
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
// from edgefunc.hpp
|
|
// Normalization factor for antialising is stored in floating point. This is
|
|
// computed during the setup and applied per-pixel after the (non-normalized)
|
|
// edge distance is evaluated.
|
|
//
|
|
DOUBLE m_dNorm;
|
|
INT16 m_iEdgeYGradBits; // 1.8 fixed point
|
|
|
|
// from edgefunc.cpp ::Set
|
|
if ( bFragProcEnable )
|
|
{
|
|
// compute normalization factor for antialiasing - normalizes for 'square'
|
|
// distance (a.k.a 'manhatten' distance) such that an equidistant point
|
|
// sweep of a distance of 0.5 is a square 1.0 pixel area.
|
|
m_dNorm = 1.0 / ( fabs( fY0-fY1 ) + fabs( fX1-fX0 ) );
|
|
|
|
// compute rounded fixed point Y gradient bits for generation of
|
|
// antialiasing coverage mask
|
|
m_iEdgeYGradBits = AS_INT16( ((fY0-fY1)*m_dNorm) + DOUBLE_8_SNAP );
|
|
}
|
|
|
|
// from ::AATest
|
|
// The edge evaluation is done exactly the same as the point sample case, then
|
|
// it is converted to double precision floating point for the normalization and
|
|
// rounding. Using doubles makes it very easy to carry adequate precision in
|
|
// the normalization factor and to convert to 32 bit signed integer (holding
|
|
// the n.5 fixed point distance) with round to nearest even.
|
|
//
|
|
|
|
// 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
|
|
|
|
// convert to double (adjust for n.8 fixed point) for normalization
|
|
// and rounding
|
|
DOUBLE dEdgeDist = (DOUBLE)iEdgeDist * (1./(DOUBLE)(1<<8));
|
|
|
|
// normalize edge distance
|
|
dEdgeDist *= m_dNorm;
|
|
|
|
// convert distance to fixed point with nearest-even round;
|
|
// keep 5 fractional bits for antialiasing
|
|
INT32 iEdgeDistRnd = AS_INT32( dEdgeDist + DOUBLE_5_SNAP );
|
|
|
|
// pixel is fully outside of edge if out by +.5 or more
|
|
if ( iEdgeDistRnd >= +(1<<4) ) return 0x0000;
|
|
|
|
// pixel is fully inside of edge if in by -.5 or more
|
|
if ( iEdgeDistRnd <= -(1<<4) ) return 0xFFFF;
|
|
|
|
// here when pixel is within 1/2 (square distance) of edge
|
|
// compute coverage mask for this edge
|
|
return ComputeCoverageMask( m_iEdgeYGradBits, m_bAPos, m_bBPos, iEdgeDistRnd );
|
|
|
|
#endif
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Tables used in computation of coverage mask
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// These are the ranges of the x gradient (the 'A' of F=Ax+By+c) for one
|
|
// octant into which the edge slopes are binned.
|
|
//-----------------------------------------------------------------------------
|
|
#define A_RANGES 4
|
|
static UINT16 uARanges[A_RANGES] = {
|
|
// 0.0.8 values
|
|
0x00, // 0.00
|
|
0x40, // 0.25
|
|
0x55, // 0.33
|
|
0x66, // 0.40
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// These are the 16 bit coverage masks for each of the A ranges. The
|
|
// 15 values within each range define the order in which the coverage
|
|
// mask bits are enabled, thus the least-significant index is the number
|
|
// of coverage mask bits that need to be enabled.
|
|
//-----------------------------------------------------------------------------
|
|
static UINT16 CvgMasks[A_RANGES][15] = {
|
|
{ // 0.000 .. 0.250
|
|
0x1,
|
|
0x3,
|
|
0x7,
|
|
0xF,
|
|
0x1F,
|
|
0x3F,
|
|
0x7F,
|
|
0xFF,
|
|
0x1FF,
|
|
0x3FF,
|
|
0x7FF,
|
|
0xFFF,
|
|
0x1FFF,
|
|
0x3FFF,
|
|
0x7FFF,
|
|
},
|
|
{ // 0.250 .. 0.333
|
|
0x1,
|
|
0x3,
|
|
0x7,
|
|
0x17,
|
|
0x1F,
|
|
0x3F,
|
|
0x7F,
|
|
0x17F,
|
|
0x1FF,
|
|
0x3FF,
|
|
0x7FF,
|
|
0x17FF,
|
|
0x1FFF,
|
|
0x3FFF,
|
|
0x7FFF,
|
|
},
|
|
{ // 0.333 .. 0.400
|
|
0x1,
|
|
0x3,
|
|
0x13,
|
|
0x17,
|
|
0x37,
|
|
0x3F,
|
|
0x13F,
|
|
0x17F,
|
|
0x37F,
|
|
0x3FF,
|
|
0x13FF,
|
|
0x17FF,
|
|
0x37FF,
|
|
0x3FFF,
|
|
0x7FFF,
|
|
},
|
|
{ // 0.400 .. 0.500
|
|
0x1,
|
|
0x3,
|
|
0x13,
|
|
0x17,
|
|
0x37,
|
|
0x137,
|
|
0x13F,
|
|
0x17F,
|
|
0x37F,
|
|
0x137F,
|
|
0x13FF,
|
|
0x17FF,
|
|
0x37FF,
|
|
0x3FFF,
|
|
0x7FFF,
|
|
},
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// This table is used for a rough area approximation. The [16] index
|
|
// is the top 4 bits of the edge distance (i.e. the distance from the
|
|
// edge to the center of the pixel). The [4] index is the top two bits
|
|
// of the A gradient term. The return is the number of bits that should
|
|
// be set in the coverage mask, which is a function of the area covered.
|
|
//-----------------------------------------------------------------------------
|
|
static INT16 nBitsA = 2;
|
|
static INT16 nBitsE = 4;
|
|
static INT16 nBitsToEnable[4][16] = {
|
|
{ // A: 0.000; B: 1.000
|
|
8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16,
|
|
},
|
|
{ // A: 0.125; B: 0.875
|
|
8, 9, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16, 16,
|
|
},
|
|
{ // A: 0.250; B: 0.750
|
|
8, 9, 9, 10, 11, 11, 12, 13, 13, 14, 15, 15, 15, 16, 16, 16,
|
|
},
|
|
{ // A: 0.375; B: 0.625
|
|
8, 9, 10, 10, 11, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 16,
|
|
},
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Mask manipulation functions - these are needed because coverage mask
|
|
// table (indexed by angle) is for one octant only and need to be
|
|
// munged in various ways for other octants
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
static void
|
|
doCvgMaskTBFlip(UINT16 &CvgMask)
|
|
{
|
|
UINT16 CvgMaskT = CvgMask;
|
|
CvgMask = 0;
|
|
CvgMask |= (((CvgMaskT >> 0) & 0x1) << 12);
|
|
CvgMask |= (((CvgMaskT >> 1) & 0x1) << 13);
|
|
CvgMask |= (((CvgMaskT >> 2) & 0x1) << 14);
|
|
CvgMask |= (((CvgMaskT >> 3) & 0x1) << 15);
|
|
CvgMask |= (((CvgMaskT >> 4) & 0x1) << 8);
|
|
CvgMask |= (((CvgMaskT >> 5) & 0x1) << 9);
|
|
CvgMask |= (((CvgMaskT >> 6) & 0x1) << 10);
|
|
CvgMask |= (((CvgMaskT >> 7) & 0x1) << 11);
|
|
CvgMask |= (((CvgMaskT >> 8) & 0x1) << 4);
|
|
CvgMask |= (((CvgMaskT >> 9) & 0x1) << 5);
|
|
CvgMask |= (((CvgMaskT >> 10) & 0x1) << 6);
|
|
CvgMask |= (((CvgMaskT >> 11) & 0x1) << 7);
|
|
CvgMask |= (((CvgMaskT >> 12) & 0x1) << 0);
|
|
CvgMask |= (((CvgMaskT >> 13) & 0x1) << 1);
|
|
CvgMask |= (((CvgMaskT >> 14) & 0x1) << 2);
|
|
CvgMask |= (((CvgMaskT >> 15) & 0x1) << 3);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
static void
|
|
doCvgMaskSFlip(UINT16 &CvgMask)
|
|
{
|
|
UINT16 CvgMaskT = CvgMask;
|
|
CvgMask = 0;
|
|
CvgMask |= (((CvgMaskT >> 0) & 0x1) << 0);
|
|
CvgMask |= (((CvgMaskT >> 1) & 0x1) << 4);
|
|
CvgMask |= (((CvgMaskT >> 2) & 0x1) << 8);
|
|
CvgMask |= (((CvgMaskT >> 3) & 0x1) << 12);
|
|
CvgMask |= (((CvgMaskT >> 4) & 0x1) << 1);
|
|
CvgMask |= (((CvgMaskT >> 5) & 0x1) << 5);
|
|
CvgMask |= (((CvgMaskT >> 6) & 0x1) << 9);
|
|
CvgMask |= (((CvgMaskT >> 7) & 0x1) << 13);
|
|
CvgMask |= (((CvgMaskT >> 8) & 0x1) << 2);
|
|
CvgMask |= (((CvgMaskT >> 9) & 0x1) << 6);
|
|
CvgMask |= (((CvgMaskT >> 10) & 0x1) << 10);
|
|
CvgMask |= (((CvgMaskT >> 11) & 0x1) << 14);
|
|
CvgMask |= (((CvgMaskT >> 12) & 0x1) << 3);
|
|
CvgMask |= (((CvgMaskT >> 13) & 0x1) << 7);
|
|
CvgMask |= (((CvgMaskT >> 14) & 0x1) << 11);
|
|
CvgMask |= (((CvgMaskT >> 15) & 0x1) << 15);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// ComputeCoverageMask - Computes the 16 bit coverage mask. Called once per
|
|
// pixel per crossing edge (i.e. up to 3 times per pixel).
|
|
//
|
|
// This is doing the algorithm described in Schilling's Siggraph paper, with
|
|
// modifications to perform the operation for a single virtual octant and
|
|
// then munging the result for the actual octant.
|
|
//
|
|
// Note that the A and B signs for the edges must be computed very carefully
|
|
// to guarantee that shared edges will always result in full complimentary
|
|
// coverage of pixels on the shared edge.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
RRCvgMask
|
|
ComputeCoverageMask(
|
|
INT16 iABits, // 1.8 value
|
|
BOOL bAPos, BOOL bBPos,
|
|
INT16 iEBits) // 1.5.5 value, but ranges from -.5 to +.5 here
|
|
{
|
|
RRCvgMask CvgMask; // return value
|
|
|
|
// grab already rounded 8 bit value and take absolute value
|
|
UINT16 uMagA = (iABits < 0) ? ((UINT16)-iABits) : ((UINT16)iABits);
|
|
UINT16 uABits = uMagA & 0x1ff;
|
|
|
|
// compute booleans for manipulating masks
|
|
BOOL bMaskInvert = TRUE;
|
|
BOOL bMaskRFlip = !(bAPos ^ bBPos);
|
|
if (!bAPos) {
|
|
iEBits = -iEBits;
|
|
bMaskInvert = FALSE;
|
|
}
|
|
|
|
//
|
|
// compute A offset from x or y axis
|
|
//
|
|
// mirror around 45 degree axis - keep track of this because
|
|
// the 45 degree mirroring requires a side-to-side mask flip
|
|
BOOL bMaskSFlip = (uABits > 0x80); // > 0.5F ?
|
|
if (bMaskSFlip) { uABits = 0x100 - uABits; }
|
|
|
|
// uABits is now a 0.0.8 value in the range 0x00 to 0x80
|
|
|
|
//
|
|
// determine number of bits to enable in mask based on the area covered
|
|
//
|
|
// extract bits from A for area lookup
|
|
UINT16 uAAreaBits = (uABits == 0x80)
|
|
? ((1<<nBitsA)-1) : (uABits >> (7-nBitsA));
|
|
|
|
// grab distance bits for area lookup - take absolute value and clamp
|
|
UINT16 uEBits = (iEBits < 0) ? ((UINT16)-iEBits) : ((UINT16)iEBits);
|
|
uEBits = MIN(uEBits,(UINT16)(((1<<nBitsE)-1))); // clamp
|
|
|
|
// look up area in table - returns number of bits to enable
|
|
INT16 iNumCvgBits = nBitsToEnable[uAAreaBits][uEBits];
|
|
|
|
// flip for negative distance
|
|
if (iEBits < 0) { iNumCvgBits = 16 - iNumCvgBits; }
|
|
|
|
//
|
|
// compute slope range index and look up coverage mask
|
|
//
|
|
INT16 iARange = 3;
|
|
for (INT16 i=0; i<(A_RANGES-1); i++) {
|
|
if ((uARanges[i] <= uABits) && (uABits < uARanges[i+1])) {
|
|
iARange = i; break;
|
|
}
|
|
}
|
|
|
|
// check for zero/full coverage else look up coverage mask
|
|
if (0 == iNumCvgBits) {
|
|
CvgMask = 0x0000;
|
|
} else if (16 == iNumCvgBits) {
|
|
CvgMask = 0xffff;
|
|
} else {
|
|
CvgMask = CvgMasks[iARange][iNumCvgBits-1];
|
|
}
|
|
|
|
//
|
|
// adjust mask for different quadrants and directions
|
|
//
|
|
// first to side-to-side mask flip for 45 degree mirroring
|
|
if (bMaskSFlip) { doCvgMaskSFlip(CvgMask); }
|
|
// invert for 'backwards' line directions
|
|
if (bMaskInvert) { CvgMask ^= 0xffff; }
|
|
// flip for same sign quadrants
|
|
if (bMaskRFlip) { doCvgMaskTBFlip(CvgMask); }
|
|
|
|
return CvgMask;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// end
|