You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
226 lines
6.8 KiB
226 lines
6.8 KiB
/******************************Module*Header**********************************\
|
|
*
|
|
* *******************
|
|
* * GDI SAMPLE CODE *
|
|
* *******************
|
|
*
|
|
* Module Name: clip.c
|
|
*
|
|
* Clipping code.
|
|
*
|
|
* 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 "clip.h"
|
|
|
|
//----------------------------*Public*Routine-------------------------------
|
|
// BOOL bIntersect
|
|
//
|
|
// Function:
|
|
// Check the integration of two input rectangles (RECTL* pRcl1,
|
|
// RECTL* pRcl2) and set the intersection result in (RECTL* pRclResult)
|
|
//
|
|
// Return:
|
|
// TRUE---If 'prcl1' and 'prcl2' intersect. The intersection will be in
|
|
// 'prclResult'
|
|
// FALSE--If they don't intersect. 'prclResult' is undefined.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
BOOL
|
|
bIntersect(RECTL* pRcl1,
|
|
RECTL* pRcl2,
|
|
RECTL* pRclResult)
|
|
{
|
|
DBG_GDI((7, "bIntersect called--pRcl1=0x%x, pRcl2=0x%x, pRclResult=0x%x",
|
|
pRcl1, pRcl2, pRclResult));
|
|
|
|
pRclResult->left = max(pRcl1->left, pRcl2->left);
|
|
pRclResult->right = min(pRcl1->right, pRcl2->right);
|
|
|
|
//
|
|
// Check if there an intersection horizontally
|
|
//
|
|
if ( pRclResult->left < pRclResult->right )
|
|
{
|
|
pRclResult->top = max(pRcl1->top, pRcl2->top);
|
|
pRclResult->bottom = min(pRcl1->bottom, pRcl2->bottom);
|
|
|
|
if (pRclResult->top < pRclResult->bottom)
|
|
{
|
|
//
|
|
// Check if there an intersection vertically
|
|
//
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
DBG_GDI((7, "bIntersect returned FALSE"));
|
|
|
|
//
|
|
// Return FALSE if there is no intersection
|
|
//
|
|
return(FALSE);
|
|
}// bIntersect()
|
|
|
|
//-----------------------------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,
|
|
LONG lNumOfRecs)
|
|
{
|
|
LONG cIntersections;
|
|
RECTL* pRclOut;
|
|
|
|
DBG_GDI((7, "cIntersect called--pRclClip=0x%x, pRclIn=0x%x,lNumOfRecs=%ld",
|
|
pRclClip, pRclIn, lNumOfRecs));
|
|
|
|
cIntersections = 0;
|
|
pRclOut = pRclIn; // Put the result in place as the input
|
|
|
|
//
|
|
// Validate input parameter
|
|
//
|
|
ASSERTDD( ((pRclIn != NULL ) && (pRclClip != NULL) && ( lNumOfRecs >= 0 )),
|
|
"Wrong input to cIntersect" );
|
|
|
|
for (; lNumOfRecs != 0; pRclIn++, lNumOfRecs--)
|
|
{
|
|
pRclOut->left = max(pRclIn->left, pRclClip->left);
|
|
pRclOut->right = min(pRclIn->right, pRclClip->right);
|
|
|
|
if ( pRclOut->left < pRclOut->right )
|
|
{
|
|
//
|
|
// Find intersection, horizontally, between current rectangle and
|
|
// the clipping rectangle.
|
|
//
|
|
pRclOut->top = max(pRclIn->top, pRclClip->top);
|
|
pRclOut->bottom = min(pRclIn->bottom, pRclClip->bottom);
|
|
|
|
if ( pRclOut->top < pRclOut->bottom )
|
|
{
|
|
//
|
|
// Find intersection, vertically, between current rectangle and
|
|
// the clipping rectangle. Put this rectangle in the result
|
|
// list and increment the counter. Ready for next input
|
|
//
|
|
pRclOut++;
|
|
cIntersections++;
|
|
}
|
|
}
|
|
}// loop through all the input rectangles
|
|
|
|
DBG_GDI((7, "cIntersect found %d intersections", cIntersections));
|
|
return(cIntersections);
|
|
}// cIntersect()
|
|
|
|
//-----------------------------Public Routine-------------------------------
|
|
// VOID vClipAndRender
|
|
//
|
|
// Clips the destination rectangle calling pfgn (the render function) as
|
|
// appropriate.
|
|
//
|
|
// Argumentes needed from function block (GFNPB)
|
|
//
|
|
// pco------pointer to clip object
|
|
// prclDst--pointer to destination rectangle
|
|
// psurfDst-pointer to destination Surf
|
|
// psurfSrc-pointer to destination Surf (NULL if no source)
|
|
// pptlSrc--pointer to source point
|
|
// prclSrc--pointer to source rectangle (used if pptlSrc == NULL)
|
|
// pgfn-----pointer to render function
|
|
//
|
|
// NOTES:
|
|
//
|
|
// pptlSrc and prclSrc are only used if psurfSrc == psurfDst. If there is
|
|
// no source psurfSrc must be set to NULL. If prclSrc is specified, pptlSrc
|
|
// is not used.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
VOID vClipAndRender(GFNPB * ppb)
|
|
{
|
|
CLIPOBJ * pco = ppb->pco;
|
|
|
|
if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
|
|
{
|
|
ppb->pRects = ppb->prclDst;
|
|
ppb->lNumRects = 1;
|
|
ppb->pgfn(ppb);
|
|
}
|
|
else if (pco->iDComplexity == DC_RECT)
|
|
{
|
|
RECTL rcl;
|
|
|
|
if (bIntersect(ppb->prclDst, &pco->rclBounds, &rcl))
|
|
{
|
|
ppb->pRects = &rcl;
|
|
ppb->lNumRects = 1;
|
|
ppb->pgfn(ppb);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ClipEnum ce;
|
|
LONG c;
|
|
BOOL bMore;
|
|
ULONG ulDir = CD_ANY;
|
|
|
|
// determine direction if operation on same surface
|
|
if(ppb->psurfDst == ppb->psurfSrc)
|
|
{
|
|
LONG lXSrc, lYSrc, offset;
|
|
|
|
if(ppb->pptlSrc != NULL)
|
|
{
|
|
lXSrc = ppb->pptlSrc->x;
|
|
lYSrc = ppb->pptlSrc->y;
|
|
}
|
|
else
|
|
{
|
|
lXSrc = ppb->prclSrc->left;
|
|
lYSrc = ppb->prclSrc->top;
|
|
}
|
|
|
|
// NOTE: we can safely shift by 16 because the surface
|
|
// stride will never be greater the 2--16
|
|
offset = (ppb->prclDst->top - lYSrc) << 16;
|
|
offset += (ppb->prclDst->left - lXSrc);
|
|
if(offset > 0)
|
|
ulDir = CD_LEFTUP;
|
|
else
|
|
ulDir = CD_RIGHTDOWN;
|
|
}
|
|
|
|
|
|
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, ulDir, 0);
|
|
|
|
do
|
|
{
|
|
bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
|
|
|
|
c = cIntersect(ppb->prclDst, ce.arcl, ce.c);
|
|
|
|
if (c != 0)
|
|
{
|
|
ppb->pRects = ce.arcl;
|
|
ppb->lNumRects = c;
|
|
ppb->pgfn(ppb);
|
|
}
|
|
|
|
} while (bMore);
|
|
}
|
|
}
|
|
|
|
|