|
|
/**************************************************************************\
* * Copyright (c) 1998 Microsoft Corporation * * Module Name: * * Rasterizer.hpp * * Abstract: * * GpRasterizer class definition (and supporting classes) * * Created: * * 12/15/1998 DCurtis * \**************************************************************************/
#ifndef _RASTERIZER_HPP
#define _RASTERIZER_HPP
/////////////////////////////////////////////////////////////////////////
// The x86 C compiler insists on making a divide and modulus operation
// into two DIVs, when it can in fact be done in one. So we use this
// macro.
//
// Note: QUOTIENT_REMAINDER implicitly takes unsigned arguments.
//
// QUOTIENT_REMAINDER_64_32 takes a 64-bit numerator and produces 32-bit
// results.
#if defined(_USE_X86_ASSEMBLY)
#define QUOTIENT_REMAINDER(ulNumerator, ulDenominator, ulQuotient, ulRemainder)\
{ \ __asm mov eax, ulNumerator \ __asm sub edx, edx \ __asm div ulDenominator \ __asm mov ulQuotient, eax \ __asm mov ulRemainder, edx \ }
#define QUOTIENT_REMAINDER_64_32(ullNumerator, ulDenominator, ulQuotient, ulRemainder)\
{ \ ULONG ulNumeratorLow = *((ULONG*) &ullNumerator); \ ULONG ulNumeratorHigh = *((ULONG*) &ullNumerator + 1); \ __asm mov eax, ulNumeratorLow \ __asm mov edx, ulNumeratorHigh \ __asm div ulDenominator \ __asm mov ulQuotient, eax \ __asm mov ulRemainder, edx \ }
#else
#define QUOTIENT_REMAINDER(ulNumerator, ulDenominator, ulQuotient, ulRemainder)\
{ \ ulQuotient = (ULONG) ulNumerator / (ULONG) ulDenominator; \ ulRemainder = (ULONG) ulNumerator % (ULONG) ulDenominator; \ }
#define QUOTIENT_REMAINDER_64_32(ullNumerator, ulDenominator, ulQuotient, ulRemainder)\
{ \ ulQuotient = (ULONG) ((ULONGLONG) ullNumerator / (ULONG) ulDenominator); \ ulRemainder = (ULONG) ((ULONGLONG) ullNumerator % (ULONG) ulDenominator);\ }
#endif
enum GpVectorDirection { VectorGoingDown = -1, VectorHorizontal = 0, VectorGoingUp = 1, };
// This class does a y (vertical) DDA from (x1,y1) to (x2,y2), where y1 < y2.
// Horizontal lines are not handled.
//
// It is up to the caller to keep track of the current y value. This class
// advances and keeps track of the current x value. The Advance method should
// be called once for each increment of y.
//
// For fill algorithms (such as a winding fill), this class will also keep
// track of the original direction of the vector, if desired.
class GpYDda { protected: INT Error; // DDA cumulative error
INT ErrorUp; // DDA constant 1
INT YDelta; // DDA constant 2
INT YMax; // greatest y value (last scan line)
INT XInc; // DDA X Increment
INT XCur; // current position
GpVectorDirection Direction; // VectorGoingUp or VectorGoingDown
public: GpYDda() { /* we need a constructor with no params */ } GpYDda( FIX4 x1, FIX4 y1, FIX4 x2, FIX4 y2, GpVectorDirection direction = VectorGoingDown ) { Init(x1, y1, x2, y2, direction); } virtual ~GpYDda() {}
virtual VOID Init( FIX4 x1, FIX4 y1, FIX4 x2, FIX4 y2, GpVectorDirection direction = VectorGoingDown );
virtual VOID Advance();
BOOL DoneWithVector (INT y) { if (y < this->YMax) { Advance(); return FALSE; } return TRUE; }
INT GetX() { return this->XCur; }
GpVectorDirection GetDirection() { return Direction; }
virtual GpYDda * CreateYDda() { return new GpYDda(); } };
// Interface class for outputing a single span of a single raster at a time.
// When all the spans on a raster have been output, the EndRaster method
// is invoked. When all rasterization for all rasters is complete, the
// End method is invoked.
template<class T> class EpScanBufferNative; #define DpScanBuffer EpScanBufferNative<ARGB>
struct DpBrush; class DpContext;
// [agodfrey]
// * "Dp" should be "Ep" in this hierarchy.
//
// There are two types of class which use this interface -
// "leaf" classes which actually produce the colors from the brush,
// and "forwarding" ones which modify the input somehow, then forward it
// down to an object of another DpOutputSpan class. The "leaf" ones
// call Scan->NextBuffer, the "forwarding" ones can't. So my suggestion:
//
// * Make just two subclasses of DpOutputSpan, one for each type.
// Derive the rest of them from one of those two, instead of directly
// from DpOutputSpan.
class DpOutputSpan { public: virtual ~DpOutputSpan() {}
virtual GpStatus OutputSpan( INT y, INT xMin, INT xMax ) = 0;
virtual GpStatus EndRaster() // no more spans on this raster
{ return Ok; }
virtual GpStatus End() // all done rasterizing everything
{ return Ok; }
// !!! PERF [agodfrey]: I don't think this needs to be virtual.
// All the implementations seem to return "Scan" - just move the Scan
// pointer into the base class. DpClipRegion can just leave it NULL.
virtual DpScanBuffer* GetScanBuffer() { return NULL; }
virtual BOOL IsValid() const = 0;
static DpOutputSpan * Create( const DpBrush * brush, DpScanBuffer * scan, DpContext * context, const GpRect * drawBounds=NULL); };
typedef GpStatus (DpOutputSpan::*DpOutputSpanFunction)(INT, INT&, INT&);
// Interface class for outputing a series of rects within a Y Span.
class GpOutputYSpan { public: virtual ~GpOutputYSpan() {} virtual GpStatus OutputYSpan( INT yMin, INT yMax, INT * xCoords, // even number of X coordinates
INT numXCoords // must be a multiple of 2
) = 0; };
//#define USE_YSPAN_BUILDER
#ifndef USE_YSPAN_BUILDER
// Interface class for outputing a rect at a time. Used by GpRectBuilder class.
class GpOutputRect { public: virtual ~GpOutputRect() {} virtual GpStatus OutputRect( INT xMin, INT yMin, INT xMax, INT yMax ) = 0; };
// Builds up and outputs Y Span rects from single span inputs
class GpRectBuilder : public DpOutputSpan, // input
public GpOutputYSpan // output
{ private: // We now use an ObjectTag to determine if the object is valid
// instead of using a BOOL. This is much more robust and helps
// with debugging. It also enables us to version our objects
// more easily with a version number in the ObjectTag.
ObjectTag Tag; // Keep this as the 1st value in the object!
protected: VOID SetValid(BOOL valid) { Tag = valid ? ObjectTagGpRectBuilder : ObjectTagInvalid; }
protected: DynIntArray RectXCoords; // currently built rects
DynIntArray RasterXCoords; // x coords of current raster so far
INT RasterY; // y value of current raster
INT RectYMin; // starting y value of current rects
INT RectHeight; // height of current rects
GpOutputYSpan * FlushRects; // Used to output the RectXCoords buffer
GpOutputRect * RenderRect; // Used by FlushRects to ouput each rect
protected: GpStatus InitArrays();
public: // You can choose to output a single rect at a time with this constructor,
// or if you use the other constructor it will output an entire Y Span
// at a time.
GpRectBuilder(GpOutputRect * renderRect); GpRectBuilder(GpOutputYSpan * flushRects); virtual ~GpRectBuilder() { SetValid(FALSE); // so we don't use a deleted object
}
virtual BOOL IsValid() const { ASSERT((Tag == ObjectTagGpRectBuilder) || (Tag == ObjectTagInvalid)); #if DBG
if (Tag == ObjectTagInvalid) { WARNING1("Invalid GpRectBuilder"); } #endif
return (Tag == ObjectTagGpRectBuilder); }
// This method is the input of spans to this class
virtual GpStatus OutputSpan( INT y, INT xMin, INT xMax );
virtual GpStatus EndRaster(); virtual GpStatus End();
// Default version to output 1 rect at a time
virtual GpStatus OutputYSpan( INT yMin, INT yMax, INT * xCoords, // even number of X coordinates
INT numXCoords // must be a multiple of 2
); }; #else
// Builds up and outputs Y Span rects from single span inputs
class GpYSpanBuilder : public DpOutputSpan // input
{ private: // We now use an ObjectTag to determine if the object is valid
// instead of using a BOOL. This is much more robust and helps
// with debugging. It also enables us to version our objects
// more easily with a version number in the ObjectTag.
ObjectTag Tag; // Keep this as the 1st value in the object!
protected: VOID SetValid(BOOL valid) { Tag = valid ? ObjectTagGpYSpanBuilder : ObjectTagInvalid; }
protected: DynIntArray XCoords; // x coords of current raster so far
INT Y; // y value of current raster
GpOutputYSpan * Output;
public: GpYSpanBuilder(GpOutputYSpan * output); virtual ~GpYSpanBuilder() { SetValid(FALSE); // so we don't use a deleted object
}
virtual BOOL IsValid() const { ASSERT((Tag == ObjectTagGpYSpanBuilder) || (Tag == ObjectTagInvalid)); #if DBG
if (Tag == ObjectTagInvalid) { WARNING1("Invalid GpYSpanBuilder"); } #endif
return (Tag == ObjectTagGpYSpanBuilder); }
// This method is the input of spans to this class
virtual GpStatus OutputSpan( INT y, INT xMin, INT xMax );
virtual GpStatus EndRaster(); }; #endif
class DpPath; class DpClipRegion; struct DpPen; class RasterizeVector;
GpStatus ConvexRasterizer( INT yMin, // min y of all vectors
INT yMax, // max y of all vectors
INT numVectors, // num vectors in VectorList
RasterizeVector * vectorList, // list of all vectors of path
INT * sortedVectorIndices, // sorted list of vector indices
GpYDda * dda1, GpYDda * dda2, DpOutputSpan * output, const GpRect * clipBounds );
GpStatus NonConvexRasterizer( INT yMin, // min y of all vectors
INT yMax, // max y of all vectors
INT numVectors, // num vectors in VectorList
RasterizeVector * vectorList, // list of all vectors of path
INT * sortedVectorIndices, // sorted list of vector indices
GpYDda * left, GpYDda * right, DpOutputSpan * output, const GpRect * clipBounds, BOOL useAlternate );
GpStatus Rasterizer( const DpPath * path, const GpMatrix * matrix, GpFillMode fillMode, DpOutputSpan * output, REAL dpiX = 0, REAL dpiY = 0, const GpRect * clipBounds = NULL, GpYDda * yDda = NULL, DpEnumerationType type = Flattened, const DpPen * pen = NULL );
GpStatus Rasterize( const DpPath * path, GpMatrix * matrix, GpFillMode fillMode, DpOutputSpan * output, DpClipRegion * clipRegion, const GpRect * drawBounds, REAL dpiX, REAL dpiY, GpYDda * yDda = NULL, DpEnumerationType type = Flattened, const DpPen * pen = NULL );
#endif // _RASTERIZER_HPP
|