857 lines
28 KiB
C
857 lines
28 KiB
C
/******************************Module*Header**********************************\
|
||
*
|
||
* *******************
|
||
* * GDI SAMPLE CODE *
|
||
* *******************
|
||
*
|
||
* Module Name: patnfill.c
|
||
*
|
||
* Contains all the pattern fill routines
|
||
*
|
||
* Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
|
||
* Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
|
||
\*****************************************************************************/
|
||
#include "precomp.h"
|
||
#include "gdi.h"
|
||
#include "directx.h"
|
||
|
||
//-----------------------------Note--------------------------------------------
|
||
//
|
||
// A Note on brushes
|
||
//
|
||
// Out cached brushes are 64x64. Here is the reason. The minimum brush
|
||
// size that we can use as a pattern is 32.
|
||
//
|
||
// Now, we need to be able to offset the pattern when rendering in x and y
|
||
// by as much as 7 pixels in either direction. The P2
|
||
// hardware does not have a simple x/Y pattern offset mechanism. Instead
|
||
// we are forced to offset the origin by offsetting the base address of the
|
||
// pattern. This requires that we store in memory a pattern that is
|
||
// 39 pixels wide. However, the stride still needs to be acceptable to the
|
||
// texture address generation hardware. The next valid stride is 64.
|
||
//
|
||
// That's why we have 64x64 pattern brushes in our cache.
|
||
//
|
||
// Note also that we over do it when caching duplicating the brush to fill
|
||
// up the entire 64x64 even though we only use 39x39. We might change
|
||
// this in the near future.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
//-----------------------------------------------------------------------------
|
||
//
|
||
// VOID vMonoOffset(GFNPB* ppb)
|
||
//
|
||
// Update the offset to be used in the area stipple unit. We do this for a
|
||
// mono brush which is realized in the hardware but whose alignment has simply
|
||
// changed. This avoids a full scale realization.
|
||
//
|
||
// Argumentes needed from function block (GFNPB)
|
||
//
|
||
// ppdev-------PPDev
|
||
// prbrush-----Pointer to the RBrush structure
|
||
// pptlBrush---Pointer to pointer brush structure
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
VOID
|
||
vMonoOffset(GFNPB* ppb)
|
||
{
|
||
PPDev ppdev = ppb->ppdev;
|
||
|
||
DWORD dwMode;
|
||
POINTL* pptlBrush = ppb->pptlBrush;
|
||
RBrush* prb = ppb->prbrush;
|
||
|
||
PERMEDIA_DECL;
|
||
|
||
DBG_GDI((6, "vMonoOffset started"));
|
||
|
||
//
|
||
// Construct the AreaStippleMode value. It contains the pattern size,
|
||
// the offset for the brush origin and the enable bit. Remember the
|
||
// offset so we can later check if it changes and update the hardware.
|
||
// Remember the mode so we can do a mirrored stipple easily.
|
||
//
|
||
prb->ptlBrushOrg.x = pptlBrush->x;
|
||
prb->ptlBrushOrg.y = pptlBrush->y;
|
||
|
||
dwMode = __PERMEDIA_ENABLE
|
||
| AREA_STIPPLE_XSEL(__PERMEDIA_AREA_STIPPLE_32_PIXEL_PATTERN)
|
||
| AREA_STIPPLE_YSEL(__PERMEDIA_AREA_STIPPLE_8_PIXEL_PATTERN)
|
||
| AREA_STIPPLE_MIRROR_X
|
||
| AREA_STIPPLE_XOFF(8 - (prb->ptlBrushOrg.x & 7))
|
||
| AREA_STIPPLE_YOFF(8 - (prb->ptlBrushOrg.y & 7));
|
||
|
||
prb->areaStippleMode = dwMode;
|
||
|
||
DBG_GDI((7, "setting new area stipple offset to %d, %d",
|
||
8 - (prb->ptlBrushOrg.x & 7), 8 - (prb->ptlBrushOrg.y & 7)));
|
||
|
||
ULONG* pBuffer;
|
||
|
||
InputBufferReserve(ppdev, 2, &pBuffer);
|
||
|
||
pBuffer[0] = __Permedia2TagAreaStippleMode;
|
||
pBuffer[1] = dwMode;
|
||
|
||
pBuffer += 2;
|
||
|
||
InputBufferCommit(ppdev, pBuffer);
|
||
|
||
}// vMonoOffset()
|
||
|
||
//-----------------------------------------------------------------------------
|
||
//
|
||
// VOID vPatRealize(GFNPB* ppb)
|
||
//
|
||
// This routine transfers an 8x8 pattern to off-screen display memory, and
|
||
// duplicates it to make a 32x32 cached realization which is then used by
|
||
// vPatFill.
|
||
//
|
||
// Argumentes needed from function block (GFNPB)
|
||
//
|
||
// ppdev-------PPDev
|
||
// prbrush-----Pointer to the RBrush structure
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
VOID
|
||
vPatRealize(GFNPB* ppb)
|
||
{
|
||
PDev* ppdev = ppb->ppdev;
|
||
RBrush* prb = ppb->prbrush; // Points to brush realization structure
|
||
BrushEntry* pbe = prb->pbe;
|
||
|
||
BYTE* pcSrc;
|
||
LONG lNextCachedBrush;
|
||
LONG lTemp;
|
||
LONG lPelSize;
|
||
ULONG* pBuffer;
|
||
|
||
PERMEDIA_DECL;
|
||
|
||
// VALIDATE_GDI_CONTEXT;
|
||
|
||
DBG_GDI((6, "vPatRealize started"));
|
||
|
||
if ( (pbe == NULL) || (pbe->prbVerify != prb) )
|
||
{
|
||
//
|
||
// Mono brushes are realized into the area stipple unit. For this we
|
||
// have a set of special BRUSHENTRYs, one for each board.
|
||
//
|
||
if ( prb->fl & RBRUSH_2COLOR )
|
||
{
|
||
//
|
||
// 1 BPP patten
|
||
//
|
||
DBG_GDI((7, "loading mono brush into cache"));
|
||
pbe = &ppdev->abeMono;
|
||
pbe->prbVerify = prb;
|
||
prb->pbe = pbe;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// We have to allocate a new off-screen cache brush entry for
|
||
// the brush
|
||
//
|
||
lNextCachedBrush = ppdev->lNextCachedBrush; // Get the next index
|
||
pbe = &ppdev->abe[lNextCachedBrush]; // Get the brush entry
|
||
|
||
//
|
||
// Check if this index is out of the total brush stamps cached
|
||
// If yes, rotate to the 1st one
|
||
//
|
||
lNextCachedBrush++;
|
||
if ( lNextCachedBrush >= ppdev->cBrushCache )
|
||
{
|
||
lNextCachedBrush = 0;
|
||
}
|
||
|
||
//
|
||
// Reset the next brush to be allocated
|
||
//
|
||
ppdev->lNextCachedBrush = lNextCachedBrush;
|
||
|
||
//
|
||
// Update our links:
|
||
//
|
||
pbe->prbVerify = prb;
|
||
prb->pbe = pbe;
|
||
DBG_GDI((7, "new cache entry allocated for color brush"));
|
||
}// Get cached brush entry depends on its color depth
|
||
}// If the brush is not cached
|
||
|
||
//
|
||
// We're going to load mono patterns into the area stipple and set the
|
||
// start offset to the brush origin. WARNING: we assume that we are
|
||
// running little endian. I believe this is always true for NT.
|
||
//
|
||
if ( prb->fl & RBRUSH_2COLOR )
|
||
{
|
||
//
|
||
// 1 BPP patten
|
||
//
|
||
DWORD* pdwSrc = &prb->aulPattern[0];
|
||
|
||
//
|
||
// This function loads the stipple offset into the hardware. We also
|
||
// call this function on its own if the brush is realized but its
|
||
// offset changes. In that case we don't have to go through a complete
|
||
// realize again.
|
||
//
|
||
ppb->prbrush = prb;
|
||
|
||
(*ppdev->pgfnMonoOffset)(ppb);
|
||
|
||
DBG_GDI((7, "area stipple pattern:"));
|
||
|
||
InputBufferReserve(ppdev, 16, &pBuffer);
|
||
|
||
for ( lTemp = 0; lTemp < 8; ++lTemp, ++pdwSrc )
|
||
{
|
||
pBuffer[0] = __Permedia2TagAreaStipplePattern0 + lTemp;
|
||
pBuffer[1] = *pdwSrc;
|
||
pBuffer += 2;
|
||
}
|
||
|
||
InputBufferCommit(ppdev, pBuffer);
|
||
|
||
DBG_GDI((7, "area stipple downloaded. vPatRealize done"));
|
||
|
||
return;
|
||
}// 1 BPP case
|
||
|
||
lPelSize = ppdev->cPelSize;
|
||
pcSrc = (BYTE*)&prb->aulPattern[0]; // Copy from brush buffer
|
||
|
||
|
||
InputBufferReserve(ppdev, 12 + 65, &pBuffer);
|
||
|
||
pBuffer[0] = __Permedia2TagFBWindowBase;
|
||
pBuffer[1] = pbe->ulPixelOffset;
|
||
pBuffer[2] = __Permedia2TagFBReadMode;
|
||
pBuffer[3] = PM_FBREADMODE_PARTIAL(ppdev->ulBrushPackedPP);
|
||
pBuffer[4] = __Permedia2TagLogicalOpMode;
|
||
pBuffer[5] = __PERMEDIA_DISABLE;
|
||
|
||
pBuffer[6] = __Permedia2TagRectangleOrigin;
|
||
pBuffer[7] = 0;
|
||
pBuffer[8] = __Permedia2TagRectangleSize;
|
||
pBuffer[9] = (8 << 16) | 8;
|
||
pBuffer[10] = __Permedia2TagRender;
|
||
pBuffer[11] = __RENDER_RECTANGLE_PRIMITIVE
|
||
| __RENDER_SYNC_ON_HOST_DATA
|
||
| __RENDER_INCREASE_Y
|
||
| __RENDER_INCREASE_X;
|
||
|
||
pBuffer += 12;
|
||
|
||
*pBuffer++ = (63 << 16) | __Permedia2TagColor;
|
||
|
||
switch( lPelSize )
|
||
{
|
||
case 0:
|
||
for ( lTemp = 0; lTemp < 64; ++lTemp )
|
||
{
|
||
*pBuffer++ = pcSrc[lTemp];
|
||
}
|
||
break;
|
||
|
||
case 1:
|
||
for ( lTemp = 0; lTemp < 64; ++lTemp )
|
||
{
|
||
*pBuffer++ = ((USHORT *) pcSrc)[lTemp];
|
||
}
|
||
break;
|
||
|
||
case 2:
|
||
for ( lTemp = 0; lTemp < 64; ++lTemp )
|
||
{
|
||
*pBuffer++ = ((ULONG *) pcSrc)[lTemp];
|
||
}
|
||
break;
|
||
}
|
||
|
||
InputBufferCommit(ppdev, pBuffer);
|
||
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
// <20>0<EFBFBD>1<EFBFBD>2 <20> We now have an 8x8 colour-expanded copy of
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> the pattern sitting in off-screen memory,
|
||
// <20>5 <20> represented here by square '0'.
|
||
// <20> <20>
|
||
// <20> <20> We're now going to expand the pattern to
|
||
// <20> <20> 64x64 by repeatedly copying larger rectangles
|
||
// <20> <20> in the indicated order, and doing a 'rolling'
|
||
// <20> <20> blt to copy vertically.
|
||
// <20> <20>
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
|
||
InputBufferReserve(ppdev, 36, &pBuffer);
|
||
|
||
pBuffer[0] = __Permedia2TagFBReadMode;
|
||
pBuffer[1] = PM_FBREADMODE_PARTIAL(ppdev->ulBrushPackedPP)
|
||
| __FB_READ_SOURCE;
|
||
pBuffer[2] = __Permedia2TagStartXDom;
|
||
pBuffer[3] = INTtoFIXED(8);
|
||
pBuffer[4] = __Permedia2TagStartXSub;
|
||
pBuffer[5] = INTtoFIXED(16);
|
||
pBuffer[6] = __Permedia2TagFBSourceOffset;
|
||
pBuffer[7] = -8;
|
||
pBuffer[8] = __Permedia2TagRender;
|
||
pBuffer[9] = __RENDER_TRAPEZOID_PRIMITIVE;
|
||
|
||
pBuffer[10] = __Permedia2TagStartXDom;
|
||
pBuffer[11] = INTtoFIXED(16);
|
||
pBuffer[12] = __Permedia2TagStartXSub;
|
||
pBuffer[13] = INTtoFIXED(32);
|
||
pBuffer[14] = __Permedia2TagFBSourceOffset;
|
||
pBuffer[15] = -16;
|
||
pBuffer[16] = __Permedia2TagRender;
|
||
pBuffer[17] = __RENDER_TRAPEZOID_PRIMITIVE;
|
||
|
||
pBuffer[18] = __Permedia2TagStartXDom;
|
||
pBuffer[19] = INTtoFIXED(32);
|
||
pBuffer[20] = __Permedia2TagStartXSub;
|
||
pBuffer[21] = INTtoFIXED(64);
|
||
pBuffer[22] = __Permedia2TagFBSourceOffset;
|
||
pBuffer[23] = -32;
|
||
pBuffer[24] = __Permedia2TagRender;
|
||
pBuffer[25] = __RENDER_TRAPEZOID_PRIMITIVE;
|
||
|
||
//
|
||
// Now rolling copy downward.
|
||
//
|
||
pBuffer[26] = __Permedia2TagStartXDom;
|
||
pBuffer[27] = INTtoFIXED(0);
|
||
pBuffer[28] = __Permedia2TagStartY;
|
||
pBuffer[29] = INTtoFIXED(8);
|
||
pBuffer[30] = __Permedia2TagFBSourceOffset;
|
||
pBuffer[31] = -(CACHED_BRUSH_WIDTH << 3);
|
||
pBuffer[32] = __Permedia2TagCount;
|
||
pBuffer[33] = CACHED_BRUSH_HEIGHT - 8;
|
||
pBuffer[34] = __Permedia2TagRender;
|
||
pBuffer[35] = __RENDER_TRAPEZOID_PRIMITIVE;
|
||
|
||
pBuffer += 36;
|
||
|
||
InputBufferCommit(ppdev, pBuffer);
|
||
|
||
}// vPatRealize()
|
||
|
||
//-----------------------------------------------------------------------------
|
||
//
|
||
// VOID vMonoPatFill(GFNPB* ppb)
|
||
//
|
||
// Fill a series of rectangles with a monochrome pattern previously loaded
|
||
// into the area stipple unit. If bTransparent is false we must do each
|
||
// rectangle twice, inverting the stipple pattern in the second go.
|
||
//
|
||
// Argumentes needed from function block (GFNPB)
|
||
//
|
||
// ppdev-------PPDev
|
||
// psurfDst----Destination surface
|
||
// lNumRects---Number of rectangles to fill
|
||
// pRects------Pointer to a list of rectangles information which needed to be
|
||
// filled
|
||
// ucFgRop3----Foreground Logic OP for the fill
|
||
// ucBgRop3----Background Logic OP for the fill
|
||
// prbrush-----Pointer to the RBrush structure
|
||
// pptlBrush---Structure for brush origin
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
VOID
|
||
vMonoPatFill(GFNPB* ppb)
|
||
{
|
||
PPDev ppdev = ppb->ppdev;
|
||
Surf* psurf = ppb->psurfDst;
|
||
|
||
RBrush* prb = ppb->prbrush;
|
||
POINTL* pptlBrush = ppb->pptlBrush;
|
||
BrushEntry* pbe = prb->pbe; // Brush entry
|
||
RECTL* pRect = ppb->pRects; // List of rectangles to be
|
||
// filled in relative
|
||
// coordinates
|
||
ULONG* pBuffer;
|
||
|
||
DWORD dwColorMode;
|
||
DWORD dwColorReg;
|
||
DWORD dwLogicMode;
|
||
DWORD dwReadMode;
|
||
LONG lNumPass;
|
||
LONG lNumRects; // Can't be zero
|
||
// ULONG ulBgLogicOp = ulRop3ToLogicop(ppb->ucBgRop3);
|
||
ULONG ulBgLogicOp = ulRop3ToLogicop(ppb->ulRop4 >> 8);
|
||
// Not used (unless the brush
|
||
// has a mask, in which case it
|
||
// is the background mix mode)
|
||
// ULONG ulFgLogicOp = ulRop3ToLogicop(ppb->ucFgRop3);
|
||
ULONG ulFgLogicOp = ulRop3ToLogicop(ppb->ulRop4 & 0xFF);
|
||
// Hardware mix mode
|
||
// (foreground mix mode if
|
||
// the brush has a mask)
|
||
ULONG ulBgColor = prb->ulBackColor;
|
||
ULONG ulFgColor = prb->ulForeColor;
|
||
ULONG ulCurrentFillColor;
|
||
ULONG ulCurrentLogicOp;
|
||
|
||
PERMEDIA_DECL;
|
||
|
||
DBG_GDI((6, "vMonoPatFill called: %d rects. ulRop4 = %x",
|
||
ppb->lNumRects, ppb->ulRop4));
|
||
// DBG_GDI((6, "ulFgLogicOp = 0x%x, ulBgLogicOp = 0x%x",
|
||
// ulFgLogicOp, ulBgLogicOp));
|
||
|
||
DBG_GDI((6, "ulFgColor 0x%x, ulBgColor 0x%x", ulFgColor, ulBgColor));
|
||
|
||
//
|
||
// If anything has changed with the brush we must re-realize it. If the
|
||
// brush has been kicked out of the area stipple unit we must fully realize
|
||
// it. If only the alignment has changed we can simply update the alignment
|
||
// for the stipple.
|
||
//
|
||
if ( (pbe == NULL) || (pbe->prbVerify != prb) )
|
||
{
|
||
DBG_GDI((7, "full brush realize"));
|
||
(*ppdev->pgfnPatRealize)(ppb);
|
||
}
|
||
else if ( (prb->ptlBrushOrg.x != pptlBrush->x)
|
||
||(prb->ptlBrushOrg.y != pptlBrush->y) )
|
||
{
|
||
DBG_GDI((7, "changing brush offset"));
|
||
(*ppdev->pgfnMonoOffset)(ppb);
|
||
}
|
||
|
||
//
|
||
// We get some common operations which are really noops. we can save
|
||
// lots of time by cutting these out. As this happens a lot for masking
|
||
// operations it's worth doing.
|
||
//
|
||
if ( ((ulFgLogicOp == K_LOGICOP_AND) && (ulFgColor == ppdev->ulWhite))
|
||
||((ulFgLogicOp == K_LOGICOP_XOR) && (ulFgColor == 0)) )
|
||
{
|
||
DBG_GDI((7, "Set FgLogicOp to NOOP"));
|
||
ulFgLogicOp = K_LOGICOP_NOOP;
|
||
}
|
||
|
||
//
|
||
// Same for background
|
||
//
|
||
if ( ((ulBgLogicOp == K_LOGICOP_AND) && (ulBgColor == ppdev->ulWhite))
|
||
||((ulBgLogicOp == K_LOGICOP_XOR) && (ulBgColor == 0)) )
|
||
{
|
||
DBG_GDI((7, "Set BgLogicOp to NOOP"));
|
||
ulBgLogicOp = K_LOGICOP_NOOP;
|
||
}
|
||
|
||
//
|
||
// Try to do the background as a solid fill. lNumPass starts at 1 rather
|
||
// than 2 because we want to do all comparisons with zero. This is faster.
|
||
// We also do a trick with its value to avoid an extra WAIT_FIFO on the
|
||
// first pass.
|
||
//
|
||
if ( (ulBgLogicOp == K_LOGICOP_COPY)
|
||
&&(ulFgLogicOp == K_LOGICOP_COPY) )
|
||
{
|
||
DBG_GDI((7, "FgLogicOp and BgLogicOp are COPY"));
|
||
|
||
//
|
||
// For PatCopy case, we can use solid fill to fill the background first
|
||
// Note: we do not need to set FBWindowBase, it will be set by
|
||
// the solid fill
|
||
//
|
||
ppb->solidColor = ulBgColor;
|
||
(*ppdev->pgfnSolidFill)(ppb);
|
||
|
||
//
|
||
// We've done the background so we only want to go round the stipple
|
||
// loop once. So set the lNumPass counter up for only one loop and set
|
||
// the ulCurrentLogicOp and color to the foreground values.
|
||
//
|
||
lNumPass = 0;
|
||
ulCurrentFillColor = ulFgColor;
|
||
ulCurrentLogicOp = ulFgLogicOp;
|
||
|
||
//
|
||
// Do this here in case the solid fill changed the packing.
|
||
//
|
||
|
||
// brh not needed
|
||
// P2_DEFAULT_FB_DEPTH;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// For non-PATCOPY cases, we have to do 2 passes. Fill the background
|
||
// first and then fill the foreground
|
||
//
|
||
lNumPass = 1;
|
||
ulCurrentFillColor = ulBgColor;
|
||
ulCurrentLogicOp = ulBgLogicOp;
|
||
|
||
//
|
||
// Note: In this case, dxDom, dXSub and dY are initialised to 0, 0,
|
||
// and 1, so we don't need to re-load them here. But we need to set
|
||
// WindowBase here
|
||
//
|
||
|
||
InputBufferReserve(ppdev, 2, &pBuffer);
|
||
|
||
pBuffer[0] = __Permedia2TagFBWindowBase;
|
||
pBuffer[1] = psurf->ulPixOffset;
|
||
|
||
pBuffer += 2;
|
||
|
||
InputBufferCommit(ppdev, pBuffer);
|
||
|
||
}// if-else for LOGICOP_COPY case
|
||
|
||
//
|
||
// Do 2 passes loop or single loop depends on "lNumPass"
|
||
//
|
||
while ( TRUE )
|
||
{
|
||
if ( ulCurrentLogicOp != K_LOGICOP_NOOP )
|
||
{
|
||
dwReadMode = psurf->ulPackedPP;
|
||
|
||
if ( ulCurrentLogicOp == K_LOGICOP_COPY )
|
||
{
|
||
DBG_GDI((7, "Current logicOP is COPY"));
|
||
dwColorReg = __Permedia2TagFBWriteData;
|
||
dwColorMode = __PERMEDIA_DISABLE;
|
||
dwLogicMode = __PERMEDIA_CONSTANT_FB_WRITE;
|
||
}
|
||
else
|
||
{
|
||
DBG_GDI((7, "Current logicOP is NOT-COPY"));
|
||
dwColorReg = __Permedia2TagConstantColor;
|
||
dwColorMode = __COLOR_DDA_FLAT_SHADE;
|
||
dwLogicMode = P2_ENABLED_LOGICALOP(ulCurrentLogicOp);
|
||
dwReadMode |= LogicopReadDest[ulCurrentLogicOp];
|
||
}
|
||
|
||
//
|
||
// On the bg fill pass, we have to invert the sense of the
|
||
// download bits. On the first pass, lNumPass == 1; on the second
|
||
// pass, lNumPass == 0, so we get our WAIT_FIFO sums correct!!
|
||
//
|
||
InputBufferReserve(ppdev, 10, &pBuffer);
|
||
|
||
if ( lNumPass > 0 )
|
||
{
|
||
pBuffer[0] = __Permedia2TagAreaStippleMode;
|
||
pBuffer[1] = (prb->areaStippleMode
|
||
| AREA_STIPPLE_INVERT_PAT);
|
||
pBuffer += 2;
|
||
|
||
}
|
||
|
||
pBuffer[0] = __Permedia2TagColorDDAMode;
|
||
pBuffer[1] = dwColorMode;
|
||
pBuffer[2] = __Permedia2TagFBReadMode;
|
||
pBuffer[3] = dwReadMode;
|
||
pBuffer[4] = __Permedia2TagLogicalOpMode;
|
||
pBuffer[5] = dwLogicMode;
|
||
|
||
pBuffer[6] = dwColorReg,
|
||
pBuffer[7] = ulCurrentFillColor;
|
||
|
||
pBuffer += 8;
|
||
|
||
InputBufferCommit(ppdev, pBuffer);
|
||
|
||
//
|
||
// Fill rects one by one
|
||
//
|
||
lNumRects = ppb->lNumRects;
|
||
|
||
while ( TRUE )
|
||
{
|
||
DBG_GDI((7, "mono pattern fill to rect (%d,%d) to (%d,%d)",
|
||
pRect->left,
|
||
pRect->top,
|
||
pRect->right,
|
||
pRect->bottom));
|
||
|
||
InputBufferReserve(ppdev, 12, &pBuffer);
|
||
|
||
//
|
||
// Render the rectangle
|
||
//
|
||
pBuffer[0] = __Permedia2TagStartXDom;
|
||
pBuffer[1] = pRect->left << 16;
|
||
pBuffer[2] = __Permedia2TagStartXSub;
|
||
pBuffer[3] = pRect->right << 16;
|
||
pBuffer[4] = __Permedia2TagStartY;
|
||
pBuffer[5] = pRect->top << 16;
|
||
pBuffer[6] = __Permedia2TagdY;
|
||
pBuffer[7] = 1 << 16;
|
||
pBuffer[8] = __Permedia2TagCount;
|
||
pBuffer[9] = pRect->bottom - pRect->top;
|
||
|
||
pBuffer[10] = __Permedia2TagRender;
|
||
pBuffer[11] = __RENDER_TRAPEZOID_PRIMITIVE
|
||
|__RENDER_AREA_STIPPLE_ENABLE;
|
||
|
||
pBuffer += 12;
|
||
|
||
InputBufferCommit(ppdev, pBuffer);
|
||
|
||
if ( --lNumRects == 0 )
|
||
{
|
||
break;
|
||
}
|
||
|
||
pRect++;
|
||
}// loop through all the rectangles
|
||
|
||
//
|
||
// Reset our pixel values.
|
||
//
|
||
InputBufferReserve(ppdev, 2, &pBuffer);
|
||
|
||
pBuffer[0] = __Permedia2TagLogicalOpMode;
|
||
pBuffer[1] = __PERMEDIA_DISABLE;
|
||
|
||
pBuffer += 2;
|
||
|
||
InputBufferCommit(ppdev, pBuffer);
|
||
|
||
//
|
||
// We must reset the area stipple mode for the foreground pass. if
|
||
// there's no foreground pass we must reset it anyway.
|
||
//
|
||
if ( lNumPass > 0 )
|
||
{
|
||
InputBufferReserve(ppdev, 2, &pBuffer);
|
||
|
||
pBuffer[0] = __Permedia2TagAreaStippleMode;
|
||
pBuffer[1] = prb->areaStippleMode;
|
||
|
||
pBuffer += 2;
|
||
|
||
InputBufferCommit(ppdev, pBuffer);
|
||
}
|
||
}// if ( ulCurrentLogicOp != K_LOGICOP_NOOP )
|
||
|
||
if ( --lNumPass < 0 )
|
||
{
|
||
break;
|
||
}
|
||
|
||
//
|
||
// We need to the 2nd pass. So reset the rectangle info, color mode
|
||
// and logicop status
|
||
//
|
||
pRect = ppb->pRects;
|
||
ulCurrentFillColor = ulFgColor;
|
||
ulCurrentLogicOp = ulFgLogicOp;
|
||
}// Loop through all the passes
|
||
|
||
if ( dwColorMode != __PERMEDIA_DISABLE )
|
||
{
|
||
InputBufferReserve(ppdev, 2, &pBuffer);
|
||
|
||
//
|
||
// Restore ColorDDAMode
|
||
//
|
||
pBuffer[0] = __Permedia2TagColorDDAMode;
|
||
pBuffer[1] = __PERMEDIA_DISABLE;
|
||
|
||
pBuffer += 2;
|
||
|
||
InputBufferCommit(ppdev, pBuffer);
|
||
}
|
||
|
||
DBG_GDI((6, "vMonoPatFill returning"));
|
||
|
||
}// vMonoPatFill()
|
||
|
||
//-----------------------------------------------------------------------------
|
||
//
|
||
// VOID vPatFill(GFNPB* ppb)
|
||
//
|
||
// Function to fill a set of rectangles with a given pattern. Colored patterns
|
||
// only. Monochrome patterns are handled in a different routine. This routine
|
||
// only handles patterns which were not rotated in memory and which have been
|
||
// replicated in X to cope with different alignments.
|
||
//
|
||
// Parameter block arguments
|
||
//
|
||
// ppdev-------Valid
|
||
// lNumRects---Number of rects pointed to by pRects
|
||
// pRects------Of destination rectangles to be filled
|
||
// ucFgRop3----Valid Pattern fill rop3 code (source invariant)
|
||
// pptlBrush---Origin of brush
|
||
// pdsurfDst---Destination surface
|
||
// prbrush-----ponter to RBRUSH
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
VOID
|
||
vPatFill(GFNPB* ppb)
|
||
{
|
||
PPDev ppdev = ppb->ppdev;
|
||
LONG lNumRects = ppb->lNumRects;
|
||
RECTL* prcl = ppb->pRects;
|
||
POINTL* pptlBrush = ppb->pptlBrush;
|
||
Surf* psurf = ppb->psurfDst;
|
||
RBrush* prbrush = ppb->prbrush;
|
||
|
||
BrushEntry* pbe = prbrush->pbe;
|
||
DWORD dwRenderBits;
|
||
ULONG ulBrushX;
|
||
ULONG ulBrushY;
|
||
ULONG ulBrushOffset;
|
||
// ULONG ulLogicOP = ulRop3ToLogicop(ppb->ucFgRop3);
|
||
ULONG ulLogicOP = ulRop3ToLogicop(ppb->ulRop4 & 0xFF);
|
||
ULONG* pBuffer;
|
||
|
||
PERMEDIA_DECL;
|
||
|
||
ASSERTDD(lNumRects > 0, "vPatFill: unexpected rectangle lNumRects <= 0");
|
||
|
||
if ( (pbe == NULL) || (pbe->prbVerify != ppb->prbrush) )
|
||
{
|
||
vPatRealize(ppb);
|
||
|
||
pbe = prbrush->pbe;
|
||
ASSERTDD(pbe != NULL, "vPatFill: unexpected null pattern brush entry");
|
||
}
|
||
|
||
dwRenderBits = __RENDER_TRAPEZOID_PRIMITIVE
|
||
| __RENDER_TEXTURED_PRIMITIVE;
|
||
|
||
InputBufferReserve(ppdev, 34, &pBuffer);
|
||
|
||
pBuffer[0] = __Permedia2TagFBWindowBase;
|
||
pBuffer[1] = psurf->ulPixOffset;
|
||
pBuffer[2] = __Permedia2TagLogicalOpMode;
|
||
pBuffer[3] = P2_ENABLED_LOGICALOP(ulLogicOP);
|
||
pBuffer[4] = __Permedia2TagFBReadMode;
|
||
pBuffer[5] = PM_FBREADMODE_PARTIAL(psurf->ulPackedPP)
|
||
| LogicopReadDest[ulLogicOP];
|
||
pBuffer[6] = __Permedia2TagFBWriteConfig;
|
||
pBuffer[7] = PM_FBREADMODE_PARTIAL(psurf->ulPackedPP)
|
||
| LogicopReadDest[ulLogicOP];
|
||
pBuffer[8] = __Permedia2TagFBSourceOffset;
|
||
pBuffer[9] = 0;
|
||
|
||
//
|
||
// Setup the texture unit with the pattern
|
||
//
|
||
pBuffer[10] = __Permedia2TagDitherMode;
|
||
pBuffer[11] = (COLOR_MODE << PM_DITHERMODE_COLORORDER)
|
||
| (ppdev->ulPermFormat << PM_DITHERMODE_COLORFORMAT)
|
||
| (ppdev->ulPermFormatEx << PM_DITHERMODE_COLORFORMATEXTENSION)
|
||
| (1 << PM_DITHERMODE_ENABLE);
|
||
|
||
pBuffer[12] = __Permedia2TagTextureAddressMode;
|
||
pBuffer[13] = (1 << PM_TEXADDRESSMODE_ENABLE);
|
||
pBuffer[14] = __Permedia2TagTextureColorMode;
|
||
pBuffer[15] = (1 << PM_TEXCOLORMODE_ENABLE)
|
||
| (0 << 4) // RGB
|
||
| (3 << 1); // Copy
|
||
|
||
|
||
pBuffer[16] = __Permedia2TagTextureReadMode;
|
||
pBuffer[17] = PM_TEXREADMODE_ENABLE(__PERMEDIA_ENABLE)
|
||
| PM_TEXREADMODE_WIDTH(CACHED_BRUSH_WIDTH_LOG2 - 1)
|
||
| PM_TEXREADMODE_HEIGHT(CACHED_BRUSH_HEIGHT_LOG2 - 1)
|
||
| (1 << 1) // repeat S
|
||
| (1 << 3); // repeat T
|
||
|
||
pBuffer[18] = __Permedia2TagTextureDataFormat;
|
||
pBuffer[19] = (ppdev->ulPermFormat << PM_TEXDATAFORMAT_FORMAT)
|
||
| (ppdev->ulPermFormatEx << PM_TEXDATAFORMAT_FORMATEXTENSION)
|
||
| (COLOR_MODE << PM_TEXDATAFORMAT_COLORORDER);
|
||
|
||
pBuffer[20] = __Permedia2TagTextureMapFormat;
|
||
pBuffer[21] = (ppdev->ulBrushPackedPP)
|
||
| (ppdev->cPelSize << PM_TEXMAPFORMAT_TEXELSIZE);
|
||
|
||
//@@BEGIN_DDKSPLIT
|
||
// TODO: use SStart and TStart to avoid having to offset the pattern using
|
||
// ulBrushOffset. This will also allow us to save some space in the
|
||
// pattern cache (we have to make it 7 pixels wider and taller due to
|
||
// our need to set different origins).
|
||
//@@END_DDKSPLIT
|
||
pBuffer[22] = __Permedia2TagSStart;
|
||
pBuffer[23] = 0;
|
||
pBuffer[24] = __Permedia2TagTStart;
|
||
pBuffer[25] = 0;
|
||
pBuffer[26] = __Permedia2TagdSdx;
|
||
pBuffer[27] = 1 << 20;
|
||
pBuffer[28] = __Permedia2TagdSdyDom;
|
||
pBuffer[29] = 0;
|
||
pBuffer[30] = __Permedia2TagdTdx;
|
||
pBuffer[31] = 0;
|
||
pBuffer[32] = __Permedia2TagdTdyDom;
|
||
pBuffer[33] = 1 << 20;
|
||
|
||
pBuffer += 34;
|
||
|
||
InputBufferCommit(ppdev, pBuffer);
|
||
|
||
//
|
||
// Render rectangles
|
||
//
|
||
do
|
||
{
|
||
//
|
||
// Caclulate brush offset taking into account the brush origin
|
||
// NOTE: that the texture unit places the origin of the texture
|
||
// at the upper left of the destination rectangle
|
||
//
|
||
ulBrushX = (prcl->left - ppb->pptlBrush->x) & 7;
|
||
ulBrushY = (prcl->top - ppb->pptlBrush->y) & 7;
|
||
ulBrushOffset = pbe->ulPixelOffset
|
||
+ ulBrushX
|
||
+ (ulBrushY * CACHED_BRUSH_WIDTH);
|
||
|
||
InputBufferReserve(ppdev, 12, &pBuffer);
|
||
|
||
pBuffer[0] = __Permedia2TagTextureBaseAddress;
|
||
pBuffer[1] = ulBrushOffset;
|
||
pBuffer[2] = __Permedia2TagStartXDom;
|
||
pBuffer[3] = INTtoFIXED(prcl->left);
|
||
pBuffer[4] = __Permedia2TagStartXSub;
|
||
pBuffer[5] = INTtoFIXED(prcl->right);
|
||
pBuffer[6] = __Permedia2TagStartY;
|
||
pBuffer[7] = INTtoFIXED(prcl->top);
|
||
pBuffer[8] = __Permedia2TagCount;
|
||
pBuffer[9] = (prcl->bottom - prcl->top);
|
||
pBuffer[10] = __Permedia2TagRender;
|
||
pBuffer[11] = dwRenderBits;
|
||
|
||
pBuffer += 12;
|
||
|
||
InputBufferCommit(ppdev, pBuffer);
|
||
|
||
prcl++;
|
||
|
||
} while (--lNumRects != 0);
|
||
|
||
//
|
||
// Restore defaults
|
||
//
|
||
InputBufferReserve(ppdev, 8, &pBuffer);
|
||
|
||
pBuffer[0] = __Permedia2TagTextureAddressMode;
|
||
pBuffer[1] = (0 << PM_TEXADDRESSMODE_ENABLE);
|
||
pBuffer[2] = __Permedia2TagTextureColorMode;
|
||
pBuffer[3] = (0 << PM_TEXCOLORMODE_ENABLE);
|
||
pBuffer[4] = __Permedia2TagDitherMode;
|
||
pBuffer[5] = (0 << PM_DITHERMODE_ENABLE);
|
||
pBuffer[6] = __Permedia2TagTextureReadMode;
|
||
pBuffer[7] = __PERMEDIA_DISABLE;
|
||
|
||
pBuffer += 8;
|
||
|
||
InputBufferCommit(ppdev, pBuffer);
|
||
|
||
DBG_GDI((6, "vPatternFillRects done"));
|
||
}// vPatFill
|
||
|