445 lines
12 KiB
C
445 lines
12 KiB
C
/******************************Module*Header*******************************\
|
|
* Module Name: misc.c
|
|
*
|
|
* Miscellaneous common routines.
|
|
*
|
|
* Copyright (c) 1992-1996 Microsoft Corporation
|
|
* Copyright (c) 1993-1996 Matrox Electronic Systems, Ltd.
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bIntersect
|
|
*
|
|
* If 'prcl1' and 'prcl2' intersect, has a return value of TRUE and returns
|
|
* the intersection in 'prclResult'. If they don't intersect, has a return
|
|
* value of FALSE, and 'prclResult' is undefined.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bIntersect(
|
|
RECTL* prcl1,
|
|
RECTL* prcl2,
|
|
RECTL* prclResult)
|
|
{
|
|
prclResult->left = max(prcl1->left, prcl2->left);
|
|
prclResult->right = min(prcl1->right, prcl2->right);
|
|
|
|
if (prclResult->left < prclResult->right)
|
|
{
|
|
prclResult->top = max(prcl1->top, prcl2->top);
|
|
prclResult->bottom = min(prcl1->bottom, prcl2->bottom);
|
|
|
|
if (prclResult->top < prclResult->bottom)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* LONG cIntersect
|
|
*
|
|
* This routine takes a list of rectangles from 'prclIn' and clips them
|
|
* in-place to the rectangle 'prclClip'. The input rectangles don't
|
|
* have to intersect 'prclClip'; the return value will reflect the
|
|
* number of input rectangles that did intersect, and the intersecting
|
|
* rectangles will be densely packed.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
LONG cIntersect(
|
|
RECTL* prclClip,
|
|
RECTL* prclIn, // List of rectangles
|
|
LONG c) // Can be zero
|
|
{
|
|
LONG cIntersections;
|
|
RECTL* prclOut;
|
|
|
|
cIntersections = 0;
|
|
prclOut = prclIn;
|
|
|
|
for (; c != 0; prclIn++, c--)
|
|
{
|
|
prclOut->left = max(prclIn->left, prclClip->left);
|
|
prclOut->right = min(prclIn->right, prclClip->right);
|
|
|
|
if (prclOut->left < prclOut->right)
|
|
{
|
|
prclOut->top = max(prclIn->top, prclClip->top);
|
|
prclOut->bottom = min(prclIn->bottom, prclClip->bottom);
|
|
|
|
if (prclOut->top < prclOut->bottom)
|
|
{
|
|
prclOut++;
|
|
cIntersections++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(cIntersections);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vResetClipping
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vResetClipping(
|
|
PDEV* ppdev)
|
|
{
|
|
BYTE* pjBase;
|
|
ULONG ulYDstOrg;
|
|
|
|
pjBase = ppdev->pjBase;
|
|
ulYDstOrg = ppdev->ulYDstOrg; // MGA's linear offset
|
|
|
|
CHECK_FIFO_SPACE(pjBase, 4);
|
|
|
|
CP_WRITE(pjBase, DWG_CXLEFT, 0);
|
|
CP_WRITE(pjBase, DWG_CXRIGHT, ppdev->cxMemory - 1);
|
|
CP_WRITE(pjBase, DWG_CYTOP, ulYDstOrg);
|
|
CP_WRITE(pjBase, DWG_CYBOT,
|
|
(ppdev->cyMemory - 1) * ppdev->cxMemory + ulYDstOrg);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vSetClipping
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vSetClipping(
|
|
PDEV* ppdev,
|
|
RECTL* prclClip) // In relative coordinates
|
|
{
|
|
BYTE* pjBase;
|
|
ULONG ulYDstOrg;
|
|
LONG xOffset;
|
|
LONG yOffset;
|
|
LONG cxMemory;
|
|
|
|
pjBase = ppdev->pjBase;
|
|
xOffset = ppdev->xOffset;
|
|
|
|
CHECK_FIFO_SPACE(pjBase, 4);
|
|
|
|
CP_WRITE(pjBase, DWG_CXLEFT, xOffset + prclClip->left);
|
|
CP_WRITE(pjBase, DWG_CXRIGHT, xOffset + prclClip->right - 1);
|
|
|
|
ulYDstOrg = ppdev->ulYDstOrg; // MGA's linear offset
|
|
yOffset = ppdev->yOffset;
|
|
cxMemory = ppdev->cxMemory;
|
|
|
|
CP_WRITE(pjBase, DWG_CYTOP,
|
|
(yOffset + prclClip->top) * cxMemory + ulYDstOrg);
|
|
CP_WRITE(pjBase, DWG_CYBOT,
|
|
(yOffset + prclClip->bottom - 1) * cxMemory + ulYDstOrg);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vAlignedCopy
|
|
*
|
|
* Copies the given portion of a bitmap, using dword alignment for the
|
|
* screen. Note that this routine has no notion of banking.
|
|
*
|
|
* Updates ppjDst and ppjSrc to point to the beginning of the next scan.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vAlignedCopy(
|
|
PDEV* ppdev,
|
|
BYTE** ppjDst,
|
|
LONG lDstDelta,
|
|
BYTE** ppjSrc,
|
|
LONG lSrcDelta,
|
|
LONG cjScan,
|
|
LONG cyScan,
|
|
BOOL bDstIsScreen)
|
|
{
|
|
BYTE* pjDst;
|
|
BYTE* pjSrc;
|
|
LONG cjMiddle;
|
|
LONG culMiddle;
|
|
LONG cjStartPhase;
|
|
LONG cjEndPhase;
|
|
LONG i;
|
|
BYTE* pjBase;
|
|
|
|
pjBase= ppdev->pjBase;
|
|
|
|
pjSrc = *ppjSrc;
|
|
pjDst = *ppjDst;
|
|
|
|
cjStartPhase = (LONG)((0 - ((bDstIsScreen) ? (ULONG_PTR) pjDst
|
|
: (ULONG_PTR) pjSrc)) & 3);
|
|
cjMiddle = cjScan - cjStartPhase;
|
|
|
|
if (cjMiddle < 0)
|
|
{
|
|
cjStartPhase = 0;
|
|
cjMiddle = cjScan;
|
|
}
|
|
|
|
lSrcDelta -= cjScan;
|
|
lDstDelta -= cjScan; // Account for middle
|
|
|
|
cjEndPhase = cjMiddle & 3;
|
|
culMiddle = cjMiddle >> 2;
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
// Portable bus-aligned copy
|
|
//
|
|
// 'memcpy' usually aligns to the destination, so we could call
|
|
// it for that case, but unfortunately we can't be sure. We
|
|
// always want to align to the frame buffer:
|
|
|
|
if (bDstIsScreen)
|
|
{
|
|
START_DIRECT_ACCESS_STORM(ppdev, pjBase);
|
|
|
|
// Align to the destination (implying that the source may be
|
|
// unaligned):
|
|
|
|
for (; cyScan > 0; cyScan--)
|
|
{
|
|
for (i = cjStartPhase; i > 0; i--)
|
|
{
|
|
*pjDst++ = *pjSrc++;
|
|
}
|
|
|
|
for (i = culMiddle; i > 0; i--)
|
|
{
|
|
*((ULONG*) pjDst) = *((ULONG UNALIGNED *) pjSrc);
|
|
pjSrc += sizeof(ULONG);
|
|
pjDst += sizeof(ULONG);
|
|
}
|
|
|
|
for (i = cjEndPhase; i > 0; i--)
|
|
{
|
|
*pjDst++ = *pjSrc++;
|
|
}
|
|
|
|
pjSrc += lSrcDelta;
|
|
pjDst += lDstDelta;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
START_DIRECT_ACCESS_STORM_FOR_READ(ppdev, pjBase);
|
|
|
|
// Align to the source (implying that the destination may be
|
|
// unaligned):
|
|
|
|
for (; cyScan > 0; cyScan--)
|
|
{
|
|
for (i = cjStartPhase; i > 0; i--)
|
|
{
|
|
*pjDst++ = *pjSrc++;
|
|
}
|
|
|
|
for (i = culMiddle; i > 0; i--)
|
|
{
|
|
*((ULONG UNALIGNED *) pjDst) = *((ULONG*) (pjSrc));
|
|
|
|
pjSrc += sizeof(ULONG);
|
|
pjDst += sizeof(ULONG);
|
|
}
|
|
|
|
for (i = cjEndPhase; i > 0; i--)
|
|
{
|
|
*pjDst++ = *pjSrc++;
|
|
}
|
|
|
|
pjSrc += lSrcDelta;
|
|
pjDst += lDstDelta;
|
|
}
|
|
}
|
|
|
|
END_DIRECT_ACCESS_STORM(ppdev, pjBase);
|
|
|
|
*ppjSrc = pjSrc; // Save the updated pointers
|
|
*ppjDst = pjDst;
|
|
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vMilGetBitsLinear
|
|
*
|
|
* Copies the bits to the given surface from the screen, using the memory
|
|
* aperture. Must be pre-clipped.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vMilGetBitsLinear(
|
|
PDEV* ppdev,
|
|
SURFOBJ* psoDst,
|
|
RECTL* prclDst, // Absolute coordinates!
|
|
POINTL* pptlSrc) // Absolute coordinates!
|
|
{
|
|
RECTL rclDraw;
|
|
LONG cjOffset;
|
|
LONG cyScan;
|
|
LONG lDstDelta;
|
|
LONG lSrcDelta;
|
|
BYTE* pjDst;
|
|
BYTE* pjSrc;
|
|
LONG cjScan;
|
|
LONG cjRemainder;
|
|
|
|
DISPDBG((5, "vGetBitsLinear -- enter"));
|
|
|
|
rclDraw.left = pptlSrc->x;
|
|
rclDraw.top = pptlSrc->y;
|
|
rclDraw.right = rclDraw.left + (prclDst->right - prclDst->left);
|
|
rclDraw.bottom = rclDraw.top + (prclDst->bottom - prclDst->top);
|
|
|
|
ASSERTDD((rclDraw.left >= 0) &&
|
|
(rclDraw.top >= 0) &&
|
|
(rclDraw.right <= ppdev->cxMemory) &&
|
|
(rclDraw.bottom <= ppdev->cyMemory),
|
|
"vGetBitsLinear: rectangle wasn't fully clipped");
|
|
|
|
// Calculate the pointer to the upper-left corner of both rectangles:
|
|
|
|
lSrcDelta = ppdev->lDelta;
|
|
pjSrc = ppdev->pjScreen + rclDraw.top * lSrcDelta
|
|
+ (ppdev->cjPelSize * (rclDraw.left + ppdev->ulYDstOrg));
|
|
|
|
lDstDelta = psoDst->lDelta;
|
|
pjDst = (BYTE*) psoDst->pvScan0 + prclDst->top * lDstDelta
|
|
+ (ppdev->cjPelSize * prclDst->left);
|
|
|
|
cjScan = ppdev->cjPelSize * (rclDraw.right - rclDraw.left);
|
|
cyScan = (rclDraw.bottom - rclDraw.top);
|
|
|
|
vAlignedCopy(ppdev, &pjDst, lDstDelta, &pjSrc, lSrcDelta, cjScan, cyScan,
|
|
FALSE); // Screen is the source
|
|
DISPDBG((5, "vGetBitsLinear -- exit"));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vMilPutBitsLinear
|
|
*
|
|
* Copies the bits from the given surface to the screen, using the memory
|
|
* aperture. Must be pre-clipped.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vMilPutBitsLinear(
|
|
PDEV* ppdev,
|
|
SURFOBJ* psoSrc,
|
|
RECTL* prclDst, // Absolute coordinates!
|
|
POINTL* pptlSrc) // Absolute coordinates!
|
|
{
|
|
RECTL rclDraw;
|
|
LONG cjOffset;
|
|
LONG cyScan;
|
|
LONG lDstDelta;
|
|
LONG lSrcDelta;
|
|
BYTE* pjDst;
|
|
BYTE* pjSrc;
|
|
LONG cjScan;
|
|
LONG cjRemainder;
|
|
|
|
DISPDBG((5, "vPutBitsLinear -- enter"));
|
|
|
|
rclDraw = *prclDst;
|
|
|
|
ASSERTDD((rclDraw.left >= 0) &&
|
|
(rclDraw.top >= 0) &&
|
|
(rclDraw.right <= ppdev->cxMemory) &&
|
|
(rclDraw.bottom <= ppdev->cyMemory),
|
|
"vPutBitsLinear: rectangle wasn't fully clipped");
|
|
|
|
// Calculate the pointer to the upper-left corner of both rectangles:
|
|
|
|
lDstDelta = ppdev->lDelta;
|
|
pjDst = ppdev->pjScreen + rclDraw.top * lDstDelta
|
|
+ (ppdev->cjPelSize * (rclDraw.left + ppdev->ulYDstOrg));
|
|
|
|
lSrcDelta = psoSrc->lDelta;
|
|
pjSrc = (BYTE*) psoSrc->pvScan0 + (pptlSrc->y * lSrcDelta)
|
|
+ (ppdev->cjPelSize * pptlSrc->x);
|
|
|
|
cjScan = ppdev->cjPelSize * (rclDraw.right - rclDraw.left);
|
|
cyScan = (rclDraw.bottom - rclDraw.top);
|
|
|
|
vAlignedCopy(ppdev, &pjDst, lDstDelta, &pjSrc, lSrcDelta, cjScan, cyScan,
|
|
TRUE); // Screen is the dest
|
|
DISPDBG((5, "vPutBitsLinear -- exit"));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vGetBits
|
|
*
|
|
* Copies the bits to the given surface from the screen, using the memory
|
|
* aperture. Must be pre-clipped.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vGetBits(
|
|
PDEV* ppdev,
|
|
SURFOBJ* psoDst,
|
|
RECTL* prclDst, // Absolute coordinates!
|
|
POINTL* pptlSrc) // Absolute coordinates!
|
|
{
|
|
if (ppdev->ulBoardId == MGA_STORM)
|
|
{
|
|
vMilGetBitsLinear(ppdev, psoDst, prclDst, pptlSrc);
|
|
}
|
|
else if (ppdev->iBitmapFormat == BMF_8BPP)
|
|
{
|
|
vMgaGetBits8bpp(ppdev, psoDst, prclDst, pptlSrc);
|
|
}
|
|
else if (ppdev->iBitmapFormat == BMF_16BPP)
|
|
{
|
|
vMgaGetBits16bpp(ppdev, psoDst, prclDst, pptlSrc);
|
|
}
|
|
else
|
|
{
|
|
vMgaGetBits24bpp(ppdev, psoDst, prclDst, pptlSrc);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vPutBits
|
|
*
|
|
* Copies the bits from the given surface to the screen, using the memory
|
|
* aperture. Must be pre-clipped.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vPutBits(
|
|
PDEV* ppdev,
|
|
SURFOBJ* psoSrc,
|
|
RECTL* prclDst, // Absolute coordinates!
|
|
POINTL* pptlSrc) // Absolute coordinates!
|
|
{
|
|
LONG xOffset;
|
|
LONG yOffset;
|
|
|
|
if (ppdev->ulBoardId == MGA_STORM)
|
|
{
|
|
vMilPutBitsLinear(ppdev, psoSrc, prclDst, pptlSrc);
|
|
}
|
|
else
|
|
{
|
|
// 'vXferNative' takes relative coordinates, but we have absolute
|
|
// coordinates here. Temporarily adjust our offset variables:
|
|
|
|
xOffset = ppdev->xOffset;
|
|
yOffset = ppdev->yOffset;
|
|
|
|
ppdev->xOffset = 0;
|
|
ppdev->yOffset = 0;
|
|
|
|
vXferNative(ppdev, 1, prclDst, 0xCCCC, psoSrc, pptlSrc, prclDst, NULL);
|
|
|
|
ppdev->xOffset = xOffset;
|
|
ppdev->yOffset = yOffset;
|
|
}
|
|
}
|