📄 path.c
字号:
//
// Permedia3 Sample Display Driver
// path.c
//
// Copyright (c) 2000 Microsoft Corporation. All rights reserved.
//
// This file contains the GDI entry points for drawing paths, or filled shapes
// given as a set of edges.
#include "pch.h" // Precompiled header support.
#include "debug.h"
#include "struct.h"
#include "proto.h"
// This is a dumb little helper macro.
#define Swap(a,b) \
{ \
(a) = (a) ^ (b); \
(b) = (a) ^ (b); \
(a) = (a) ^ (b); \
}
// This is the amount we grow the edge arrays when we run out of space.
#define EDGE_ARRAY_GROW 20
// These structures are private to this module, and used for filled path
// rasterization.
typedef struct t_PERM3_EDGE {
// This is the smaller of the y values of the edge end points.
LONG TopY;
// Pointer to the next edge, as sorted by TopY values.
struct t_PERM3_EDGE * NextTop;
// This is the larger of the y values of the edge end points.
LONG BottomY;
// Pointer to the next edge, as sorted by BottomY values.
struct t_PERM3_EDGE * NextBottom;
// X coordinate of the edges intersection with the current scanline.
LONG X;
// Pointer to the next edge, sorted by x, which intersect the current line.
struct t_PERM3_EDGE * NextActive;
// 1 if yEnd > yStart, -1 otherwise.
LONG Direction;
// X coordinate coresponding to TopY.
LONG TopX;
// For each increment in y, how many whole pixels do we move in x?
LONG XIntegralAdvance;
// For each increment in y, how many fractional (1 / Height) pixels do we
// move in x?
LONG XFractionalAdvance;
// The sum of all the frqctional advances we have done so far which have
// not yet added up to one integral advance. Or think of it as the
// fraction you need to add to X to get the current real (non-integral)
// x-coordinate.
LONG FractionalTotal;
LONG FractionalTotalStart;
// The height of the edge (BottomY - TopY)
LONG Height;
} PERM3_EDGE;
typedef struct t_PERM3_EDGE_LIST {
PERM3_EDGE * Array;
PERM3_EDGE * FirstTop;
PERM3_EDGE * FirstBottom;
PERM3_EDGE * FirstActive;
LONG Size;
LONG Count;
LONG MinY;
LONG MaxY;
} PERM3_EDGE_LIST;
// Internal prototypes. These functions are not exposed outside this module.
static ULONG
MixToRop(
MIX Mix
);
static void
InitializeEdgeList(
PERM3_EDGE_LIST * EdgeList,
ULONG NumEdges
);
static BOOL
AddEdge(
PERM3_EDGE_LIST * EdgeList,
FIX x1,
FIX y1,
FIX x2,
FIX y2
);
static BOOL
FillEdge(
PERM3_EDGE_LIST * EdgeList,
PERM3_BLT_PARAM * Parameters
);
static void
DestroyEdgeList(
PERM3_EDGE_LIST * EdgeList
);
BOOL DrvFillPath(
SURFOBJ * DestSurface,
PATHOBJ * Path,
CLIPOBJ * Clipper,
BRUSHOBJ * Brush,
POINTL * BrushOrigin,
MIX Mix,
FLONG Options
)
{
// DrvFillPath
// This function is called by GDI when it needs it draw a filled, closed
// path. It accomplishes this by building a list of edges from the points
// the GDI feeds us via path enumeration. It then scanconverts that edge
// list with blit operations.
// It might be possible to optimize this operation by triangulating the
// given points and feeding them to a triangle rasterizer.
// Local variables.
BOOL FnRetVal = FALSE;
PERM3_BLT_PARAM Parameters;
PERM3_SURFACE Dest;
RECT DestRect;
PERM3_SURFACE * BrushSurface;
RECT BrushRect;
POINT LocalBrushOrigin;
ENUMRECTS * ClipperRects = NULL;
ULONG SizeofClipperRects;
LONG More;
ULONG i;
PERM3_EDGE_LIST EdgeList;
PATHDATA PathData;
POINTFIX FirstPoint;
POINTFIX LastPoint;
// Check parameters.
// !TODO!
Enter(L"DrvFillPath");
memset(&Parameters, 0, sizeof(PERM3_BLT_PARAM));
// Fill in the blt parameters that we can reuse.
Parameters.Rop = MixToRop(Mix);
SurfobjToPerm3Surface(&Dest,
DestSurface,
NULL,
FALSE);
Parameters.Destination = (const SURFACE *)&Dest;
// Make sure we have a destination rectangle to fill out in FillEdge.
Parameters.DestRect = &DestRect;
// Using a surface as a brush to fill a path on itself is pedantically
// possible, but, we're not going to worry about it.
Parameters.ScanXPositive = TRUE;
Parameters.ScanYPositive = TRUE;
if (Brush) {
if (Brush->iSolidColor == 0xFFFFFFFF) {
Parameters.PatternType = BitmapPattern;
// Get the brush surface and transfer the appropriate details into
// the parameters structure.
if (Brush->pvRbrush == NULL) {
BrushSurface = (PERM3_SURFACE *)(BRUSHOBJ_pvGetRbrush(Brush));
// !TODO! Check return code?
}
else {
BrushSurface = (PERM3_SURFACE *)(Brush->pvRbrush);
}
Parameters.Brush = (const SURFACE *)BrushSurface;
BrushRect.left = 0;
BrushRect.top = 0;
BrushRect.right = Parameters.Brush->Size.cx;
BrushRect.bottom = Parameters.Brush->Size.cy;
Parameters.BrushRect = &BrushRect;
if (BrushOrigin) {
Parameters.BrushOrigin = (POINT *)BrushOrigin;
}
else {
LocalBrushOrigin.x = 0;
LocalBrushOrigin.y = 0;
Parameters.BrushOrigin = &LocalBrushOrigin;
}
}
else {
Parameters.PatternType = SolidPattern;
Parameters.FillValue = Brush->iSolidColor;
}
}
if (Clipper && Clipper->iDComplexity != DC_TRIVIAL) {
if (Clipper->iDComplexity == DC_RECT) {
Parameters.ClipRectCount = 1;
Parameters.ClipRect = (const RECT *)&(Clipper->rclBounds);
}
else if (Clipper->iDComplexity == DC_COMPLEX) {
// Extract all of the rectangles from GDI.
Parameters.ClipRectCount = CLIPOBJ_cEnumStart(Clipper,
TRUE,
CT_RECTANGLES,
CD_ANY,
0);
// The ENUMRECTS strcuture already contains space for 1 rectangle.
SizeofClipperRects = sizeof(ENUMRECTS) +
sizeof(RECT) * (Parameters.ClipRectCount - 1);
ClipperRects = SystemAlloc(SizeofClipperRects);
if (ClipperRects) {
CLIPOBJ_bEnum(Clipper,
SizeofClipperRects,
(ULONG *)ClipperRects);
Assert(ClipperRects->c == Parameters.ClipRectCount);
Parameters.ClipRect = (const RECT *)ClipperRects->arcl;
}
else {
Error(L"System memory allocation failure.\n");
}
}
else {
Error(L"Unknown clipping complexity.\n");
}
}
// Now, we extract the path information into a PERM3_EDGE_LIST structure
// that we can rasterize.
InitializeEdgeList(&EdgeList, Path->cCurves);
PATHOBJ_vEnumStart(Path);
do {
More = PATHOBJ_bEnum(Path, &PathData);
if (PathData.count == 0) break;
// Handle the first point.
if (PathData.flags & PD_BEGINSUBPATH) {
// This is the start of a new sub-path. We need only save the first
// point to close the path with.
FirstPoint = PathData.pptfx[0];
}
else {
// Continue the current subpath.
if (!AddEdge(&EdgeList,
LastPoint.x,
LastPoint.y,
PathData.pptfx[0].x,
PathData.pptfx[0].y)) {
More = 0;
}
}
// Add all of the points remaining in this PathData.
for (i = 0; i < PathData.count - 1; i++) {
if (!AddEdge(&EdgeList,
PathData.pptfx[i].x,
PathData.pptfx[i].y,
PathData.pptfx[i + 1].x,
PathData.pptfx[i + 1].y)) {
More = 0;
}
}
// Handle the last point. Either close the subpath, or save the last
// point to use with the next batch of data.
if (PathData.flags & PD_ENDSUBPATH) {
if (!AddEdge(&EdgeList,
PathData.pptfx[i].x,
PathData.pptfx[i].y,
FirstPoint.x,
FirstPoint.y)){
More = 0;
}
}
else {
LastPoint = PathData.pptfx[i];
}
} while (More != 0);
// Rasterize.
FnRetVal = FillEdge(&EdgeList, &Parameters);
// Cleanup.
DestroyEdgeList(&EdgeList);
if (ClipperRects) {
SystemFree(ClipperRects);
}
FreeSurfobjDerivedPerm3Surface(&Dest);
Exit(L"DrvFillPath");
return FnRetVal;
}
ULONG
MixToRop(
MIX Mix
)
{
// MixToRop
// This function converts a MIX value (a pair of ROP2's) into a ROP4
// appropriate for blitting. No Enter/Exit semantics for inlined functions.
// Local constants.
// This lookup is derived from the definition of the ROP2 and MIX
// raster operation definitions.
const BYTE MixLookup[] =
{
0xFF, // R2_WHITE - Allow rop = gaMix[mix & 0x0F]
0x00, // R2_BLACK
0x05, // R2_NOTMERGEPEN
0x0A, // R2_MASKNOTPEN
0x0F, // R2_NOTCOPYPEN
0x50, // R2_MASKPENNOT
0x55, // R2_NOT
0x5A, // R2_XORPEN
0x5F, // R2_NOTMASKPEN
0xA0, // R2_MASKPEN
0xA5, // R2_NOTXORPEN
0xAA, // R2_NOP
0xAF, // R2_MERGENOTPEN
0xF0, // R2_COPYPEN
0xF5, // R2_MERGEPENNOT
0xFA, // R2_MERGEPEN
0xFF // R2_WHITE - Allow rop = gaMix[mix & 0xFF]
};
// Check parameters.
// !TODO!
return (((ULONG)(MixLookup[(Mix >> 8) & 0x0f]) << 8) | MixLookup[Mix & 0x0f]);
}
void
InitializeEdgeList(
PERM3_EDGE_LIST * EdgeList,
ULONG NumEdges
)
{
// InitializeEdgeList
// This function will, given an PERM3_EDGE_LIST structure, and a number of
// edges, prepare that edge list for use (for AddEdge and FillEdge to be
// called on it.)
// Check parameters.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -