/******************************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); } }