a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync/*
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsyncCopyright 1987, 1998 The Open Group
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsyncPermission to use, copy, modify, distribute, and sell this software and its
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsyncdocumentation for any purpose is hereby granted without fee, provided that
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsyncthe above copyright notice appear in all copies and that both that
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsynccopyright notice and this permission notice appear in supporting
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsyncdocumentation.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsyncThe above copyright notice and this permission notice shall be included
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsyncin all copies or substantial portions of the Software.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsyncTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsyncOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsyncMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsyncIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsyncOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsyncARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsyncOTHER DEALINGS IN THE SOFTWARE.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsyncExcept as contained in this notice, the name of The Open Group shall
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsyncnot be used in advertising or otherwise to promote the sale, use or
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsyncother dealings in this Software without prior written authorization
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsyncfrom The Open Group.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync*/
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync/*
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * fill.h
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync *
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * Created by Brian Kelleher; Oct 1985
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync *
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * Include file for filled polygon routines.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync *
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * These are the data structures needed to scan
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * convert regions. Two different scan conversion
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * methods are available -- the even-odd method, and
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * the winding number method.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * The even-odd rule states that a point is inside
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * the polygon if a ray drawn from that point in any
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * direction will pass through an odd number of
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * path segments.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * By the winding number rule, a point is decided
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * to be inside the polygon if a ray drawn from that
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * point in any direction passes through a different
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * number of clockwise and counter-clockwise path
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * segments.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync *
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * These data structures are adapted somewhat from
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * the algorithm in (Foley/Van Dam) for scan converting
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * polygons.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * The basic algorithm is to start at the top (smallest y)
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * of the polygon, stepping down to the bottom of
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * the polygon by incrementing the y coordinate. We
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * keep a list of edges which the current scanline crosses,
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * sorted by x. This list is called the Active Edge Table (AET)
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * As we change the y-coordinate, we update each entry in
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * in the active edge table to reflect the edges new xcoord.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * This list must be sorted at each scanline in case
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * two edges intersect.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * We also keep a data structure known as the Edge Table (ET),
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * which keeps track of all the edges which the current
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * scanline has not yet reached. The ET is basically a
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * list of ScanLineList structures containing a list of
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * edges which are entered at a given scanline. There is one
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * ScanLineList per scanline at which an edge is entered.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * When we enter a new edge, we move it from the ET to the AET.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync *
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * From the AET, we can implement the even-odd rule as in
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * (Foley/Van Dam).
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * The winding number rule is a little trickier. We also
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * keep the EdgeTableEntries in the AET linked by the
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * nextWETE (winding EdgeTableEntry) link. This allows
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * the edges to be linked just as before for updating
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * purposes, but only uses the edges linked by the nextWETE
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * link as edges representing spans of the polygon to
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * drawn (as with the even-odd rule).
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync */
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync/*
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * for the winding number rule
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync */
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync#define CLOCKWISE 1
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync#define COUNTERCLOCKWISE -1
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsynctypedef struct _EdgeTableEntry {
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync int ymax; /* ycoord at which we exit this edge. */
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync BRESINFO bres; /* Bresenham info to run the edge */
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync struct _EdgeTableEntry *next; /* next in the list */
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync struct _EdgeTableEntry *back; /* for insertion sort */
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync struct _EdgeTableEntry *nextWETE; /* for winding num rule */
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync int ClockWise; /* flag for winding number rule */
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync} EdgeTableEntry;
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsynctypedef struct _ScanLineList {
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync int scanline; /* the scanline represented */
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync EdgeTableEntry *edgelist; /* header node */
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync struct _ScanLineList *next; /* next in the list */
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync} ScanLineList;
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsynctypedef struct {
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync int ymax; /* ymax for the polygon */
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync int ymin; /* ymin for the polygon */
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync ScanLineList scanlines; /* header node */
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync} EdgeTable;
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync/*
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * Here is a struct to help with storage allocation
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * so we can allocate a big chunk at a time, and then take
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * pieces from this heap when we need to.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync */
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync#define SLLSPERBLOCK 25
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsynctypedef struct _ScanLineListBlock {
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync ScanLineList SLLs[SLLSPERBLOCK];
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync struct _ScanLineListBlock *next;
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync} ScanLineListBlock;
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync/*
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * number of points to buffer before sending them off
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * to scanlines() : Must be an even number
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync */
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync#define NUMPTSTOBUFFER 200
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync/*
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync *
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * a few macros for the inner loops of the fill code where
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * performance considerations don't allow a procedure call.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync *
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * Evaluate the given edge at the given scanline.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * If the edge has expired, then we leave it and fix up
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * the active edge table; otherwise, we increment the
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * x value to be ready for the next scanline.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * The winding number rule is in effect, so we must notify
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * the caller when the edge has been removed so he
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * can reorder the Winding Active Edge Table.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync */
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync if (pAET->ymax == y) { /* leaving this edge */ \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync pPrevAET->next = pAET->next; \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync pAET = pPrevAET->next; \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync fixWAET = 1; \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync if (pAET) \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync pAET->back = pPrevAET; \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync } \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync else { \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync BRESINCRPGONSTRUCT(pAET->bres); \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync pPrevAET = pAET; \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync pAET = pAET->next; \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync } \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync}
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync/*
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * Evaluate the given edge at the given scanline.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * If the edge has expired, then we leave it and fix up
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * the active edge table; otherwise, we increment the
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * x value to be ready for the next scanline.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync * The even-odd rule is in effect.
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync */
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync if (pAET->ymax == y) { /* leaving this edge */ \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync pPrevAET->next = pAET->next; \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync pAET = pPrevAET->next; \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync if (pAET) \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync pAET->back = pPrevAET; \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync } \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync else { \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync BRESINCRPGONSTRUCT(pAET->bres); \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync pPrevAET = pAET; \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync pAET = pAET->next; \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync } \
a5e7ae69e440f6816420fc99599f044e79e716b6vboxsync}