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.
773 lines
22 KiB
773 lines
22 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: clipobj.cxx
|
|
*
|
|
* Clipping object non-inline methods
|
|
*
|
|
* Created: 15-Sep-1990 15:25:02
|
|
* Author: Donald Sidoroff [donalds]
|
|
*
|
|
* Copyright (c) 1990-1999 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
/******************************Public*Routine******************************\
|
|
* XCLIPOBJ::vSetup
|
|
*
|
|
* Create an XCLIPOBJ.
|
|
*
|
|
* input:
|
|
*
|
|
* prgn_ - region to build clipobj from
|
|
* erclExcl - Only intrested in the part of the region that intersects this
|
|
* iForcedClip - CLIP_NOFORCE - will be trivial if erclExcl is fully bounded
|
|
* CLIP_FORCE - will never be trivial
|
|
* CLIP_NOFORCETRIV - will be trivial if single rectangle
|
|
*
|
|
* output/clipobj:
|
|
*
|
|
* iUniq - iUniq from region
|
|
*
|
|
* rclBounds - bounds of the clipping area
|
|
* intersection of erclExcl and region bounds. It may further
|
|
* be reduced to only bound rectangles that touch erclExcl.
|
|
*
|
|
* iDComplexity - complexity of part of region that intersects drawing
|
|
*
|
|
* TRIVIAL - all parts of erclExcl are visible. The object may
|
|
* span multiple scans but is fully contained.
|
|
*
|
|
* RECT - The object (bounded by erclExcl) need only be clipped
|
|
* against a single rectangle set in rclBounds.
|
|
*
|
|
* COMPLEX - enumeration is needed to get a list of rectangles to clip against
|
|
*
|
|
* iFComplexity - full region complexity, RECT, RECT4, COMPLEX
|
|
*
|
|
* iMode - TC_RECTANGLES - internal storage mode
|
|
*
|
|
* fjOptions - OC_RESERVED - this bit used to be called OC_BANK_CLIP and
|
|
* is set by banking drivers. This bit has been obsoleted,
|
|
* but because 4.0 drivers may still set the bit we can't
|
|
* re-use it for something else.
|
|
*
|
|
*
|
|
* hidden fields:
|
|
*
|
|
* cObj - number of rectangles that intersect erclExcl
|
|
*
|
|
* History:
|
|
* 06-Oct-1993 -by- Eric Kutter [erick]
|
|
* Update documentation, remove traps, add paths
|
|
*
|
|
* 24-Jul-1991 -by- Donald Sidoroff [donalds]
|
|
* Updated to DDI spec.
|
|
*
|
|
* 15-Sep-1990 -by- Donald Sidoroff [donalds]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
#define CMAXOBJ 10
|
|
|
|
VOID XCLIPOBJ::vSetup(REGION *prgn_, ERECTL& erclExcl, int iForcedClip)
|
|
{
|
|
// Set up the internal fields
|
|
|
|
prgn = prgn_;
|
|
|
|
// Initialize as many of the CLIPOBJ fields as we can:
|
|
|
|
*((ULONG*)&iDComplexity) = 0; // iDComplexity = DC_TRIVIAL,
|
|
// iMode = TC_RECTANGLES,
|
|
// fjOptions = 0,
|
|
// iFComplexity = invalid
|
|
rclBounds.bottom = erclExcl.bottom;
|
|
rclBounds.right = erclExcl.right;
|
|
rclBounds.top = erclExcl.top;
|
|
rclBounds.left = erclExcl.left;
|
|
iUniq = prgn->iUnique;
|
|
|
|
if ((prgn->sizeRgn <= SINGLE_REGION_SIZE) &&
|
|
(rclBounds.left >= prgn->rcl.left) &&
|
|
(rclBounds.top >= prgn->rcl.top) &&
|
|
(rclBounds.right <= prgn->rcl.right) &&
|
|
(rclBounds.bottom <= prgn->rcl.bottom) &&
|
|
(iForcedClip != CLIP_FORCE))
|
|
{
|
|
// Unfortunately, some callers may give us an empty or crossed
|
|
// 'erclExcl', and we have to watch for that case:
|
|
|
|
if ((rclBounds.top < rclBounds.bottom) &&
|
|
(rclBounds.left < rclBounds.right))
|
|
{
|
|
|
|
// This is the trivial acceptance case, which will be the most common
|
|
// case. The region is a single rectangle that bounds the drawing.
|
|
// We've already set up for trivial clipping.
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Calculate the intersection of the drawing bounds with the region
|
|
// bounds:
|
|
|
|
rclBounds.left = max(rclBounds.left, prgn->rcl.left);
|
|
rclBounds.top = max(rclBounds.top, prgn->rcl.top);
|
|
rclBounds.right = min(rclBounds.right, prgn->rcl.right);
|
|
rclBounds.bottom = min(rclBounds.bottom, prgn->rcl.bottom);
|
|
|
|
if ((rclBounds.left >= rclBounds.right) ||
|
|
(rclBounds.top >= rclBounds.bottom))
|
|
{
|
|
// This takes care of the trivial rejection case. It is the caller's
|
|
// responsibility to again check for this case by calling 'bEmpty'
|
|
// on 'rclBounds' -- in which case, we have to collapse the rectangle:
|
|
|
|
rclBounds.left = rclBounds.right;
|
|
return;
|
|
}
|
|
|
|
if ((prgn->sizeRgn <= SINGLE_REGION_SIZE) &&
|
|
(iForcedClip != CLIP_FORCE))
|
|
{
|
|
// If the region is a single rectangle, the region bound IS the
|
|
// region, so we're done. Note that the trivial rejection case
|
|
// may come through this case -- it's the caller's responsibility
|
|
// to check that the rectangle is not empty.
|
|
|
|
if (iForcedClip != CLIP_NOFORCETRIV)
|
|
iDComplexity = DC_RECT;
|
|
|
|
return;
|
|
}
|
|
|
|
// Darn, now we have to do some real work.
|
|
|
|
ERECTL *percl = (ERECTL *) &rclBounds;
|
|
|
|
cObjs = 0; // Initialize object count
|
|
|
|
if (prgn->sizeRgn > QUANTUM_REGION_SIZE)
|
|
iFComplexity = FC_COMPLEX;
|
|
else
|
|
if (prgn->sizeRgn > SINGLE_REGION_SIZE)
|
|
iFComplexity = FC_RECT4;
|
|
|
|
// Traverse the scans
|
|
|
|
ERECTL erclAcc(0, 0, 0, 0); // Accumulate segments here
|
|
PSCAN pscn = prgn->pscnHead();
|
|
COUNT cScan = prgn->cScans;
|
|
COUNT iWall;
|
|
BOOL bSimple = (iForcedClip != CLIP_FORCE); // Assume DC_TRIVIAL clipping unless forced
|
|
|
|
COUNT cHit = 0;
|
|
|
|
// find the first one inside
|
|
|
|
while (cScan && (percl->top >= pscn->yBottom))
|
|
{
|
|
pscn = pscnGet(pscn);
|
|
--cScan;
|
|
}
|
|
|
|
while (cScan--)
|
|
{
|
|
if (pscn->yTop >= percl->bottom) // Have we passed the rectangle?
|
|
break;
|
|
|
|
BOOL bBounded = FALSE; // Assume rectangle is unbounded
|
|
|
|
for (iWall = 0; iWall != pscn->cWalls; iWall += 2)
|
|
{
|
|
// If the right edge of the segment is to the left of the rectangle
|
|
// advance to the next scan segment and test again.
|
|
|
|
if (pscn->ai_x[iWall + 1].x <= percl->left)
|
|
continue;
|
|
|
|
// If the left edge of the segment is to the right of the rectangle
|
|
// goto the next scan.
|
|
|
|
if (pscn->ai_x[iWall].x >= percl->right)
|
|
break;
|
|
|
|
// Increment count of objects
|
|
|
|
cObjs++;
|
|
|
|
// this is getting rediculous, we assume it is complex
|
|
|
|
if (cObjs >= CMAXOBJ)
|
|
{
|
|
iDComplexity = DC_COMPLEX;
|
|
cObjs = (COUNT)-1;
|
|
return;
|
|
}
|
|
|
|
// OK, we now know that SOME part of the rectangle overlaps
|
|
// this scan segment. Find the overlap and accumulate it.
|
|
|
|
RECTL rclTmp;
|
|
|
|
rclTmp.left = pscn->ai_x[iWall].x;
|
|
rclTmp.right = pscn->ai_x[iWall + 1].x;
|
|
rclTmp.top = pscn->yTop;
|
|
rclTmp.bottom = pscn->yBottom;
|
|
|
|
erclAcc += rclTmp; // Expand the accumlated rectangle
|
|
|
|
// Now see if this rectangle peeks out past the segment. If
|
|
// it doesn't, then we still might be simply clipped.
|
|
|
|
if ((percl->left >= pscn->ai_x[iWall].x) &&
|
|
(percl->right <= pscn->ai_x[iWall + 1].x))
|
|
{
|
|
bBounded = TRUE;
|
|
}
|
|
}
|
|
|
|
// If the rectangle was not left/right bounded by some segment in
|
|
// the scan, then this can't be a simple clip case.
|
|
|
|
bSimple &= bBounded;
|
|
|
|
pscn = pscnGet(pscn);
|
|
}
|
|
|
|
// Clip the exclusion rectangle against the accumulated rectangle
|
|
|
|
*percl *= erclAcc;
|
|
|
|
if (!bSimple)
|
|
{
|
|
iDComplexity = (BYTE)(cObjs == 1 ? DC_RECT : DC_COMPLEX);
|
|
}
|
|
else
|
|
{
|
|
if ((iForcedClip == CLIP_NOFORCE) && !percl->bEqual(erclExcl))
|
|
iDComplexity = DC_RECT;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ULONG XCLIPOBJ::cEnumStart(bAll, iType, iDir, cLimit)
|
|
*
|
|
* Set up the enumerator for the clipping object
|
|
*
|
|
* History:
|
|
* 24-Jul-1991 -by- Donald Sidoroff [donalds]
|
|
* Updated to DDI spec.
|
|
*
|
|
* 19-Sep-1990 -by- Donald Sidoroff [donalds]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
extern "C" ULONG CLIPOBJ_cEnumStart(
|
|
CLIPOBJ *pco,
|
|
BOOL bAll,
|
|
ULONG iType,
|
|
ULONG iDir,
|
|
ULONG cLimit)
|
|
{
|
|
return (*(XCLIPOBJ *)pco).cEnumStart(bAll, iType, iDir, cLimit);
|
|
}
|
|
|
|
|
|
ULONG XCLIPOBJ::cEnumStart(
|
|
BOOL bAll,
|
|
ULONG iType,
|
|
ULONG iDir,
|
|
ULONG cLimit)
|
|
{
|
|
// We may need to merge trapezoid region with the bounding rect if the flag
|
|
// indicate so.
|
|
|
|
// Handle any old direction requests
|
|
|
|
if (iDir == CD_ANY)
|
|
iDir = CD_RIGHTDOWN;
|
|
|
|
// Save the info in the enumerator
|
|
|
|
enmr.iType = iType;
|
|
enmr.iDir = iDir;
|
|
enmr.bAll = bAll;
|
|
|
|
// If we are enumerating the entire region, use the region bounding box
|
|
// otherwise use the exclusion rectangle
|
|
|
|
if (enmr.bAll)
|
|
enmr.ercl = *((ERECTL *) &prgn->rcl);
|
|
else
|
|
{
|
|
enmr.ercl = *((ERECTL *) &rclBounds);
|
|
}
|
|
|
|
// Now we have to do some actual work
|
|
// Set up top to bottom info
|
|
|
|
enmr.cScans = prgn->cScans - 1;
|
|
enmr.yCurr = 0;
|
|
enmr.yFinal = 0;
|
|
|
|
// Start from the top or bottom? Also, find the scan before the first scan
|
|
// that intersects the rclBounds. By finding the previous scan, we can let
|
|
// the normal enumeration find the first wall.
|
|
|
|
PSCAN pscn1;
|
|
|
|
if (iDir < CD_RIGHTUP)
|
|
{
|
|
// top to bottom
|
|
|
|
enmr.pscn = prgn->pscnHead();
|
|
enmr.yDelta = 1;
|
|
|
|
if (!enmr.bAll)
|
|
{
|
|
pscn1 = pscnGet(enmr.pscn);
|
|
|
|
while (pscn1->yBottom <= enmr.ercl.top)
|
|
{
|
|
--enmr.cScans;
|
|
|
|
if (enmr.cScans == 0)
|
|
return((ULONG)-1);
|
|
|
|
enmr.pscn = pscn1;
|
|
pscn1 = pscnGet(pscn1);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// bottom to top
|
|
|
|
enmr.pscn = pscnGot(prgn->pscnTail);
|
|
enmr.yDelta = -1;
|
|
|
|
if (!enmr.bAll)
|
|
{
|
|
pscn1 = pscnGot(enmr.pscn);
|
|
|
|
while (pscn1->yTop >= enmr.ercl.bottom)
|
|
{
|
|
--enmr.cScans;
|
|
|
|
if (enmr.cScans == 0)
|
|
return((ULONG)-1);
|
|
|
|
enmr.pscn = pscn1;
|
|
pscn1 = pscnGot(pscn1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Left to right info
|
|
|
|
enmr.iWall = 0;
|
|
enmr.iFinal = 0;
|
|
|
|
// Going left or right?
|
|
|
|
if (iDir & 1)
|
|
enmr.iOff = (COUNT) -2;
|
|
else
|
|
enmr.iOff = 2;
|
|
|
|
if (enmr.bAll)
|
|
return(cObjs <= cLimit ? cObjs : (ULONG) -1);
|
|
|
|
return((ULONG) -1);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ULONG XCLIPOBJ::cEnum(cj, pv)
|
|
*
|
|
* Get the next batch of rectangles or trapezoids from the clipping object
|
|
*
|
|
* History:
|
|
* 24-Jul-1991 -by- Donald Sidoroff [donalds]
|
|
* Updated to DDI spec.
|
|
*
|
|
* 15-Sep-1990 -by- Donald Sidoroff [donalds]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
extern "C" BOOL CLIPOBJ_bEnum(CLIPOBJ* pco, ULONG cj, ULONG *pv)
|
|
{
|
|
return (*(XCLIPOBJ *)pco).bEnum(cj, (VOID *)pv);
|
|
}
|
|
|
|
BOOL XCLIPOBJ::bEnum(ULONG cj,PVOID pv,ULONG *pcjFilled)
|
|
{
|
|
// Good old rectangle to rectangle enumeration
|
|
|
|
ENUMRECTS *penrc = (ENUMRECTS *) pv;
|
|
RECTL *prcl = penrc->arcl;
|
|
|
|
if (cj < sizeof(ENUMRECTS))
|
|
{
|
|
if (pcjFilled)
|
|
*pcjFilled = 0;
|
|
return FALSE;
|
|
}
|
|
|
|
cj -= offsetof(ENUMRECTS,arcl);
|
|
|
|
if (pcjFilled)
|
|
*pcjFilled = offsetof(ENUMRECTS,arcl);
|
|
|
|
penrc->c = 0;
|
|
|
|
if (enmr.bAll)
|
|
{
|
|
ULONG const RightToLeft = enmr.iDir & 1;
|
|
ULONG const TopToBottom = enmr.iDir < CD_RIGHTUP;
|
|
ULONG RectsWanted = cj / sizeof(RECTL);
|
|
PSCAN pCurrentScan = enmr.pscn;
|
|
COUNT CurrentWall = enmr.iWall;
|
|
COUNT FinalWall = enmr.iFinal;
|
|
int long Offset = enmr.iOff;
|
|
|
|
while (enmr.cScans)
|
|
{
|
|
if (CurrentWall == FinalWall)
|
|
{
|
|
// go to the next scan
|
|
|
|
if (TopToBottom)
|
|
pCurrentScan = pscnGet(pCurrentScan);
|
|
else
|
|
pCurrentScan = pscnGot(pCurrentScan);
|
|
|
|
enmr.cScans--;
|
|
|
|
if(!pCurrentScan->cWalls)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (RightToLeft)
|
|
{
|
|
CurrentWall = pCurrentScan->cWalls - 2;
|
|
FinalWall = (COUNT) -2;
|
|
}
|
|
else
|
|
{
|
|
CurrentWall = 0;
|
|
FinalWall = pCurrentScan->cWalls;
|
|
}
|
|
}
|
|
|
|
prcl->left = pCurrentScan->ai_x[CurrentWall].x;
|
|
prcl->right = pCurrentScan->ai_x[CurrentWall + 1].x;
|
|
prcl->top = pCurrentScan->yTop;
|
|
prcl->bottom = pCurrentScan->yBottom;
|
|
|
|
CurrentWall += Offset;
|
|
|
|
prcl++;
|
|
penrc->c++;
|
|
--RectsWanted;
|
|
|
|
if (pcjFilled)
|
|
*pcjFilled += sizeof(RECTL);
|
|
|
|
if (!RectsWanted)
|
|
{
|
|
// this is the only time we need to save state, no?
|
|
enmr.iWall = CurrentWall;
|
|
enmr.iFinal = FinalWall;
|
|
enmr.pscn = pCurrentScan;
|
|
return(TRUE);
|
|
}
|
|
}
|
|
}
|
|
else // and the not all case
|
|
{
|
|
|
|
ERECTL erclSrc;
|
|
erclSrc.top = enmr.pscn->yTop; // Reset source top
|
|
erclSrc.bottom = enmr.pscn->yBottom; // and bottom
|
|
|
|
while (enmr.cScans)
|
|
{
|
|
// do we need a new scan?
|
|
|
|
if (enmr.iWall == enmr.iFinal)
|
|
{
|
|
// go to the next scan and see if we are done
|
|
|
|
if (enmr.iDir < CD_RIGHTUP)
|
|
{
|
|
// top to bottom
|
|
|
|
if (enmr.pscn->yBottom >= enmr.ercl.bottom)
|
|
{
|
|
enmr.cScans = 0;
|
|
break;
|
|
}
|
|
enmr.pscn = pscnGet(enmr.pscn);
|
|
}
|
|
else
|
|
{
|
|
// bottom to top
|
|
|
|
if (enmr.pscn->yTop <= enmr.ercl.top)
|
|
{
|
|
enmr.cScans = 0;
|
|
break;
|
|
}
|
|
enmr.pscn = pscnGot(enmr.pscn);
|
|
}
|
|
|
|
enmr.cScans--;
|
|
|
|
// setup the scan
|
|
|
|
erclSrc.top = enmr.pscn->yTop; // Reset source top
|
|
erclSrc.bottom = enmr.pscn->yBottom; // and bottom
|
|
|
|
// find the first rectangle within the scan
|
|
|
|
if (enmr.iDir & 1)
|
|
{
|
|
// right to left
|
|
|
|
enmr.iWall = enmr.pscn->cWalls - 2;
|
|
enmr.iFinal = (COUNT) -2;
|
|
|
|
while ((enmr.iWall != -2) &&
|
|
(enmr.pscn->ai_x[enmr.iWall].x >= enmr.ercl.right))
|
|
{
|
|
enmr.iWall -= 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// left to right
|
|
|
|
enmr.iWall = 0;
|
|
enmr.iFinal = enmr.pscn->cWalls;
|
|
|
|
while ((enmr.iWall != enmr.iFinal) &&
|
|
(enmr.pscn->ai_x[enmr.iWall+1].x <= enmr.ercl.left))
|
|
{
|
|
enmr.iWall += 2;
|
|
}
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
// get the left and right from the scan
|
|
|
|
erclSrc.left = enmr.pscn->ai_x[enmr.iWall].x;
|
|
erclSrc.right = enmr.pscn->ai_x[enmr.iWall + 1].x;
|
|
|
|
// intersect the side walls. If the rectangles don't overlap, we
|
|
// are done with this scan.
|
|
|
|
prcl->left = max(enmr.ercl.left,erclSrc.left);
|
|
prcl->right = min(enmr.ercl.right,erclSrc.right);
|
|
|
|
if (prcl->left >= prcl->right)
|
|
{
|
|
enmr.iWall = enmr.iFinal;
|
|
continue;
|
|
}
|
|
|
|
// compute the top and bottom - these should be moved out of inner loop(erick)
|
|
|
|
prcl->top = max(enmr.ercl.top,erclSrc.top);
|
|
prcl->bottom = min(enmr.ercl.bottom,erclSrc.bottom);
|
|
|
|
ASSERTGDI(prcl->top < prcl->bottom,"CLIPOBJ_benum, top >= bottom\n");
|
|
|
|
// advance to the next rectangle
|
|
|
|
enmr.iWall += enmr.iOff;
|
|
|
|
prcl++;
|
|
cj -= sizeof(RECTL);
|
|
|
|
if (pcjFilled)
|
|
*pcjFilled += sizeof(RECTL);
|
|
|
|
penrc->c++;
|
|
|
|
if (cj < sizeof(RECTL))
|
|
return(TRUE);
|
|
}
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* PATHOBJ *XCLIPOBJ::ppoGetPath()
|
|
*
|
|
* Create PATHOBJ from the clipping region.
|
|
*
|
|
* NOTE: This does NOT take the multi-monitor offset into account, so this
|
|
* may not be used by display drivers.
|
|
*
|
|
* History:
|
|
* 09-Mar-1992 -by- Donald Sidoroff [donalds]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
extern "C" PATHOBJ *CLIPOBJ_ppoGetPath(CLIPOBJ *pco)
|
|
{
|
|
return (*(XCLIPOBJ*)pco).ppoGetPath();
|
|
}
|
|
|
|
|
|
PATHOBJ *XCLIPOBJ::ppoGetPath()
|
|
{
|
|
// Allocate a PATHOBJ from the heap. We will free this memory only if
|
|
// this function fails. Otherwise, we will rely on the device driver to
|
|
// call EngDeletePath later on to free the memory.
|
|
|
|
PVOID pepo = PALLOCNOZ(sizeof(EPATHOBJ),'oppG');
|
|
if (pepo == (PVOID) NULL)
|
|
{
|
|
return((PATHOBJ *) NULL);
|
|
}
|
|
|
|
// Sigh, we have to create a path for this region.
|
|
|
|
PATHMEMOBJ pmo;
|
|
if (!pmo.bValid())
|
|
{
|
|
VFREEMEM(pepo);
|
|
return(NULL);
|
|
}
|
|
|
|
EXFORMOBJ exo(IDENTITY);
|
|
ASSERTGDI(exo.bValid(), "Invalid Identity transform");
|
|
|
|
{
|
|
// pmoRect will contain an intermediate rectangular path that will
|
|
// in turn be processed into a diagonalized path that will be
|
|
// contained in pmo.
|
|
|
|
RTP_PATHMEMOBJ pmoRect;
|
|
if
|
|
(
|
|
!pmoRect.bValid() ||
|
|
!bCreate(pmoRect, &exo) ||
|
|
!pmoRect.bDiagonalizePath(&pmo)
|
|
)
|
|
{
|
|
VFREEMEM(pepo);
|
|
return(NULL);
|
|
}
|
|
// pmoRect passes out of scope. Since I have NOT called
|
|
// pmoRect.vKeepIt() the memory of the rectangular path will
|
|
// be freed, while the diagonalized path as embodied in pmo
|
|
// will live on.
|
|
}
|
|
|
|
// OK, nothing can fail now. We will keep the diagonalized path
|
|
// by marking it as permanent. We will allow the destructor to
|
|
// kill the rectangular path in pmo.
|
|
|
|
pmo.vKeepIt();
|
|
|
|
// Make sure we copy the accelerator fields to the path we'll be
|
|
// giving out:
|
|
|
|
*((EPATHOBJ*) pepo) = pmo;
|
|
|
|
// Now lock down the object and point our path to it:
|
|
|
|
((EPATHOBJ *) pepo)->vLock(pmo.hpath());
|
|
|
|
return((PATHOBJ *) pepo);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID XCLIPOBJ::vFindScan(prcl, y)
|
|
*
|
|
* Search for the scan that contains the given point
|
|
*
|
|
* History:
|
|
* 13-Aug-1992 -by- Donald Sidoroff [donalds]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID XCLIPOBJ::vFindScan(
|
|
RECTL *prcl,
|
|
LONG y)
|
|
{
|
|
if (y < enmr.pscn->yTop)
|
|
{
|
|
while (y < enmr.pscn->yTop)
|
|
enmr.pscn = pscnGot(enmr.pscn);
|
|
|
|
prcl->top = max(enmr.pscn->yTop, rclBounds.top);
|
|
prcl->bottom = min(enmr.pscn->yBottom, rclBounds.bottom);
|
|
prcl->left = prcl->right;
|
|
|
|
if (prcl->top >= prcl->bottom)
|
|
prcl->top = NEG_INFINITY;
|
|
|
|
if (prcl->top == NEG_INFINITY)
|
|
prcl->bottom = NEG_INFINITY;
|
|
}
|
|
else if (y >= enmr.pscn->yBottom)
|
|
{
|
|
while (y >= enmr.pscn->yBottom)
|
|
enmr.pscn = pscnGet(enmr.pscn);
|
|
|
|
prcl->top = max(enmr.pscn->yTop, rclBounds.top);
|
|
prcl->bottom = min(enmr.pscn->yBottom, rclBounds.bottom);
|
|
prcl->left = prcl->right;
|
|
|
|
if (prcl->top >= prcl->bottom)
|
|
prcl->bottom = POS_INFINITY;
|
|
|
|
if (prcl->bottom == POS_INFINITY)
|
|
prcl->top = POS_INFINITY;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID XCLIPOBJ::vFindSegment(prcl, x, y)
|
|
*
|
|
* Search for the segment in the current scan that contains the given point
|
|
*
|
|
* History:
|
|
* 13-Aug-1992 -by- Donald Sidoroff [donalds]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID XCLIPOBJ::vFindSegment(
|
|
RECTL *prcl,
|
|
LONG x,
|
|
LONG y)
|
|
{
|
|
DONTUSE(y);
|
|
|
|
COUNT iWall;
|
|
LONG xLeft;
|
|
LONG xRight;
|
|
|
|
for (iWall = 0; iWall != enmr.pscn->cWalls; iWall += 2)
|
|
{
|
|
if ((x >= enmr.pscn->ai_x[iWall].x) &&
|
|
(x < enmr.pscn->ai_x[iWall + 1].x))
|
|
{
|
|
xLeft = max(enmr.pscn->ai_x[iWall].x, rclBounds.left);
|
|
xRight = min(enmr.pscn->ai_x[iWall + 1].x, rclBounds.right);
|
|
|
|
if (xLeft < xRight)
|
|
{
|
|
prcl->left = xLeft;
|
|
prcl->right = xRight;
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|