704 lines
22 KiB
C
704 lines
22 KiB
C
/******************************Module*Header*******************************\
|
|
* Module Name: Stroke.c
|
|
*
|
|
* DrvStrokePath for VGA driver
|
|
*
|
|
* Copyright (c) 1992-1995 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "driver.h"
|
|
|
|
#include "lines.h"
|
|
|
|
// External calls
|
|
|
|
VOID vSetStrips(ULONG, ULONG);
|
|
VOID vClearStrips(ULONG);
|
|
|
|
#define MIN(A,B) ((A) < (B) ? (A) : (B))
|
|
|
|
// Prototypes to go to the screen:
|
|
|
|
VOID vStripSolidHorizontal(STRIP*, LINESTATE*, LONG*);
|
|
VOID vStripSolidHorizontalSet(STRIP*, LINESTATE*, LONG*);
|
|
VOID vStripSolidVertical(STRIP*, LINESTATE*, LONG*);
|
|
VOID vStripSolidDiagonalHorizontal(STRIP*, LINESTATE*, LONG*);
|
|
VOID vStripSolidDiagonalVertical(STRIP*, LINESTATE*, LONG*);
|
|
|
|
VOID vStripStyledHorizontal(STRIP*, LINESTATE*, LONG*);
|
|
VOID vStripStyledVertical(STRIP*, LINESTATE*, LONG*);
|
|
|
|
VOID vStripMaskedHorizontal(STRIP*, LINESTATE*, LONG*);
|
|
VOID vStripMaskedVertical(STRIP*, LINESTATE*, LONG*);
|
|
|
|
PFNSTRIP gapfnStripSolidSet[] = {
|
|
|
|
// Special strip drawers for solid lines with SET style ROPs:
|
|
|
|
vStripSolidHorizontalSet,
|
|
vStripSolidVertical,
|
|
vStripSolidDiagonalHorizontal,
|
|
vStripSolidDiagonalVertical
|
|
};
|
|
|
|
PFNSTRIP gapfnStrip[] = {
|
|
|
|
// The order of these first 3 sets of strip drawers is determined by
|
|
// the FL_STYLE_MASK bits of the line flags:
|
|
|
|
vStripSolidHorizontal,
|
|
vStripSolidVertical,
|
|
vStripSolidDiagonalHorizontal,
|
|
vStripSolidDiagonalVertical,
|
|
|
|
vStripStyledHorizontal,
|
|
vStripStyledVertical,
|
|
NULL, // Diagonal goes here
|
|
NULL, // Diagonal goes here
|
|
|
|
vStripMaskedHorizontal,
|
|
vStripMaskedVertical,
|
|
NULL, // Diagonal goes here
|
|
NULL, // Diagonal goes here
|
|
};
|
|
|
|
|
|
STYLEPOS gaspAlternateStyle[] = { 1 };
|
|
|
|
|
|
// Prototypes to go to a device-format bitmap:
|
|
|
|
VOID vBitmapSolidHorizontal(STRIP*, LINESTATE*, LONG*);
|
|
VOID vBitmapSolidVertical(STRIP*, LINESTATE*, LONG*);
|
|
VOID vBitmapSolidDiagonal(STRIP*, LINESTATE*, LONG*);
|
|
|
|
VOID vBitmapStyledHorizontal(STRIP*, LINESTATE*, LONG*);
|
|
VOID vBitmapStyledVertical(STRIP*, LINESTATE*, LONG*);
|
|
|
|
VOID vCatchDFB(STRIP*, LINESTATE*, LONG*);
|
|
|
|
PFNSTRIP gapfnCatchDFB[] = {
|
|
vCatchDFB,
|
|
vCatchDFB,
|
|
vCatchDFB,
|
|
vCatchDFB
|
|
};
|
|
|
|
PFNSTRIP gapfnDFB[] = {
|
|
vBitmapSolidHorizontal,
|
|
vBitmapSolidVertical,
|
|
vBitmapSolidDiagonal,
|
|
vBitmapSolidDiagonal,
|
|
|
|
vBitmapStyledHorizontal,
|
|
vBitmapStyledVertical,
|
|
NULL, // Diagonal goes here
|
|
NULL // Diagonal goes here
|
|
};
|
|
|
|
// For two-pass ROPs:
|
|
|
|
VOID vCatchTwoPass(STRIP*, LINESTATE*, LONG*);
|
|
|
|
PFNSTRIP gapfnCatchTwoPass[] = {
|
|
vCatchTwoPass,
|
|
vCatchTwoPass,
|
|
vCatchTwoPass,
|
|
vCatchTwoPass
|
|
};
|
|
|
|
// VGA ulVgaMode constants:
|
|
|
|
#define DR_SET 0x00
|
|
#define DR_AND 0x08
|
|
#define DR_OR 0x10
|
|
#define DR_XOR 0x18
|
|
|
|
// Bit flag set if two passes needed:
|
|
|
|
#define DR_2PASS 0x80
|
|
|
|
// Table to convert ROP to usable information:
|
|
|
|
static struct {
|
|
ULONG ulColorAnd;
|
|
ULONG ulColorXor;
|
|
ULONG ulVgaMode;
|
|
} arop[] = {
|
|
{0x00, 0xff, DR_SET}, // 1 R2_WHITE
|
|
{0x00, 0x00, DR_SET}, // 0 R2_BLACK
|
|
{0xff, 0xff, DR_AND|DR_2PASS}, // DPon R2_NOTMERGEPEN Dest invert + DPna
|
|
{0xff, 0xff, DR_AND}, // DPna R2_MASKNOTPEN
|
|
{0xff, 0xff, DR_SET}, // PN R2_NOTCOPYPEN
|
|
{0xff, 0x00, DR_AND|DR_2PASS}, // PDna R2_MASKPENNOT Dest invert + DPa
|
|
{0x00, 0xff, DR_XOR}, // Dn R2_NOT Invert dest without pen
|
|
{0xff, 0x00, DR_XOR}, // DPx R2_XORPEN
|
|
{0xff, 0xff, DR_OR|DR_2PASS}, // DPan R2_NOTMASKPEN Dest invert + DPno
|
|
{0xff, 0x00, DR_AND}, // DPa R2_MASKPEN
|
|
{0xff, 0xff, DR_XOR}, // DPxn R2_NOTXORPEN DPxn == DPnx
|
|
{0x00, 0x00, DR_OR}, // D R2_NOP Silliness!
|
|
{0xff, 0xff, DR_OR}, // DPno R2_MERGENOTPEN
|
|
{0xff, 0x00, DR_SET}, // P R2_COPYPEN
|
|
{0xff, 0x00, DR_OR|DR_2PASS}, // PDno R2_MERGEPENNOT Dest invert + DPo
|
|
{0xff, 0x00, DR_OR}, // DPo R2_MERGEPEN
|
|
};
|
|
|
|
// The gaulAndXorTable contains and-masks and xor-masks for setting
|
|
// pels to one of four possible values. The and-masks have been
|
|
// inverted, and are stored in the low byte of each word. The
|
|
// xor-masks are stored in the high bytes.
|
|
//
|
|
// ROP XOR ~AND
|
|
// -------------------
|
|
// DDx 00 FF Set to zero
|
|
// Dn FF 00 Not destination
|
|
// D 00 00 Leave alone
|
|
// DDxn FF FF Set to one
|
|
|
|
ULONG gaulAndXorTable[] = {
|
|
0x00ff, // Set to zero
|
|
0xff00, // Not destination
|
|
0x0000, // Leave alone
|
|
0xffff // Set to one
|
|
};
|
|
|
|
ULONG gaulInitMasksLtoR[] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f };
|
|
ULONG gaulInitMasksRtoL[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL DrvStrokePath(pso, ppo, pco, pxo, pbo, pptlBrushOrg, pla, mix)
|
|
*
|
|
* Strokes the path.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL DrvStrokePath(
|
|
SURFOBJ* pso,
|
|
PATHOBJ* ppo,
|
|
CLIPOBJ* pco,
|
|
XFORMOBJ* pxo,
|
|
BRUSHOBJ* pbo,
|
|
POINTL* pptlBrushOrg,
|
|
LINEATTRS* pla,
|
|
MIX mix)
|
|
{
|
|
STYLEPOS aspLtoR[STYLE_MAX_COUNT];
|
|
STYLEPOS aspRtoL[STYLE_MAX_COUNT];
|
|
LINESTATE ls;
|
|
PFNSTRIP* apfn;
|
|
FLONG fl;
|
|
PDEVSURF pdsurf;
|
|
ULONG ulVgaMode;
|
|
|
|
UNREFERENCED_PARAMETER(pxo);
|
|
UNREFERENCED_PARAMETER(pptlBrushOrg);
|
|
|
|
// Get the device ready:
|
|
|
|
pdsurf = (PDEVSURF) pso->dhsurf;
|
|
|
|
fl = 0;
|
|
|
|
// Look after styling initialization:
|
|
|
|
if (pla->fl & LA_ALTERNATE)
|
|
{
|
|
ASSERT(pla->pstyle == (FLOAT_LONG*) NULL && pla->cstyle == 0,
|
|
"DrvStrokePath: Non-empty style array for PS_ALTERNATE");
|
|
|
|
ls.spNext = HIWORD(pla->elStyleState.l) & 1;
|
|
// Light first pixel if
|
|
// a multiple of 2
|
|
|
|
ls.spTotal = 1; // Sum of style array
|
|
ls.spTotal2 = 2; // Twice the sum
|
|
ls.xyDensity = 1; // Each 'dot' is one
|
|
// pixel long
|
|
|
|
if (pdsurf->iFormat == BMF_DFB)
|
|
{
|
|
fl |= (FL_ARBITRARYSTYLED);
|
|
|
|
ls.cStyle = 1; // Size of style array
|
|
ls.aspRtoL = &gaspAlternateStyle[0]; // Right-to-left array
|
|
ls.aspLtoR = &gaspAlternateStyle[0]; // Left-to-right array
|
|
ls.ulStartMask = 0; // First pel is a dash
|
|
}
|
|
else
|
|
{
|
|
fl |= (FL_ALTERNATESTYLED | FL_MASKSTYLED);
|
|
}
|
|
}
|
|
else if (pla->pstyle != (FLOAT_LONG*) NULL)
|
|
{
|
|
PFLOAT_LONG pstyle;
|
|
|
|
pstyle = &pla->pstyle[pla->cstyle];
|
|
|
|
ls.xyDensity = STYLE_DENSITY;
|
|
ls.spTotal = 0;
|
|
while (pstyle-- > pla->pstyle)
|
|
{
|
|
ls.spTotal += pstyle->l;
|
|
}
|
|
ls.spTotal *= STYLE_DENSITY;
|
|
ls.spTotal2 = 2 * ls.spTotal;
|
|
|
|
// Compute starting style position (this is guaranteed not to overflow):
|
|
|
|
ls.spNext = HIWORD(pla->elStyleState.l) * STYLE_DENSITY +
|
|
LOWORD(pla->elStyleState.l);
|
|
|
|
// We optimize the style arrays that are even length and sum to 8. We
|
|
// also don't have any masked strip drawers for DFBs:
|
|
|
|
if (ls.spTotal == (8 * STYLE_DENSITY) &&
|
|
(pla->cstyle & 1) == 0 &&
|
|
pdsurf->iFormat != BMF_DFB)
|
|
{
|
|
// Do "masked" styles.
|
|
// -------------------
|
|
//
|
|
// This case is merely an optimization; you can remove it and
|
|
// all style lines will still work. It just so happens that the
|
|
// default styles (such as PS_DOT, PS_DASHDOT, etc.) will all
|
|
// sum to 8, and there are some optimizations we can do on the
|
|
// VGA for that case.
|
|
//
|
|
// We make an 8 bit mask that represents each style unit in the
|
|
// style array, and we pass this to the "Masked" strip drawers
|
|
// (instead of calling the "Styled" strip drawers which still
|
|
// handle the arbitrary styles).
|
|
|
|
LONG ii;
|
|
|
|
ls.ulStyleMaskLtoR = 0;
|
|
ls.ulStyleMaskRtoL = 0;
|
|
|
|
for (pstyle = pla->pstyle, ii = 8; ii > 0;)
|
|
{
|
|
LONG l1 = (pstyle++)->l;
|
|
LONG l2 = (pstyle++)->l;
|
|
|
|
ls.ulStyleMaskRtoL >>= l1 + l2;
|
|
ls.ulStyleMaskRtoL |= gaulInitMasksRtoL[l2];
|
|
|
|
ls.ulStyleMaskLtoR <<= l1 + l2;
|
|
ls.ulStyleMaskLtoR |= gaulInitMasksLtoR[l2];
|
|
|
|
ii -= (l1 + l2);
|
|
}
|
|
|
|
// Replicate byte and initialize to style position zero:
|
|
|
|
ls.ulStyleMaskLtoR |= (ls.ulStyleMaskLtoR << 8);
|
|
ls.ulStyleMaskLtoR |= (ls.ulStyleMaskLtoR << 16);
|
|
|
|
ls.ulStyleMaskRtoL |= (ls.ulStyleMaskRtoL << 8);
|
|
ls.ulStyleMaskRtoL |= (ls.ulStyleMaskRtoL << 16);
|
|
|
|
// Check if we should start with a gap or start with a dash:
|
|
|
|
if (pla->fl & LA_STARTGAP)
|
|
{
|
|
ls.ulStyleMaskLtoR = ~ls.ulStyleMaskLtoR;
|
|
ls.ulStyleMaskRtoL = ~ls.ulStyleMaskRtoL;
|
|
}
|
|
|
|
// Initialize some other state:
|
|
|
|
fl |= FL_MASKSTYLED;
|
|
}
|
|
else
|
|
|
|
// Okay, we've got to do it the slow way:
|
|
|
|
{
|
|
// Handle Arbitrary Styles
|
|
// -----------------------
|
|
//
|
|
// Because arbitrary styles are new to Win32, many apps won't
|
|
// know about them and will use the default styles (which will
|
|
// be handled by the "Masked" optimization case above), and so
|
|
// this code path won't get exercised too often. (See GDI's
|
|
// ExtCreatePen API.)
|
|
//
|
|
// But you still have to handle them, and do them right!
|
|
|
|
FLOAT_LONG* pstyle;
|
|
STYLEPOS* pspDown;
|
|
STYLEPOS* pspUp;
|
|
|
|
fl |= FL_ARBITRARYSTYLED;
|
|
ls.cStyle = pla->cstyle;
|
|
ls.aspRtoL = aspRtoL;
|
|
ls.aspLtoR = aspLtoR;
|
|
|
|
if (pla->fl & LA_STARTGAP)
|
|
ls.ulStartMask = 0xffffffffL;
|
|
else
|
|
ls.ulStartMask = 0L;
|
|
|
|
pstyle = pla->pstyle;
|
|
pspDown = &ls.aspRtoL[ls.cStyle - 1];
|
|
pspUp = &ls.aspLtoR[0];
|
|
|
|
// We always draw strips left-to-right, but styles have to be laid
|
|
// down in the direction of the original line. This means that in
|
|
// the strip code we have to traverse the style array in the
|
|
// opposite direction;
|
|
|
|
while (pspDown >= &ls.aspRtoL[0])
|
|
{
|
|
*pspDown = pstyle->l * STYLE_DENSITY;
|
|
*pspUp = *pspDown;
|
|
|
|
pspUp++;
|
|
pspDown--;
|
|
pstyle++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pdsurf->iFormat == BMF_DFB)
|
|
{
|
|
ULONG iStripIndex;
|
|
|
|
// Handle device-format bitmaps.
|
|
|
|
// The table we give to the line routine will have all entries pointing
|
|
// to the vCatchDFB function; it will intercept the strip draw call and
|
|
// in turn break it into 4 calls to the appropriate DFB strip drawing
|
|
// routines, once for each plane.
|
|
|
|
apfn = gapfnCatchDFB;
|
|
|
|
ls.ulDrawModeIndex = mix - 1;
|
|
ls.lNextPlane = pdsurf->lNextPlane;
|
|
ls.iColor = pbo->iSolidColor;
|
|
|
|
iStripIndex = 4 * ((fl & FL_ARBITRARYSTYLED) >> FL_STYLE_SHIFT);
|
|
ls.apfnStrip = &gapfnDFB[iStripIndex];
|
|
|
|
}
|
|
else
|
|
{
|
|
ULONG iColor;
|
|
ULONG iStripIndex;
|
|
|
|
fl |= FL_PHYSICAL_DEVICE;
|
|
|
|
// Compute the pointer to the correct strip drawing table. We
|
|
// have a special table for solid lines done with VGA mode == SET:
|
|
|
|
iStripIndex = 4 * ((fl & FL_STYLE_MASK) >> FL_STYLE_SHIFT);
|
|
apfn = &gapfnStrip[iStripIndex];
|
|
|
|
mix &= 0xf;
|
|
ulVgaMode = arop[mix].ulVgaMode;
|
|
|
|
if (ulVgaMode == DR_SET && iStripIndex == 0)
|
|
apfn = &gapfnStripSolidSet[0];
|
|
|
|
// Compute the correct color, based on the ROP we're doing:
|
|
|
|
iColor = (pbo->iSolidColor & arop[mix].ulColorAnd)
|
|
^ (arop[mix].ulColorXor);
|
|
|
|
if (!(ulVgaMode & DR_2PASS))
|
|
vSetStrips(iColor, ulVgaMode);
|
|
else
|
|
{
|
|
// If the ROP requires 2 passes, we sneakily change our strip
|
|
// table pointer to point to only our own routine, and it
|
|
// handles calling the appropriate strip routines twice:
|
|
|
|
ls.ulVgaMode = ulVgaMode ^ DR_2PASS;
|
|
ls.iColor = iColor;
|
|
ls.apfnStrip = apfn;
|
|
apfn = gapfnCatchTwoPass;
|
|
}
|
|
}
|
|
|
|
// Set up to enumerate the path:
|
|
|
|
if (pco->iDComplexity != DC_COMPLEX)
|
|
{
|
|
RECTL arclClip[4]; // For rectangular clipping
|
|
PATHDATA pd;
|
|
RECTL* prclClip = (RECTL*) NULL;
|
|
BOOL bMore;
|
|
ULONG cptfx;
|
|
POINTFIX ptfxStartFigure;
|
|
POINTFIX ptfxLast;
|
|
POINTFIX* pptfxFirst;
|
|
POINTFIX* pptfxBuf;
|
|
|
|
if (pco->iDComplexity == DC_RECT)
|
|
{
|
|
fl |= FL_SIMPLE_CLIP;
|
|
|
|
arclClip[0] = pco->rclBounds;
|
|
|
|
// FL_FLIP_D:
|
|
|
|
arclClip[1].top = pco->rclBounds.left;
|
|
arclClip[1].left = pco->rclBounds.top;
|
|
arclClip[1].bottom = pco->rclBounds.right;
|
|
arclClip[1].right = pco->rclBounds.bottom;
|
|
|
|
// FL_FLIP_V:
|
|
|
|
arclClip[2].top = -pco->rclBounds.bottom + 1;
|
|
arclClip[2].left = pco->rclBounds.left;
|
|
arclClip[2].bottom = -pco->rclBounds.top + 1;
|
|
arclClip[2].right = pco->rclBounds.right;
|
|
|
|
// FL_FLIP_V | FL_FLIP_D:
|
|
|
|
arclClip[3].top = pco->rclBounds.left;
|
|
arclClip[3].left = -pco->rclBounds.bottom + 1;
|
|
arclClip[3].bottom = pco->rclBounds.right;
|
|
arclClip[3].right = -pco->rclBounds.top + 1;
|
|
|
|
prclClip = arclClip;
|
|
}
|
|
|
|
PATHOBJ_vEnumStart(ppo);
|
|
|
|
do {
|
|
bMore = PATHOBJ_bEnum(ppo, &pd);
|
|
|
|
cptfx = pd.count;
|
|
if (cptfx == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (pd.flags & PD_BEGINSUBPATH)
|
|
{
|
|
ptfxStartFigure = *pd.pptfx;
|
|
pptfxFirst = pd.pptfx;
|
|
pptfxBuf = pd.pptfx + 1;
|
|
cptfx--;
|
|
}
|
|
else
|
|
{
|
|
pptfxFirst = &ptfxLast;
|
|
pptfxBuf = pd.pptfx;
|
|
}
|
|
|
|
if (pd.flags & PD_RESETSTYLE)
|
|
ls.spNext = 0;
|
|
|
|
// We have to check for cptfx == 0 because the only point in the
|
|
// subpath may have been the StartFigure point:
|
|
|
|
if (cptfx > 0)
|
|
{
|
|
if (!bLines(pdsurf,
|
|
pptfxFirst,
|
|
pptfxBuf,
|
|
(RUN*) NULL,
|
|
cptfx,
|
|
&ls,
|
|
prclClip,
|
|
apfn,
|
|
fl))
|
|
return(FALSE);
|
|
}
|
|
|
|
ptfxLast = pd.pptfx[pd.count - 1];
|
|
|
|
if (pd.flags & PD_CLOSEFIGURE)
|
|
{
|
|
if (!bLines(pdsurf,
|
|
&ptfxLast,
|
|
&ptfxStartFigure,
|
|
(RUN*) NULL,
|
|
1,
|
|
&ls,
|
|
prclClip,
|
|
apfn,
|
|
fl))
|
|
return(FALSE);
|
|
}
|
|
} while (bMore);
|
|
|
|
if (fl & FL_STYLED)
|
|
{
|
|
// Save the style state:
|
|
|
|
ULONG ulHigh;
|
|
ULONG ulLow;
|
|
|
|
// !!! The engine handles unnormalized style states. This can
|
|
// !!! be removed. Might have to remove some asserts in the
|
|
// !!! engine.
|
|
|
|
// Masked styles don't normalize the style state. It's a good
|
|
// thing to do, so let's do it now:
|
|
|
|
if ((ULONG) ls.spNext >= (ULONG) ls.spTotal2)
|
|
ls.spNext = (ULONG) ls.spNext % (ULONG) ls.spTotal2;
|
|
|
|
ulHigh = ls.spNext / ls.xyDensity;
|
|
ulLow = ls.spNext % ls.xyDensity;
|
|
|
|
pla->elStyleState.l = MAKELONG(ulLow, ulHigh);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Local state for path enumeration:
|
|
|
|
BOOL bMore;
|
|
union {
|
|
BYTE aj[offsetof(CLIPLINE, arun) + RUN_MAX * sizeof(RUN)];
|
|
CLIPLINE cl;
|
|
} cl;
|
|
|
|
fl |= FL_COMPLEX_CLIP;
|
|
|
|
// We use the clip object when non-simple clipping is involved:
|
|
|
|
PATHOBJ_vEnumStartClipLines(ppo, pco, pso, pla);
|
|
|
|
do {
|
|
bMore = PATHOBJ_bEnumClipLines(ppo, sizeof(cl), &cl.cl);
|
|
if (cl.cl.c != 0)
|
|
{
|
|
if (fl & FL_STYLED)
|
|
{
|
|
ls.spComplex = HIWORD(cl.cl.lStyleState) * ls.xyDensity
|
|
+ LOWORD(cl.cl.lStyleState);
|
|
}
|
|
if (!bLines(pdsurf,
|
|
&cl.cl.ptfxA,
|
|
&cl.cl.ptfxB,
|
|
&cl.cl.arun[0],
|
|
cl.cl.c,
|
|
&ls,
|
|
(RECTL*) NULL,
|
|
apfn,
|
|
fl))
|
|
return(FALSE);
|
|
}
|
|
} while (bMore);
|
|
}
|
|
|
|
if (fl & FL_PHYSICAL_DEVICE)
|
|
vClearStrips(ulVgaMode);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vCatchTwoPass(pstrip, pls, plStripEnd)
|
|
*
|
|
* Handles ROPs that cannot be done in a single pass using the VGA
|
|
* hardware. In order not to have a check in our main drawing loop for
|
|
* two-pass ROPs, we change the strip function table so that this function
|
|
* intercepts the call to draw the strips.
|
|
*
|
|
* This routine then figures out the appropriate actual strip drawer, and
|
|
* makes two calls to it: first to invert the destination, then to do the
|
|
* rest of the ROP.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vCatchTwoPass(STRIP* pstrip, LINESTATE* pls, LONG* plStripEnd)
|
|
{
|
|
BYTE* pjScreen = pstrip->pjScreen;
|
|
BYTE jBitMask = pstrip->jBitMask;
|
|
BYTE jStyleMask = pstrip->jStyleMask;
|
|
STYLEPOS* psp = pstrip->psp;
|
|
STYLEPOS spRemaining = pstrip->spRemaining;
|
|
|
|
// Figure out the actual strip routine we're supposed to call:
|
|
|
|
PFNSTRIP pfn = pls->apfnStrip[(pstrip->flFlips & FL_STRIP_MASK) >>
|
|
FL_STRIP_SHIFT];
|
|
|
|
// On the first pass, we invert the destination:
|
|
|
|
vSetStrips(0xff, DR_XOR);
|
|
|
|
(*pfn)(pstrip, pls, plStripEnd);
|
|
|
|
// We reset our strip variables for the second pass and handle the rest
|
|
// of the ROP:
|
|
|
|
pstrip->pjScreen = pjScreen;
|
|
pstrip->jBitMask = jBitMask;
|
|
pstrip->jStyleMask = jStyleMask;
|
|
pstrip->psp = psp;
|
|
pstrip->spRemaining = spRemaining;
|
|
|
|
vSetStrips(pls->iColor, pls->ulVgaMode);
|
|
|
|
(*pfn)(pstrip, pls, plStripEnd);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vCatchDFB(pstrip, pls, plStripEnd)
|
|
*
|
|
* Intercepts the strip draw call and in turn breaks it into 4 calls
|
|
* to the appropriate DFB strip drawing routines, once for each plane.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vCatchDFB(STRIP* pstrip, LINESTATE* pls, LONG* plStripEnd)
|
|
{
|
|
BYTE* pjScreen = pstrip->pjScreen;
|
|
BYTE jBitMask = pstrip->jBitMask;
|
|
BYTE jStyleMask = pstrip->jStyleMask;
|
|
STYLEPOS* psp = pstrip->psp;
|
|
STYLEPOS spRemaining = pstrip->spRemaining;
|
|
|
|
BYTE* pjScreenNextPass;
|
|
LONG lNextPlane = pls->lNextPlane;
|
|
ULONG ulPen0 = gaulAndXorTable[
|
|
(pls->ulDrawModeIndex) & 3];
|
|
ULONG ulPen1 = gaulAndXorTable[
|
|
(pls->ulDrawModeIndex >> 2) & 3];
|
|
|
|
// Figure out the actual strip routine we're supposed to call:
|
|
|
|
PFNSTRIP pfn = pls->apfnStrip[(pstrip->flFlips & FL_STRIP_MASK) >>
|
|
FL_STRIP_SHIFT];
|
|
|
|
pstrip->ulBitmapROP = (pls->iColor & 1) ? ulPen1 : ulPen0;
|
|
(*pfn)(pstrip, pls, plStripEnd); // Plane 0
|
|
pjScreenNextPass = pstrip->pjScreen;
|
|
|
|
pstrip->ulBitmapROP = (pls->iColor & 2) ? ulPen1 : ulPen0;
|
|
pjScreen += lNextPlane;
|
|
pstrip->pjScreen = pjScreen;
|
|
pstrip->jBitMask = jBitMask;
|
|
pstrip->jStyleMask = jStyleMask;
|
|
pstrip->psp = psp;
|
|
pstrip->spRemaining = spRemaining;
|
|
(*pfn)(pstrip, pls, plStripEnd); // Plane 1
|
|
|
|
pstrip->ulBitmapROP = (pls->iColor & 4) ? ulPen1 : ulPen0;
|
|
pjScreen += lNextPlane;
|
|
pstrip->pjScreen = pjScreen;
|
|
pstrip->jBitMask = jBitMask;
|
|
pstrip->jStyleMask = jStyleMask;
|
|
pstrip->psp = psp;
|
|
pstrip->spRemaining = spRemaining;
|
|
(*pfn)(pstrip, pls, plStripEnd); // Plane 2
|
|
|
|
pstrip->ulBitmapROP = (pls->iColor & 8) ? ulPen1 : ulPen0;
|
|
pjScreen += lNextPlane;
|
|
pstrip->pjScreen = pjScreen;
|
|
pstrip->jBitMask = jBitMask;
|
|
pstrip->jStyleMask = jStyleMask;
|
|
pstrip->psp = psp;
|
|
pstrip->spRemaining = spRemaining;
|
|
(*pfn)(pstrip, pls, plStripEnd); // Plane 3
|
|
|
|
pstrip->pjScreen = pjScreenNextPass;
|
|
}
|