📄 winrgn.c
字号:
* this may be pointless -- see above).
*/
temp = region->tail;
while (temp->prev->rc.top == temp->rc.top) {
temp = temp->prev;
}
newStart = temp;
}
if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
pCurRect = curStart;
/*
* The bands may only be coalesced if the bottom of the previous
* matches the top scanline of the current.
*/
if (pPrevRect->rc.bottom == pCurRect->rc.top) {
/*
* Make sure the bands have rects in the same places. This
* assumes that rects have been added in such a way that they
* cover the most area possible. I.e. two rects in a band must
* have some horizontal space between them.
*/
do {
if ((pPrevRect->rc.left != pCurRect->rc.left) ||
(pPrevRect->rc.right != pCurRect->rc.right))
{
/*
* The bands don't line up so they can't be coalesced.
*/
return newStart;
}
pPrevRect = pPrevRect->next;
pCurRect = pCurRect->next;
} while (--prevNumRects);
/*
* If only one band was added to the region, we have to backup
* newStart to the start of the previous band.
*/
if (pCurRect == NULL) {
newStart = prevStart;
}
/*
* The bands may be merged, so set the bottom of each rect
* in the previous band to that of the corresponding rect in
* the current band.
*/
/*
* free the clipping rects merged.
*/
pCurRect = curStart;
pPrevRect = prevStart;
do {
pPrevRect->rc.bottom = pCurRect->rc.bottom;
pPrevRect = pPrevRect->next;
if (pCurRect->next)
pCurRect->next->prev = pCurRect->prev;
else
region->tail = pCurRect->prev;
if (pCurRect->prev)
pCurRect->prev->next = pCurRect->next;
else
region->head = pCurRect->next;
temp = pCurRect->next;
FreeClipRect (region->heap, pCurRect);
pCurRect = temp;
} while (--curNumRects);
}
}
return (newStart);
}
/***********************************************************************
* REGION_RegionOp
*
* Apply an operation to two regions. Called by Union,
* Xor, Subtract, Intersect...
*
* Results:
* None.
*
* Side Effects:
* The new region is overwritten.
*
* Notes:
* The idea behind this function is to view the two regions as sets.
* Together they cover a rectangle of area that this function divides
* into horizontal bands where points are covered only by one region
* or by both. For the first case, the nonOverlapFunc is called with
* each the band and the band's upper and lower rcBound. For the
* second, the overlapFunc is called to process the entire band. It
* is responsible for clipping the rectangles in the band, though
* this function provides the boundaries.
* At the end of each band, the new region is coalesced, if possible,
* to reduce the number of rectangles in the region.
*
*/
static void
REGION_RegionOp(
TREGION *newReg, /* Place to store result */
const TREGION *reg1, /* First region in operation */
const TREGION *reg2, /* 2nd region in operation */
voidProcp1 overlapFunc, /* Function to call for over-lapping bands */
voidProcp2 nonOverlap1Func, /* Function to call for non-overlapping bands in region 1 */
voidProcp2 nonOverlap2Func /* Function to call for non-overlapping bands in region 2 */
) { TREGION my_dst;
TREGION* pdst;
const TClipRect *r1; /* Pointer into first region */
const TClipRect *r2; /* Pointer into 2d region */
const TClipRect *r1BandEnd; /* End of current band in r1 */
const TClipRect *r2BandEnd; /* End of current band in r2 */
int ybot; /* Bottom of intersection */
int ytop; /* Top of intersection */
TClipRect * prevBand; /* start of previous band in newReg */
TClipRect * curBand; /* start of current band in newReg */
int top; /* Top of non-overlapping band */
int bot; /* Bottom of non-overlapping band */
/*
* Initialization:
* set r1, r2, r1End and r2End appropriately, preserve the important
* parts of the destination region until the end in case it's one of
* the two source regions, then mark the "new" region empty, allocating
* another array of rectangles for it to use.
*/
r1 = reg1->head;
r2 = reg2->head;
if (newReg == reg1 || newReg == reg2) {
InitRegion (&my_dst, newReg->heap);
pdst = &my_dst;
}
else
{ if(newReg->head) ClearRegion (newReg);
pdst = newReg;
}
/*
* Initialize ybot and ytop.
* In the upcoming loop, ybot and ytop serve different functions depending
* on whether the band being handled is an overlapping or non-overlapping
* band.
* In the case of a non-overlapping band (only one of the regions
* has points in the band), ybot is the bottom of the most recent
* intersection and thus clips the top of the rectangles in that band.
* ytop is the top of the next intersection between the two regions and
* serves to clip the bottom of the rectangles in the current band.
* For an overlapping band (where the two regions intersect), ytop clips
* the top of the rectangles of both regions and ybot clips the bottoms.
*/
if (reg1->rcBound.top < reg2->rcBound.top)
ybot = reg1->rcBound.top;
else
ybot = reg2->rcBound.top;
/*
* prevBand serves to mark the start of the previous band so rectangles
* can be coalesced into larger rectangles. qv. miCoalesce, above.
* In the beginning, there is no previous band, so prevBand == curBand
* (curBand is set later on, of course, but the first band will always
* start at index 0). prevBand and curBand must be indices because of
* the possible expansion, and resultant moving, of the new region's
* array of rectangles.
*/
prevBand = pdst->head;
do {
curBand = pdst->tail;
/*
* This algorithm proceeds one source-band (as opposed to a
* destination band, which is determined by where the two regions
* intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
* rectangle after the last one in the current band for their
* respective regions.
*/
r1BandEnd = r1;
while (r1BandEnd && (r1BandEnd->rc.top == r1->rc.top))
r1BandEnd = r1BandEnd->next;
r2BandEnd = r2;
while (r2BandEnd && (r2BandEnd->rc.top == r2->rc.top))
r2BandEnd = r2BandEnd->next;
/*
* First handle the band that doesn't intersect, if any.
*
* Note that attention is restricted to one band in the
* non-intersecting region at once, so if a region has n
* bands between the current position and the next place it overlaps
* the other, this entire loop will be passed through n times.
*/
if (r1->rc.top < r2->rc.top) {
top = max (r1->rc.top, ybot);
bot = min (r1->rc.bottom, r2->rc.top);
if ((top != bot) && (nonOverlap1Func != NULL))
(* nonOverlap1Func) (pdst, r1, r1BandEnd, top, bot);
ytop = r2->rc.top;
}
else if (r2->rc.top < r1->rc.top) {
top = max (r2->rc.top, ybot);
bot = min (r2->rc.bottom, r1->rc.top);
if ((top != bot) && (nonOverlap2Func != NULL))
(* nonOverlap2Func) (pdst, r2, r2BandEnd, top, bot);
ytop = r1->rc.top;
}
else {
ytop = r1->rc.top;
}
/*
* If any rectangles got added to the region, try and coalesce them
* with rectangles from the previous band. Note we could just do
* this test in miCoalesce, but some machines incur a not
* inconsiderable cost for function calls, so...
*/
if (pdst->tail != curBand) {
prevBand = REGION_Coalesce (pdst, prevBand, curBand);
}
/*
* Now see if we've hit an intersecting band. The two bands only
* intersect if ybot > ytop
*/
ybot = min (r1->rc.bottom, r2->rc.bottom);
curBand = pdst->tail;
if (ybot > ytop)
(* overlapFunc) (pdst, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
if (pdst->tail != curBand)
prevBand = REGION_Coalesce (pdst, prevBand, curBand);
/*
* If we've finished with a band (bottom == ybot) we skip forward
* in the region to the next band.
*/
if (r1->rc.bottom == ybot)
r1 = r1BandEnd;
if (r2->rc.bottom == ybot)
r2 = r2BandEnd;
} while (r1 && r2);
/*
* Deal with whichever region still has rectangles left.
*/
curBand = pdst->tail;
if (r1) {
if (nonOverlap1Func != NULL) {
do {
r1BandEnd = r1;
while ((r1BandEnd) && (r1BandEnd->rc.top == r1->rc.top)) {
r1BandEnd = r1BandEnd->next;
}
(* nonOverlap1Func) (pdst, r1, r1BandEnd,
max (r1->rc.top, ybot), r1->rc.bottom);
r1 = r1BandEnd;
} while (r1);
}
}
else if ((r2) && (nonOverlap2Func != NULL))
{
do {
r2BandEnd = r2;
while ((r2BandEnd) && (r2BandEnd->rc.top == r2->rc.top)) {
r2BandEnd = r2BandEnd->next;
}
(* nonOverlap2Func) (pdst, r2, r2BandEnd,
max (r2->rc.top, ybot), r2->rc.bottom);
r2 = r2BandEnd;
} while (r2);
}
if (pdst->tail != curBand)
(void) REGION_Coalesce (pdst, prevBand, curBand);
if (pdst != newReg)
{ ClearRegion (newReg);
*newReg = my_dst;
}
}
/***********************************************************************
* Region Intersection
***********************************************************************/
/***********************************************************************
* REGION_IntersectO
*
* Handle an overlapping band for REGION_Intersect.
*
* Results:
* None.
*
* Side Effects:
* Rectangles may be added to the region.
*
*/
static void REGION_IntersectO (TREGION *region, const TClipRect *r1, const TClipRect *r1End,
const TClipRect *r2, const TClipRect *r2End, int top, int bottom)
{
int left, right;
TClipRect *newcliprect;
while ((r1 != r1End) && (r2 != r2End))
{
left = max (r1->rc.left, r2->rc.left);
right = min (r1->rc.right, r2->rc.right);
/*
* If there's any overlap between the two rectangles, add that
* overlap to the new region.
* There's no need to check for subsumption because the only way
* such a need could arise is if some region has two rectangles
* right next to each other. Since that should never happen...
*/
if (left < right) {
NEWCLIPRECT (region, newcliprect);
newcliprect->rc.left = left;
newcliprect->rc.top = top;
newcliprect->rc.right = right;
newcliprect->rc.bottom = bottom;
}
/*
* Need to advance the pointers. Shift the one that extends
* to the right the least, since the other still has a chance to
* overlap with that region's next rectangle, if you see what I mean.
*/
if (r1->rc.right < r2->rc.right) {
r1 = r1->next;
}
else if (r2->rc.right < r1->rc.right) {
r2 = r2->next;
}
else {
r1 = r1->next;
r2 = r2->next;
}
}
}
/***********************************************************************
* Region Union
***********************************************************************/
/***********************************************************************
* REGION_UnionNonO
*
* Handle a non-overlapping band for the union operation. Just
* Adds the rectangles into the region. Doesn't have to check for
* subsumption or anything.
*
* Results:
* None.
*
* Side Effects:
* region->numRects is incremented and the final rectangles overwritten
* with the rectangles we're passed.
*
*/
static void REGION_UnionNonO (TREGION *region, const TClipRect *r, const TClipRect *rEnd, int top, int bottom)
{
TClipRect *newcliprect;
while (r != rEnd) {
NEWCLIPRECT (region, newcliprect);
newcliprect->rc.left = r->rc.left;
newcliprect->rc.top = top;
newcliprect->rc.right = r->rc.right;
newcliprect->rc.bottom = bottom;
r = r->next;
}
}
/***********************************************************************
* REGION_UnionO
*
* Handle an overlapping band for the union operation. Picks the
* left-most rectangle each time and merges it into the region.
*
* Results:
* None.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -