1616 lines
30 KiB
C
1616 lines
30 KiB
C
/*
|
|
* Copyright (c) 1998 by The XFree86 Project, Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
|
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
* Except as contained in this notice, the name of the XFree86 Project shall
|
|
* not be used in advertising or otherwise to promote the sale, use or other
|
|
* dealings in this Software without prior written authorization from the
|
|
* XFree86 Project.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
#include <stdlib.h>
|
|
|
|
#include <X11/IntrinsicP.h>
|
|
#include <X11/Xmu/Xmu.h>
|
|
|
|
#define XmuMax(a, b) ((a) > (b) ? (a) : (b))
|
|
#define XmuMin(a, b) ((a) < (b) ? (a) : (b))
|
|
|
|
/*
|
|
* Function:
|
|
* XmuNewArea
|
|
*
|
|
* Parameters:
|
|
* x1 - Coordinates of the rectangle
|
|
* y1 - ""
|
|
* x2 - ""
|
|
* y2 - ""
|
|
*
|
|
* Description:
|
|
* Creates a new rectangular clipping area
|
|
*/
|
|
XmuArea *
|
|
XmuNewArea(int x1, int y1, int x2, int y2)
|
|
{
|
|
XmuArea *area;
|
|
|
|
area = (XmuArea *)XtMalloc(sizeof(XmuArea));
|
|
if (x2 > x1 && y2 > y1)
|
|
{
|
|
area->scanline = XmuNewScanline(y1, x1, x2);
|
|
area->scanline->next = XmuNewScanline(y2, 0, 0);
|
|
}
|
|
else
|
|
area->scanline = (XmuScanline *)NULL;
|
|
|
|
return (area);
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* XmuAreaDup
|
|
*
|
|
* Parameters:
|
|
* area - Area to copy
|
|
*
|
|
* Description:
|
|
* Returns a copy of its argument
|
|
*/
|
|
XmuArea *
|
|
XmuAreaDup(XmuArea *area)
|
|
{
|
|
XmuArea *dst;
|
|
|
|
if (!area)
|
|
return ((XmuArea *)NULL);
|
|
|
|
dst = XmuCreateArea();
|
|
XmuAreaCopy(dst, area);
|
|
return (dst);
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* XmuAreaCopy
|
|
*
|
|
* Parameters:
|
|
* dst - destination area
|
|
* src - source area
|
|
*
|
|
* Description:
|
|
* Minimizes memory allocation, trying to use already allocated memory
|
|
* in dst, freeing what is not required anymore.
|
|
*/
|
|
XmuArea *
|
|
XmuAreaCopy(XmuArea *dst, XmuArea *src)
|
|
{
|
|
XmuScanline *z, *p, *Z;
|
|
|
|
if (!dst || !src || dst == src)
|
|
return (dst);
|
|
|
|
z = p = dst->scanline;
|
|
Z = src->scanline;
|
|
|
|
/*CONSTCOND*/
|
|
while (1)
|
|
{
|
|
if (!Z)
|
|
{
|
|
if (z == dst->scanline)
|
|
{
|
|
XmuDestroyScanlineList(dst->scanline);
|
|
dst->scanline = (XmuScanline *)NULL;
|
|
}
|
|
else
|
|
{
|
|
XmuDestroyScanlineList(p->next);
|
|
p->next = (XmuScanline *)NULL;
|
|
}
|
|
return (dst);
|
|
}
|
|
if (z)
|
|
{
|
|
XmuScanlineCopy(z, Z);
|
|
z->y = Z->y;
|
|
}
|
|
else
|
|
{
|
|
z = XmuNewScanline(Z->y, 0, 0);
|
|
XmuScanlineCopy(z, Z);
|
|
if (p == dst->scanline && !dst->scanline)
|
|
p = dst->scanline = z;
|
|
else
|
|
p->next = z;
|
|
}
|
|
p = z;
|
|
z = z->next;
|
|
Z = Z->next;
|
|
}
|
|
|
|
return (dst);
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* XmuAreaNot
|
|
*
|
|
* Parameters:
|
|
* area - area to operate
|
|
* x1 - retangle to clip the result against
|
|
* y1 - ""
|
|
* x2 - ""
|
|
* y2 - ""
|
|
*
|
|
* Description:
|
|
* (Input)
|
|
* (x1, y1) (x2, y1)
|
|
* +-------------+
|
|
* +------------+ +----+
|
|
* | +--------------+
|
|
* +----------------+
|
|
* (x1, y2) (x2, y2)
|
|
*
|
|
* (Output)
|
|
* (x1, y1) (x2, y1)
|
|
* +--------------+ +--------------------------+
|
|
* | +------------+ +----+ |
|
|
* | | +--------------+ |
|
|
* +-+ +------------------------------------+
|
|
* (x1, y2) (x2, y2)
|
|
*/
|
|
XmuArea *
|
|
XmuAreaNot(XmuArea *area, int x1, int y1, int x2, int y2)
|
|
{
|
|
XmuScanline *z;
|
|
XmuArea *and;
|
|
|
|
if (!area)
|
|
return (area);
|
|
|
|
if (x1 > x2)
|
|
{
|
|
x1 ^= x2; x2 ^= x1; x1 ^= x2;
|
|
}
|
|
if (y1 > y2)
|
|
{
|
|
y1 ^= y2; y2 ^= y1; y1 ^= y2;
|
|
}
|
|
if (!area->scanline)
|
|
{
|
|
if ((area->scanline = XmuNewScanline(y1, x1, x2)) != NULL)
|
|
area->scanline->next = XmuNewScanline(y2, 0, 0);
|
|
return (area);
|
|
}
|
|
and = XmuNewArea(x1, y1, x2, y2);
|
|
XmuAreaAnd(area, and);
|
|
XmuDestroyArea(and);
|
|
z = area->scanline;
|
|
if (z->y != y1)
|
|
{
|
|
XmuScanline *q = XmuNewScanline(y1, x1, x2);
|
|
q->next = z;
|
|
area->scanline = q;
|
|
}
|
|
else
|
|
{
|
|
area->scanline = area->scanline->next;
|
|
XmuDestroyScanline(z);
|
|
XmuOptimizeArea(area);
|
|
if((z = area->scanline) == (XmuScanline *)NULL)
|
|
return (area);
|
|
}
|
|
|
|
/* CONSTCOND */
|
|
while (1)
|
|
{
|
|
XmuScanlineNot(z, x1, x2);
|
|
if (!z->next)
|
|
{
|
|
z->next = XmuNewScanline(y2, 0, 0);
|
|
break;
|
|
}
|
|
if (z->next->y == y2)
|
|
{
|
|
XmuDestroyScanlineList(z->next);
|
|
z->next = XmuNewScanline(y2, 0, 0);
|
|
break;
|
|
}
|
|
z = z->next;
|
|
}
|
|
|
|
return (area);
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* XmuAreaOrXor
|
|
*
|
|
* Parameters:
|
|
* dst - destination area
|
|
* src - source area
|
|
* or - or operation if true, else xor operation
|
|
*
|
|
* Description:
|
|
* Executes Or (Union) or Xor (Reverse intersection) of the areas
|
|
*/
|
|
XmuArea *
|
|
XmuAreaOrXor(XmuArea *dst, XmuArea *src, Bool or)
|
|
{
|
|
XmuScanline *z, *p, *Z, *P, *ins, *top;
|
|
|
|
if (!dst || !src)
|
|
return (dst);
|
|
|
|
if (dst == src)
|
|
{
|
|
if (or)
|
|
return (dst);
|
|
XmuDestroyScanlineList(dst->scanline);
|
|
dst->scanline = (XmuScanline *)NULL;
|
|
return (dst);
|
|
}
|
|
if (!XmuValidArea(src))
|
|
return (dst);
|
|
if (!XmuValidArea(dst))
|
|
{
|
|
XmuAreaCopy(dst, src);
|
|
return (dst);
|
|
}
|
|
|
|
p = z = dst->scanline;
|
|
P = Z = src->scanline;
|
|
ins = XmuNewScanline(dst->scanline->y, 0, 0);
|
|
top = XmuNewScanline(dst->scanline->y, 0, 0);
|
|
XmuScanlineCopy(ins, dst->scanline);
|
|
XmuScanlineCopy(top, dst->scanline);
|
|
|
|
/*CONSTCOND*/
|
|
while (1)
|
|
{
|
|
if (!Z)
|
|
break;
|
|
else if (Z->y < z->y)
|
|
{
|
|
XmuScanline *q = XmuNewScanline(Z->y, 0, 0);
|
|
XmuScanlineCopy(q, Z);
|
|
|
|
if (z == dst->scanline)
|
|
{
|
|
dst->scanline = p = q;
|
|
q->next = z;
|
|
}
|
|
else
|
|
{
|
|
p->next = q;
|
|
q->next = z;
|
|
if (Z->y >= p->y)
|
|
{
|
|
if (ins->y >= top->y
|
|
&& (p->y != P->y || !XmuScanlineEqu(p, P)
|
|
|| (ins->y <= P->y && !XmuScanlineEqu(ins, P))))
|
|
{
|
|
if (or)
|
|
XmuScanlineOr(q, ins);
|
|
else
|
|
XmuScanlineXor(q, ins);
|
|
}
|
|
else if (Z->y >= top->y
|
|
&& (top->y == p->y || top->y > ins->y
|
|
|| !XmuValidScanline(Z)
|
|
|| (p->y == P->y && XmuValidScanline(p)
|
|
&& XmuValidScanline(P))
|
|
|| XmuScanlineEqu(ins, top)))
|
|
{
|
|
if (or)
|
|
XmuScanlineOr(q, top);
|
|
else
|
|
XmuScanlineXor(q, top);
|
|
}
|
|
if (ins->y != p->y && p->y != P->y)
|
|
{
|
|
XmuScanlineCopy(ins, p);
|
|
ins->y = p->y;
|
|
}
|
|
}
|
|
if (!XmuValidScanline(p) || Z->y <= p->y)
|
|
{
|
|
XmuScanlineCopy(top, p);
|
|
top->y = p->y;
|
|
}
|
|
p = q;
|
|
}
|
|
P = Z;
|
|
Z = Z->next;
|
|
continue;
|
|
}
|
|
else if (Z->y == z->y)
|
|
{
|
|
if (top->y != z->y)
|
|
{
|
|
XmuScanlineCopy(top, z);
|
|
top->y = z->y;
|
|
}
|
|
if (or)
|
|
XmuScanlineOr(z, Z);
|
|
else
|
|
XmuScanlineXor(z, Z);
|
|
P = Z;
|
|
Z = Z->next;
|
|
}
|
|
else if (P != Z) /* && Z->y > z->y */
|
|
{
|
|
if (top->y == ins->y && top->y != z->y)
|
|
{
|
|
XmuScanlineCopy(top, z);
|
|
top->y = z->y;
|
|
}
|
|
if (ins->y != z->y)
|
|
{
|
|
XmuScanlineCopy(ins, z);
|
|
ins->y = z->y;
|
|
}
|
|
if (or)
|
|
XmuScanlineOr(z, P);
|
|
else
|
|
XmuScanlineXor(z, P);
|
|
}
|
|
else if (ins->y != z->y)
|
|
{
|
|
XmuScanlineCopy(ins, z);
|
|
ins->y = z->y;
|
|
}
|
|
p = z;
|
|
z = z->next;
|
|
if (!z)
|
|
{
|
|
while (Z)
|
|
{
|
|
p->next = XmuNewScanline(Z->y, 0, 0);
|
|
XmuScanlineCopy(p->next, Z);
|
|
p = p->next;
|
|
Z = Z->next;
|
|
}
|
|
break;
|
|
}
|
|
else if (ins->y > top->y && !XmuValidScanline(z)
|
|
&& XmuValidScanline(ins))
|
|
{
|
|
XmuScanlineCopy(top, ins);
|
|
top->y = ins->y;
|
|
}
|
|
}
|
|
XmuOptimizeArea(dst);
|
|
XmuDestroyScanline(ins);
|
|
XmuDestroyScanline(top);
|
|
|
|
return (dst);
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* XmuAreaAnd(dst, src)
|
|
*
|
|
* Parameters:
|
|
* dst - destination area
|
|
* src - source area
|
|
*
|
|
* Description:
|
|
* Executes And (intersection) of the areas
|
|
*/
|
|
XmuArea *
|
|
XmuAreaAnd(XmuArea *dst, XmuArea *src)
|
|
{
|
|
XmuScanline *z, *p, *Z, *P, *top;
|
|
|
|
if (!dst || !src || dst == src)
|
|
return (dst);
|
|
if (!XmuValidArea(dst) || !XmuValidArea(src))
|
|
{
|
|
XmuDestroyScanlineList(dst->scanline);
|
|
dst->scanline = (XmuScanline *)NULL;
|
|
return (dst);
|
|
}
|
|
z = p = dst->scanline;
|
|
Z = P = src->scanline;
|
|
top = XmuNewScanline(dst->scanline->y, 0, 0);
|
|
XmuScanlineCopy(top, dst->scanline);
|
|
|
|
while (z)
|
|
{
|
|
while (Z->next && Z->next->y < z->y)
|
|
{
|
|
P = Z;
|
|
Z = Z->next;
|
|
if (Z->y >= p->y)
|
|
{
|
|
XmuScanline *q = XmuNewScanline(Z->y, 0, 0);
|
|
XmuScanlineCopy(q, Z);
|
|
|
|
XmuScanlineAnd(q, top);
|
|
if (p->y != P->y)
|
|
{
|
|
XmuScanlineAnd(p, P);
|
|
p->y = XmuMax(p->y, P->y);
|
|
}
|
|
p->next = q;
|
|
q->next = z;
|
|
p = q;
|
|
}
|
|
}
|
|
if (!z->next)
|
|
{
|
|
z->y = XmuMax(z->y, Z->y);
|
|
break;
|
|
}
|
|
while (Z->y >= z->next->y)
|
|
{
|
|
if (z == dst->scanline)
|
|
{
|
|
p = dst->scanline = dst->scanline->next;
|
|
XmuDestroyScanline(z);
|
|
z = dst->scanline;
|
|
}
|
|
else
|
|
{
|
|
p->next = z->next;
|
|
XmuDestroyScanline(z);
|
|
z = p;
|
|
}
|
|
if (!z || !z->next)
|
|
{
|
|
XmuOptimizeArea(dst);
|
|
XmuDestroyScanline(top);
|
|
|
|
return (dst);
|
|
}
|
|
}
|
|
if (Z->y > p->y)
|
|
z->y = XmuMax(z->y, Z->y);
|
|
if (top->y != z->y)
|
|
{
|
|
XmuScanlineCopy(top, z);
|
|
top->y = z->y;
|
|
}
|
|
XmuScanlineAnd(z, Z);
|
|
p = z;
|
|
z = z->next;
|
|
}
|
|
XmuOptimizeArea(dst);
|
|
XmuDestroyScanline(top);
|
|
|
|
return (dst);
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* XmuValidArea(area)
|
|
*
|
|
* Parameters:
|
|
* area - area to verify
|
|
*
|
|
* Description:
|
|
* Verifies if the area is valid and/or useful
|
|
*/
|
|
Bool
|
|
XmuValidArea(XmuArea *area)
|
|
{
|
|
XmuScanline *at;
|
|
|
|
if (!area || !area->scanline)
|
|
return (False);
|
|
|
|
at = area->scanline;
|
|
while (at)
|
|
{
|
|
if (XmuValidScanline(at))
|
|
return (True);
|
|
at = at->next;
|
|
}
|
|
|
|
return (False);
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* XmuValidScanline
|
|
*
|
|
* Parameters:
|
|
* scanline - scanline to verify
|
|
*
|
|
* Description:
|
|
* Verifies if a scanline is useful
|
|
*/
|
|
Bool
|
|
XmuValidScanline(XmuScanline *scanline)
|
|
{
|
|
XmuSegment *z;
|
|
|
|
if (!scanline)
|
|
return (False);
|
|
|
|
z = scanline->segment;
|
|
while (z)
|
|
{
|
|
if (XmuValidSegment(z))
|
|
return (True);
|
|
z = z->next;
|
|
}
|
|
|
|
return (False);
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* XmuScanlineEqu
|
|
*
|
|
* Parameters:
|
|
* s1 - scanline 1
|
|
* s2 - scanline 2
|
|
*
|
|
* Description:
|
|
* Checks if s1 and s2 are equal
|
|
*/
|
|
Bool
|
|
XmuScanlineEqu(XmuScanline *s1, XmuScanline *s2)
|
|
{
|
|
XmuSegment *z, *Z;
|
|
|
|
if ((!s1 && !s2) || s1 == s2)
|
|
return (True);
|
|
if (!s1 || !s2)
|
|
return (False);
|
|
|
|
z = s1->segment;
|
|
Z = s2->segment;
|
|
|
|
/*CONSTCOND*/
|
|
while (1)
|
|
{
|
|
if (!z && !Z)
|
|
return (True);
|
|
if (!z || !Z)
|
|
return (False);
|
|
if (!XmuSegmentEqu(z, Z))
|
|
return (False);
|
|
z = z->next;
|
|
Z = Z->next;
|
|
}
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* XmuNewSegment
|
|
*
|
|
* Parameters:
|
|
* x1 - coordinates of the segment
|
|
* x2 - ""
|
|
*
|
|
* Description:
|
|
* Creates a new segments with the coordinates x1 and x2
|
|
*
|
|
* Returns:
|
|
* New Segment of NULL
|
|
*/
|
|
XmuSegment *
|
|
XmuNewSegment(int x1, int x2)
|
|
{
|
|
XmuSegment *segment;
|
|
|
|
if ((segment = (XmuSegment *)XtMalloc(sizeof(XmuSegment))) == NULL)
|
|
return (segment);
|
|
|
|
segment->x1 = x1;
|
|
segment->x2 = x2;
|
|
segment->next = (XmuSegment *)NULL;
|
|
|
|
return (segment);
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* XmuDestroySegmentList
|
|
*
|
|
* Parameters:
|
|
* segment - Segment to destroy
|
|
*
|
|
* Description:
|
|
* Frees the memory used by the list headed by segment
|
|
*/
|
|
void
|
|
XmuDestroySegmentList(XmuSegment *segment)
|
|
{
|
|
XmuSegment *z;
|
|
|
|
if (!segment)
|
|
return;
|
|
|
|
while (segment)
|
|
{
|
|
z = segment;
|
|
segment = segment->next;
|
|
XmuDestroySegment(z);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* XmuScanlineCopy
|
|
*
|
|
* Parameters:
|
|
* dst - destination scanline
|
|
* src - source scanline
|
|
*
|
|
* Description:
|
|
* Makes dst contain the same data as src
|
|
*/
|
|
XmuScanline *
|
|
XmuScanlineCopy(XmuScanline *dst, XmuScanline *src)
|
|
{
|
|
XmuSegment *z, *p, *Z;
|
|
|
|
if (!dst || !src || dst == src)
|
|
return (dst);
|
|
|
|
z = p = dst->segment;
|
|
Z = src->segment;
|
|
|
|
/*CONSTCOND*/
|
|
while (1)
|
|
{
|
|
if (!Z)
|
|
{
|
|
if (z == dst->segment)
|
|
dst->segment = (XmuSegment *)NULL;
|
|
else
|
|
p->next = (XmuSegment *)NULL;
|
|
XmuDestroySegmentList(z);
|
|
return (dst);
|
|
}
|
|
if (z)
|
|
{
|
|
z->x1 = Z->x1;
|
|
z->x2 = Z->x2;
|
|
}
|
|
else
|
|
{
|
|
z = XmuNewSegment(Z->x1, Z->x2);
|
|
if (p == dst->segment && !dst->segment)
|
|
p = dst->segment = z;
|
|
else
|
|
p->next = z;
|
|
}
|
|
p = z;
|
|
z = z->next;
|
|
Z = Z->next;
|
|
}
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* XmuAppendSegment
|
|
*
|
|
* Parameters:
|
|
* segment - destination segment
|
|
* append - segment to add
|
|
*
|
|
* Description:
|
|
* Adds a copy of the append list at the end of the segment list
|
|
*/
|
|
Bool
|
|
XmuAppendSegment(XmuSegment *segment, XmuSegment *append)
|
|
{
|
|
if (!segment || !append)
|
|
return (False);
|
|
|
|
if (segment->next)
|
|
/* Should not happen! */
|
|
XmuDestroySegmentList(segment->next);
|
|
|
|
while (append)
|
|
{
|
|
if (XmuValidSegment(append))
|
|
{
|
|
if ((segment->next = XmuNewSegment(append->x1, append->x2)) == NULL)
|
|
return (False);
|
|
segment = segment->next;
|
|
}
|
|
append = append->next;
|
|
}
|
|
|
|
return (True);
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* XmuOptimizeScanline
|
|
*
|
|
* Parameters:
|
|
* scanline - scanline to optimize
|
|
*
|
|
* Description:
|
|
* Some functions, when transforming Segments of Scanlines, left these
|
|
* with unnecessary data (that may cause error in these same functions).
|
|
* This function corrects these incorrect segments.
|
|
*/
|
|
XmuScanline *
|
|
XmuOptimizeScanline(XmuScanline *scanline)
|
|
{
|
|
XmuSegment *z, *p;
|
|
|
|
while (scanline->segment && !XmuValidSegment(scanline->segment))
|
|
{
|
|
XmuSegment *s = scanline->segment;
|
|
|
|
scanline->segment = scanline->segment->next;
|
|
XmuDestroySegment(s);
|
|
}
|
|
for (z = p = scanline->segment; z; p = z, z = z->next)
|
|
{
|
|
if (!XmuValidSegment(z))
|
|
{
|
|
p->next = z->next;
|
|
XmuDestroySegment(z);
|
|
z = p;
|
|
}
|
|
}
|
|
return (scanline);
|
|
}
|
|
|
|
/*
|
|
* Name:
|
|
* XmuScanlineNot(scanline, minx, maxx)
|
|
*
|
|
* Parameters:
|
|
* scanline - scanlines operate
|
|
* minx - minimum x coordinate
|
|
* maxx - maximum x coordinate
|
|
*
|
|
* Description:
|
|
* (minx) (maxx)
|
|
* + +
|
|
* (input) +---------+ +--------+ +--------+
|
|
* (output) +-----+ +-----+ +--------+ +------------+
|
|
*/
|
|
XmuScanline *
|
|
XmuScanlineNot(XmuScanline *scanline, int minx, int maxx)
|
|
{
|
|
XmuSegment *z;
|
|
static XmuSegment x = { 0, 0, NULL };
|
|
static XmuScanline and = { 0, &x, NULL };
|
|
|
|
if (!scanline)
|
|
return (scanline);
|
|
|
|
XmuOptimizeScanline(scanline);
|
|
if (minx > maxx)
|
|
{
|
|
minx ^= maxx; maxx ^= minx; minx ^= maxx;
|
|
}
|
|
and.segment->x1 = minx;
|
|
and.segment->x2 = maxx;
|
|
XmuScanlineAnd(scanline, &and);
|
|
if (!scanline->segment)
|
|
{
|
|
scanline->segment = XmuNewSegment(minx, maxx);
|
|
return (scanline);
|
|
}
|
|
z = scanline->segment;
|
|
if (z->x1 != minx)
|
|
{
|
|
XmuSegment *q = XmuNewSegment(minx, z->x1);
|
|
|
|
q->next = z;
|
|
scanline->segment = q;
|
|
}
|
|
|
|
/*CONSTCOND*/
|
|
while (1)
|
|
{
|
|
z->x1 = z->x2;
|
|
if (!z->next)
|
|
{
|
|
z->x2 = maxx;
|
|
break;
|
|
}
|
|
z->x2 = z->next->x1;
|
|
if (z->next->x2 == maxx)
|
|
{
|
|
XmuDestroySegment(z->next);
|
|
z->next = (XmuSegment *)NULL;
|
|
break;
|
|
}
|
|
z = z->next;
|
|
}
|
|
|
|
return (scanline);
|
|
}
|
|
|
|
|
|
#ifndef notdef
|
|
/*
|
|
* Function:
|
|
* XmuScanlineOrSegment
|
|
*
|
|
* Parameters:
|
|
* dst - destination scanline
|
|
* src - source segment
|
|
*
|
|
* Description:
|
|
* (input) +-----------+ +--------+ +---------+
|
|
* (src) +-------------------+
|
|
* (output) +-------------------------+ +---------+
|
|
*/
|
|
XmuScanline *
|
|
XmuScanlineOrSegment(XmuScanline *dst, XmuSegment *src)
|
|
{
|
|
XmuSegment *z, *p, ins;
|
|
|
|
if (!src || !dst || !XmuValidSegment(src))
|
|
return (dst);
|
|
|
|
if (!dst->segment)
|
|
{
|
|
dst->segment = XmuNewSegment(src->x1, src->x2);
|
|
return (dst);
|
|
}
|
|
|
|
z = p = dst->segment;
|
|
ins.x1 = src->x1;
|
|
ins.x2 = src->x2;
|
|
|
|
/*CONSTCOND*/
|
|
while (1)
|
|
{
|
|
if (!z)
|
|
{
|
|
XmuSegment *q = XmuNewSegment(ins.x1, ins.x2);
|
|
|
|
if (p == dst->segment && z == p)
|
|
dst->segment = q;
|
|
else
|
|
p->next = q;
|
|
break;
|
|
}
|
|
else if (ins.x2 < z->x1)
|
|
{
|
|
XmuSegment *q = XmuNewSegment(ins.x1, ins.x2);
|
|
|
|
if (p == dst->segment && z == p)
|
|
{
|
|
q->next = dst->segment;
|
|
dst->segment = q;
|
|
}
|
|
else
|
|
{
|
|
p->next = q;
|
|
q->next = z;
|
|
}
|
|
break;
|
|
}
|
|
else if (ins.x2 <= z->x2)
|
|
{
|
|
z->x1 = XmuMin(z->x1, ins.x1);
|
|
break;
|
|
}
|
|
else if (ins.x1 <= z->x2)
|
|
{
|
|
ins.x1 = XmuMin(z->x1, ins.x1);
|
|
if (!z->next)
|
|
{
|
|
z->x1 = ins.x1;
|
|
z->x2 = ins.x2;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (z == dst->segment)
|
|
{
|
|
p = dst->segment = dst->segment->next;
|
|
XmuDestroySegment(z);
|
|
z = dst->segment;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
p->next = z->next;
|
|
XmuDestroySegment(z);
|
|
z = p;
|
|
}
|
|
}
|
|
}
|
|
p = z;
|
|
z = z->next;
|
|
}
|
|
|
|
return (dst);
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* XmuScanlineAndSegment
|
|
*
|
|
* Parameters:
|
|
* dst - destination scanline
|
|
* src - source segment
|
|
*
|
|
* Description:
|
|
* (input) +------------+ +------+ +----------+
|
|
* (src) +---------------------+
|
|
* (output) +-------+ +------+
|
|
*/
|
|
XmuScanline *
|
|
XmuScanlineAndSegment(XmuScanline *dst, XmuSegment *src)
|
|
{
|
|
XmuSegment *z, *p;
|
|
|
|
if (!dst || !src)
|
|
return (dst);
|
|
|
|
if (!XmuValidSegment(src))
|
|
{
|
|
XmuDestroySegmentList(dst->segment);
|
|
dst->segment = (XmuSegment *)NULL;
|
|
return (dst);
|
|
}
|
|
if (!dst->segment)
|
|
return (dst);
|
|
|
|
z = p = dst->segment;
|
|
while (z)
|
|
{
|
|
if (src->x2 <= z->x1 || src->x1 >= z->x2)
|
|
{
|
|
if (z == dst->segment)
|
|
{
|
|
p = dst->segment = dst->segment->next;
|
|
XmuDestroySegment(z);
|
|
z = dst->segment;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
p->next = z->next;
|
|
XmuDestroySegment(z);
|
|
z = p;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
z->x1 = XmuMax(z->x1, src->x1);
|
|
z->x2 = XmuMin(z->x2, src->x2);
|
|
}
|
|
p = z;
|
|
z = z->next;
|
|
}
|
|
|
|
return (dst);
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* XmuScanlineXorSegment
|
|
*
|
|
* Parameters:
|
|
* dst - destination scanline
|
|
* src - source segment
|
|
*
|
|
* Description:
|
|
* (input) +------------+ +----------+ +-----------+
|
|
* (src) +------------------------+
|
|
* (output) +---+ +--+ +-+ +-----------+
|
|
*/
|
|
XmuScanline *
|
|
XmuScanlineXorSegment(XmuScanline *dst, XmuSegment *src)
|
|
{
|
|
XmuSegment *p, *z, ins;
|
|
int tmp1, tmp2;
|
|
|
|
if (!dst || !src || !XmuValidSegment(src))
|
|
return (dst);
|
|
if (!dst->segment)
|
|
{
|
|
dst->segment = XmuNewSegment(src->x1, src->x2);
|
|
return (dst);
|
|
}
|
|
|
|
p = z = dst->segment;
|
|
ins.x1 = src->x1;
|
|
ins.x2 = src->x2;
|
|
|
|
/*CONSTCOND*/
|
|
while (1)
|
|
{
|
|
if (!XmuValidSegment((&ins)))
|
|
break;
|
|
if (!z || ins.x2 < z->x1)
|
|
{
|
|
XmuSegment *q = XmuNewSegment(ins.x1, ins.x2);
|
|
|
|
q->next = z;
|
|
if (z == dst->segment)
|
|
dst->segment = q;
|
|
else
|
|
p->next = q;
|
|
break;
|
|
}
|
|
else if (ins.x2 == z->x1)
|
|
{
|
|
z->x1 = ins.x1;
|
|
break;
|
|
}
|
|
else if (ins.x1 < z->x2)
|
|
{
|
|
if (ins.x1 < z->x1)
|
|
{
|
|
tmp1 = ins.x2;
|
|
tmp2 = z->x2;
|
|
ins.x2 = XmuMax(ins.x2, z->x2);
|
|
z->x2 = z->x1;
|
|
z->x1 = ins.x1;
|
|
ins.x1 = XmuMin(tmp1, tmp2);
|
|
}
|
|
else if (ins.x1 > z->x1)
|
|
{
|
|
tmp1 = ins.x1;
|
|
ins.x1 = XmuMin(ins.x2, z->x2);
|
|
ins.x2 = XmuMax(z->x2, ins.x2);
|
|
z->x2 = tmp1;
|
|
}
|
|
else /* ins.x1 == z->x1 */
|
|
{
|
|
if (ins.x2 < z->x2)
|
|
{
|
|
z->x1 = ins.x2;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
ins.x1 = z->x2;
|
|
if (z == dst->segment)
|
|
p = dst->segment = dst->segment->next;
|
|
else
|
|
p->next = z->next;
|
|
XmuDestroySegment(z);
|
|
z = p;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else if (ins.x1 == z->x2)
|
|
{
|
|
ins.x1 = z->x1;
|
|
if (z == dst->segment)
|
|
p = dst->segment = dst->segment->next;
|
|
else
|
|
p->next = z->next;
|
|
XmuDestroySegment(z);
|
|
z = p;
|
|
continue;
|
|
}
|
|
p = z;
|
|
z = z->next;
|
|
}
|
|
|
|
return (dst);
|
|
}
|
|
#endif /* notdef */
|
|
|
|
/*
|
|
* Function:
|
|
* ScanlineOr
|
|
*
|
|
* Parameters:
|
|
* dst - destination scanline
|
|
* src - source scanline
|
|
*
|
|
* Description:
|
|
* (input) +--------------+ +-----+ +----------+
|
|
* (src) +---------------------+ +-----------+
|
|
* (output) +-------------------------+ +----------------+
|
|
*/
|
|
XmuScanline *
|
|
XmuScanlineOr(XmuScanline *dst, XmuScanline *src)
|
|
{
|
|
XmuSegment *z, *p, *Z, ins;
|
|
|
|
if (!src || !src->segment || !dst || dst == src)
|
|
return (dst);
|
|
if (!dst->segment)
|
|
{
|
|
XmuScanlineCopy(dst, src);
|
|
return (dst);
|
|
}
|
|
|
|
z = p = dst->segment;
|
|
Z = src->segment;
|
|
ins.x1 = Z->x1;
|
|
ins.x2 = Z->x2;
|
|
|
|
/*CONSTCOND*/
|
|
while (1)
|
|
{
|
|
while (!XmuValidSegment((&ins)))
|
|
{
|
|
if ((Z = Z->next) == (XmuSegment *)NULL)
|
|
return (dst);
|
|
ins.x1 = Z->x1;
|
|
ins.x2 = Z->x2;
|
|
}
|
|
if (!z)
|
|
{
|
|
XmuSegment *q = XmuNewSegment(ins.x1, ins.x2);
|
|
|
|
if (p == dst->segment && z == p)
|
|
dst->segment = p = q;
|
|
else
|
|
{
|
|
p->next = q;
|
|
p = q;
|
|
}
|
|
Z = Z->next;
|
|
XmuAppendSegment(p, Z);
|
|
break;
|
|
}
|
|
else if (ins.x2 < z->x1)
|
|
{
|
|
XmuSegment *r = XmuNewSegment(ins.x1, ins.x2);
|
|
|
|
if (p == dst->segment && z == p)
|
|
{
|
|
r->next = dst->segment;
|
|
dst->segment = p = r;
|
|
}
|
|
else
|
|
{
|
|
p->next = r;
|
|
r->next = z;
|
|
p = r;
|
|
}
|
|
Z = Z->next;
|
|
if (!Z)
|
|
break;
|
|
else
|
|
{
|
|
ins.x1 = Z->x1;
|
|
ins.x2 = Z->x2;
|
|
continue;
|
|
}
|
|
}
|
|
else if (ins.x2 <= z->x2)
|
|
{
|
|
z->x1 = XmuMin(z->x1, ins.x1);
|
|
Z = Z->next;
|
|
if (!Z)
|
|
break;
|
|
else
|
|
{
|
|
ins.x1 = Z->x1;
|
|
ins.x2 = Z->x2;
|
|
continue;
|
|
}
|
|
}
|
|
else if (ins.x1 <= z->x2)
|
|
{
|
|
ins.x1 = XmuMin(z->x1, ins.x1);
|
|
if (!z->next)
|
|
{
|
|
z->x1 = ins.x1;
|
|
z->x2 = ins.x2;
|
|
p = z;
|
|
Z = Z->next;
|
|
XmuAppendSegment(p, Z);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (z == dst->segment)
|
|
{
|
|
p = dst->segment = dst->segment->next;
|
|
XmuDestroySegment(z);
|
|
z = p;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
p->next = z->next;
|
|
XmuDestroySegment(z);
|
|
z = p;
|
|
}
|
|
}
|
|
}
|
|
p = z;
|
|
z = z->next;
|
|
}
|
|
|
|
return (dst);
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* XmuScanlineAnd
|
|
*
|
|
* Parameters:
|
|
* dst - destination scanline
|
|
* src - source scanline
|
|
*
|
|
* Description:
|
|
* (input) +--------------+ +-----+ +----------+
|
|
* (src) +---------------------+ +-----------+
|
|
* (output) +----------+ +-----+ +-----+
|
|
*/
|
|
XmuScanline *
|
|
XmuScanlineAnd(XmuScanline *dst, XmuScanline *src)
|
|
{
|
|
XmuSegment *z, *p, *Z;
|
|
|
|
if (!dst || !src || dst == src || !dst->segment) {
|
|
return (dst);
|
|
}
|
|
if (!src->segment)
|
|
{
|
|
XmuDestroySegmentList(dst->segment);
|
|
dst->segment = (XmuSegment *)NULL;
|
|
return (dst);
|
|
}
|
|
z = p = dst->segment;
|
|
Z = src->segment;
|
|
|
|
while (z)
|
|
{
|
|
while (!XmuValidSegment(Z) || Z->x2 <= z->x1)
|
|
{
|
|
Z = Z->next;
|
|
if (!Z)
|
|
{
|
|
if (z == dst->segment)
|
|
dst->segment = (XmuSegment *)NULL;
|
|
else
|
|
p->next = (XmuSegment *)0;
|
|
XmuDestroySegmentList(z);
|
|
return (dst);
|
|
}
|
|
}
|
|
if (Z->x1 >= z->x2)
|
|
{
|
|
if (z == dst->segment)
|
|
{
|
|
p = dst->segment = dst->segment->next;
|
|
XmuDestroySegment(z);
|
|
z = dst->segment;
|
|
}
|
|
else
|
|
{
|
|
p->next = z->next;
|
|
XmuDestroySegment(z);
|
|
z = p->next;
|
|
}
|
|
if (!z)
|
|
return (dst);
|
|
else
|
|
continue;
|
|
}
|
|
z->x1 = XmuMax(z->x1, Z->x1);
|
|
if (z->x2 > Z->x2)
|
|
{
|
|
if (Z->next)
|
|
{
|
|
XmuSegment *q = XmuNewSegment(Z->x2, z->x2);
|
|
|
|
q->next = z->next;
|
|
z->next = q;
|
|
}
|
|
z->x2 = Z->x2;
|
|
}
|
|
p = z;
|
|
z = z->next;
|
|
}
|
|
|
|
return (dst);
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* ScanlineXor
|
|
*
|
|
* Parameters:
|
|
* dst - destination scanline
|
|
* src - source scanline
|
|
*
|
|
* Description:
|
|
* (input) +--------------+ +-----+ +----------+
|
|
* (src) +---------------------+ +-----------+
|
|
* (output) +---+ +--+ +-+ +----+ +-----+
|
|
*/
|
|
XmuScanline *
|
|
XmuScanlineXor(XmuScanline *dst, XmuScanline *src)
|
|
{
|
|
XmuSegment *z, *p, *Z, ins;
|
|
int tmp1, tmp2;
|
|
|
|
if (!src || !dst || !src->segment)
|
|
return (dst);
|
|
if (src == dst)
|
|
{
|
|
XmuDestroySegmentList(dst->segment);
|
|
dst->segment = (XmuSegment *)NULL;
|
|
return (dst);
|
|
}
|
|
if (!dst->segment)
|
|
{
|
|
XmuScanlineCopy(dst, src);
|
|
return (dst);
|
|
}
|
|
|
|
z = p = dst->segment;
|
|
Z = src->segment;
|
|
ins.x1 = Z->x1;
|
|
ins.x2 = Z->x2;
|
|
|
|
/*CONSTCOND*/
|
|
while (1)
|
|
{
|
|
while (!XmuValidSegment((&ins)))
|
|
{
|
|
if ((Z = Z->next) == (XmuSegment *)NULL)
|
|
return (dst);
|
|
ins.x1 = Z->x1;
|
|
ins.x2 = Z->x2;
|
|
}
|
|
if (!z)
|
|
{
|
|
XmuSegment *q = XmuNewSegment(ins.x1, ins.x2);
|
|
|
|
if (!dst->segment)
|
|
dst->segment = q;
|
|
else
|
|
p->next = q;
|
|
p = q;
|
|
Z = Z->next;
|
|
XmuAppendSegment(p, Z);
|
|
break;
|
|
}
|
|
else if (ins.x2 < z->x1)
|
|
{
|
|
XmuSegment *q = XmuNewSegment(ins.x1, ins.x2);
|
|
|
|
q->next = z;
|
|
if (z == dst->segment)
|
|
dst->segment = q;
|
|
else
|
|
p->next = q;
|
|
if ((Z = Z->next) == (XmuSegment *)NULL)
|
|
return (dst);
|
|
|
|
p = q;
|
|
ins.x1 = Z->x1;
|
|
ins.x2 = Z->x2;
|
|
continue;
|
|
}
|
|
else if (ins.x2 == z->x1)
|
|
{
|
|
z->x1 = ins.x1;
|
|
if ((Z = Z->next) == (XmuSegment *)NULL)
|
|
break;
|
|
ins.x1 = Z->x1;
|
|
ins.x2 = Z->x2;
|
|
continue;
|
|
}
|
|
else if (ins.x1 < z->x2)
|
|
{
|
|
if (ins.x1 == z->x1)
|
|
{
|
|
if (ins.x2 < z->x2)
|
|
{
|
|
z->x1 = ins.x2;
|
|
if ((Z = Z->next) == (XmuSegment *)NULL)
|
|
break;
|
|
ins.x1 = Z->x1;
|
|
ins.x2 = Z->x2;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
ins.x1 = z->x2;
|
|
if (z == dst->segment)
|
|
p = dst->segment = dst->segment->next;
|
|
else
|
|
p->next = z->next;
|
|
XmuDestroySegment(z);
|
|
z = p;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Z->x2 < z->x2)
|
|
{
|
|
XmuSegment *q = XmuNewSegment(XmuMin(ins.x1, z->x1),
|
|
XmuMax(z->x1, ins.x1));
|
|
|
|
q->next = z;
|
|
if (z == dst->segment)
|
|
dst->segment = q;
|
|
else
|
|
p->next = q;
|
|
ins.x1 = z->x2;
|
|
z->x1 = ins.x2;
|
|
p = q;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
tmp1 = ins.x2;
|
|
tmp2 = z->x2;
|
|
ins.x2 = XmuMax(ins.x2, z->x2);
|
|
z->x2 = XmuMax(z->x1, ins.x1);
|
|
z->x1 = XmuMin(ins.x1, z->x1);
|
|
ins.x1 = XmuMin(tmp1, tmp2);
|
|
}
|
|
}
|
|
}
|
|
else if (ins.x1 == z->x2)
|
|
{
|
|
ins.x1 = z->x1;
|
|
if (z == dst->segment)
|
|
p = dst->segment = dst->segment->next;
|
|
else
|
|
p->next = z->next;
|
|
XmuDestroySegment(z);
|
|
z = p;
|
|
continue;
|
|
}
|
|
p = z;
|
|
z = z->next;
|
|
}
|
|
|
|
return (dst);
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* XmuNewScanline
|
|
*
|
|
* Parameters:
|
|
* y - y coordinate
|
|
* x1 - left coordinate
|
|
* x2 - right coordinate
|
|
*
|
|
* Description:
|
|
* Creates a new Scanline
|
|
*/
|
|
XmuScanline *
|
|
XmuNewScanline(int y, int x1, int x2)
|
|
{
|
|
XmuScanline *scanline;
|
|
|
|
scanline = (XmuScanline *)XtMalloc(sizeof(XmuScanline));
|
|
scanline->y = y;
|
|
if (x1 < x2)
|
|
scanline->segment = XmuNewSegment(x1, x2);
|
|
else
|
|
scanline->segment = (XmuSegment *)NULL;
|
|
|
|
scanline->next = (XmuScanline *)NULL;
|
|
|
|
return (scanline);
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* XmuDestroyScanlineList
|
|
*
|
|
* Parameters:
|
|
* scanline - scanline list to destroy
|
|
*
|
|
* Description:
|
|
* Destroy a scanline list
|
|
*
|
|
* Observation:
|
|
* Use as follow:
|
|
* XmuDestroyScanlineList(area->scanline);
|
|
* area->scanline = (XmuScanline *)NULL;
|
|
*/
|
|
void
|
|
XmuDestroyScanlineList(XmuScanline *scanline)
|
|
{
|
|
XmuScanline *z;
|
|
|
|
if (!scanline)
|
|
return;
|
|
|
|
while (scanline)
|
|
{
|
|
z = scanline;
|
|
scanline = scanline->next;
|
|
XmuDestroyScanline(z);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function:
|
|
* XmuOptimizeArea
|
|
*
|
|
* Parameters:
|
|
* area - area to optimize
|
|
*
|
|
* Description:
|
|
* Optimizes an area. This function is called when finishing a
|
|
* operation between areas, since they can end with redundant data,
|
|
* and the algorithms for area combination waits a area with
|
|
* correct data (but can left unnecessary data in the area, to avoid
|
|
* to much paranoia tests).
|
|
*/
|
|
XmuArea *XmuOptimizeArea(XmuArea *area)
|
|
{
|
|
XmuScanline *pr, *at;
|
|
|
|
if (!area || !area->scanline)
|
|
return (area);
|
|
|
|
if (!area->scanline->next)
|
|
{
|
|
XmuDestroyScanlineList(area->scanline);
|
|
area->scanline = (XmuScanline *)0;
|
|
return (area);
|
|
}
|
|
|
|
pr = area->scanline;
|
|
at = area->scanline->next;
|
|
while (area->scanline && (!XmuValidScanline(area->scanline)
|
|
|| (area->scanline->next && area->scanline->y
|
|
>= area->scanline->next->y)))
|
|
{
|
|
area->scanline = area->scanline->next;
|
|
XmuDestroyScanline(pr);
|
|
pr = area->scanline;
|
|
if (pr)
|
|
at = pr->next;
|
|
}
|
|
|
|
for (; at; pr = at, at = at->next)
|
|
{
|
|
if (XmuScanlineEqu(at, pr)
|
|
|| (!XmuValidScanline(at) && !XmuValidScanline(pr))
|
|
|| (at->next && at->y >= at->next->y))
|
|
{
|
|
pr->next = at->next;
|
|
XmuDestroyScanline(at);
|
|
at = pr;
|
|
}
|
|
}
|
|
if (pr && XmuValidScanline(pr))
|
|
{
|
|
XmuDestroySegmentList(pr->segment);
|
|
pr->segment = (XmuSegment *)NULL;
|
|
}
|
|
if (area->scanline && !area->scanline->next)
|
|
{
|
|
XmuDestroyScanlineList(area->scanline);
|
|
area->scanline = (XmuScanline *)NULL;
|
|
}
|
|
|
|
return (area);
|
|
}
|