/////////////////////////////////////////////////////////////////////////////// // 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<> (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<