Blame gdk/gdkpolyreg-generic.c

Packit 98cdb6
/* $TOG: PolyReg.c /main/15 1998/02/06 17:47:08 kaleb $ */
Packit 98cdb6
/************************************************************************
Packit 98cdb6
Packit 98cdb6
Copyright 1987, 1998  The Open Group
Packit 98cdb6
Packit 98cdb6
All Rights Reserved.
Packit 98cdb6
Packit 98cdb6
The above copyright notice and this permission notice shall be included in
Packit 98cdb6
all copies or substantial portions of the Software.
Packit 98cdb6
Packit 98cdb6
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit 98cdb6
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit 98cdb6
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
Packit 98cdb6
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
Packit 98cdb6
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit 98cdb6
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Packit 98cdb6
Packit 98cdb6
Except as contained in this notice, the name of The Open Group shall not be
Packit 98cdb6
used in advertising or otherwise to promote the sale, use or other dealings
Packit 98cdb6
in this Software without prior written authorization from The Open Group.
Packit 98cdb6
Packit 98cdb6
Packit 98cdb6
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
Packit 98cdb6
Packit 98cdb6
                        All Rights Reserved
Packit 98cdb6
Packit 98cdb6
Permission to use, copy, modify, and distribute this software and its 
Packit 98cdb6
documentation for any purpose and without fee is hereby granted, 
Packit 98cdb6
provided that the above copyright notice appear in all copies and that
Packit 98cdb6
both that copyright notice and this permission notice appear in 
Packit 98cdb6
supporting documentation, and that the name of Digital not be
Packit 98cdb6
used in advertising or publicity pertaining to distribution of the
Packit 98cdb6
software without specific, written prior permission.  
Packit 98cdb6
Packit 98cdb6
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
Packit 98cdb6
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
Packit 98cdb6
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
Packit 98cdb6
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
Packit 98cdb6
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
Packit 98cdb6
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
Packit 98cdb6
SOFTWARE.
Packit 98cdb6
Packit 98cdb6
************************************************************************/
Packit 98cdb6
/* $XFree86: xc/lib/X11/PolyReg.c,v 1.4 1998/10/03 08:41:21 dawes Exp $ */
Packit 98cdb6
Packit 98cdb6
#define LARGE_COORDINATE 1000000
Packit 98cdb6
#define SMALL_COORDINATE -LARGE_COORDINATE
Packit 98cdb6
Packit 98cdb6
#include "config.h"
Packit 98cdb6
#include <gdkregion.h>
Packit 98cdb6
#include "gdkregion-generic.h"
Packit 98cdb6
#include "gdkpoly-generic.h"
Packit 98cdb6
#include "gdkalias.h"
Packit 98cdb6
Packit 98cdb6
/*
Packit 98cdb6
 *     InsertEdgeInET
Packit 98cdb6
 *
Packit 98cdb6
 *     Insert the given edge into the edge table.
Packit 98cdb6
 *     First we must find the correct bucket in the
Packit 98cdb6
 *     Edge table, then find the right slot in the
Packit 98cdb6
 *     bucket.  Finally, we can insert it.
Packit 98cdb6
 *
Packit 98cdb6
 */
Packit 98cdb6
static void
Packit 98cdb6
InsertEdgeInET (EdgeTable          *ET,
Packit 98cdb6
                EdgeTableEntry     *ETE,
Packit 98cdb6
                int                 scanline,
Packit 98cdb6
                ScanLineListBlock **SLLBlock,
Packit 98cdb6
                int                *iSLLBlock)
Packit 98cdb6
{
Packit 98cdb6
    EdgeTableEntry *start, *prev;
Packit 98cdb6
    ScanLineList *pSLL, *pPrevSLL;
Packit 98cdb6
    ScanLineListBlock *tmpSLLBlock;
Packit 98cdb6
Packit 98cdb6
    /*
Packit 98cdb6
     * find the right bucket to put the edge into
Packit 98cdb6
     */
Packit 98cdb6
    pPrevSLL = &ET->scanlines;
Packit 98cdb6
    pSLL = pPrevSLL->next;
Packit 98cdb6
    while (pSLL && (pSLL->scanline < scanline)) 
Packit 98cdb6
    {
Packit 98cdb6
        pPrevSLL = pSLL;
Packit 98cdb6
        pSLL = pSLL->next;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
    /*
Packit 98cdb6
     * reassign pSLL (pointer to ScanLineList) if necessary
Packit 98cdb6
     */
Packit 98cdb6
    if ((!pSLL) || (pSLL->scanline > scanline)) 
Packit 98cdb6
    {
Packit 98cdb6
        if (*iSLLBlock > SLLSPERBLOCK-1) 
Packit 98cdb6
        {
Packit 98cdb6
            tmpSLLBlock = 
Packit 98cdb6
		  (ScanLineListBlock *)g_malloc(sizeof(ScanLineListBlock));
Packit 98cdb6
            (*SLLBlock)->next = tmpSLLBlock;
Packit 98cdb6
            tmpSLLBlock->next = (ScanLineListBlock *)NULL;
Packit 98cdb6
            *SLLBlock = tmpSLLBlock;
Packit 98cdb6
            *iSLLBlock = 0;
Packit 98cdb6
        }
Packit 98cdb6
        pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
Packit 98cdb6
Packit 98cdb6
        pSLL->next = pPrevSLL->next;
Packit 98cdb6
        pSLL->edgelist = (EdgeTableEntry *)NULL;
Packit 98cdb6
        pPrevSLL->next = pSLL;
Packit 98cdb6
    }
Packit 98cdb6
    pSLL->scanline = scanline;
Packit 98cdb6
Packit 98cdb6
    /*
Packit 98cdb6
     * now insert the edge in the right bucket
Packit 98cdb6
     */
Packit 98cdb6
    prev = (EdgeTableEntry *)NULL;
Packit 98cdb6
    start = pSLL->edgelist;
Packit 98cdb6
    while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) 
Packit 98cdb6
    {
Packit 98cdb6
        prev = start;
Packit 98cdb6
        start = start->next;
Packit 98cdb6
    }
Packit 98cdb6
    ETE->next = start;
Packit 98cdb6
Packit 98cdb6
    if (prev)
Packit 98cdb6
        prev->next = ETE;
Packit 98cdb6
    else
Packit 98cdb6
        pSLL->edgelist = ETE;
Packit 98cdb6
}
Packit 98cdb6

Packit 98cdb6
/*
Packit 98cdb6
 *     CreateEdgeTable
Packit 98cdb6
 *
Packit 98cdb6
 *     This routine creates the edge table for
Packit 98cdb6
 *     scan converting polygons. 
Packit 98cdb6
 *     The Edge Table (ET) looks like:
Packit 98cdb6
 *
Packit 98cdb6
 *    EdgeTable
Packit 98cdb6
 *     --------
Packit 98cdb6
 *    |  ymax  |        ScanLineLists
Packit 98cdb6
 *    |scanline|-->------------>-------------->...
Packit 98cdb6
 *     --------   |scanline|   |scanline|
Packit 98cdb6
 *                |edgelist|   |edgelist|
Packit 98cdb6
 *                ---------    ---------
Packit 98cdb6
 *                    |             |
Packit 98cdb6
 *                    |             |
Packit 98cdb6
 *                    V             V
Packit 98cdb6
 *              list of ETEs   list of ETEs
Packit 98cdb6
 *
Packit 98cdb6
 *     where ETE is an EdgeTableEntry data structure,
Packit 98cdb6
 *     and there is one ScanLineList per scanline at
Packit 98cdb6
 *     which an edge is initially entered.
Packit 98cdb6
 *
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
CreateETandAET (int                count,
Packit 98cdb6
                const GdkPoint    *pts,
Packit 98cdb6
                EdgeTable         *ET,
Packit 98cdb6
                EdgeTableEntry    *AET,
Packit 98cdb6
                EdgeTableEntry    *pETEs,
Packit 98cdb6
                ScanLineListBlock *pSLLBlock)
Packit 98cdb6
{
Packit 98cdb6
    const GdkPoint *top, *bottom;
Packit 98cdb6
    const GdkPoint *PrevPt, *CurrPt;
Packit 98cdb6
    int iSLLBlock = 0;
Packit 98cdb6
    int dy;
Packit 98cdb6
Packit 98cdb6
    if (count < 2)  return;
Packit 98cdb6
Packit 98cdb6
    /*
Packit 98cdb6
     *  initialize the Active Edge Table
Packit 98cdb6
     */
Packit 98cdb6
    AET->next = (EdgeTableEntry *)NULL;
Packit 98cdb6
    AET->back = (EdgeTableEntry *)NULL;
Packit 98cdb6
    AET->nextWETE = (EdgeTableEntry *)NULL;
Packit 98cdb6
    AET->bres.minor_axis = SMALL_COORDINATE;
Packit 98cdb6
Packit 98cdb6
    /*
Packit 98cdb6
     *  initialize the Edge Table.
Packit 98cdb6
     */
Packit 98cdb6
    ET->scanlines.next = (ScanLineList *)NULL;
Packit 98cdb6
    ET->ymax = SMALL_COORDINATE;
Packit 98cdb6
    ET->ymin = LARGE_COORDINATE;
Packit 98cdb6
    pSLLBlock->next = (ScanLineListBlock *)NULL;
Packit 98cdb6
Packit 98cdb6
    PrevPt = &pts[count-1];
Packit 98cdb6
Packit 98cdb6
    /*
Packit 98cdb6
     *  for each vertex in the array of points.
Packit 98cdb6
     *  In this loop we are dealing with two vertices at
Packit 98cdb6
     *  a time -- these make up one edge of the polygon.
Packit 98cdb6
     */
Packit 98cdb6
    while (count--) 
Packit 98cdb6
    {
Packit 98cdb6
        CurrPt = pts++;
Packit 98cdb6
Packit 98cdb6
        /*
Packit 98cdb6
         *  find out which point is above and which is below.
Packit 98cdb6
         */
Packit 98cdb6
        if (PrevPt->y > CurrPt->y) 
Packit 98cdb6
        {
Packit 98cdb6
            bottom = PrevPt, top = CurrPt;
Packit 98cdb6
            pETEs->ClockWise = 0;
Packit 98cdb6
        }
Packit 98cdb6
        else 
Packit 98cdb6
        {
Packit 98cdb6
            bottom = CurrPt, top = PrevPt;
Packit 98cdb6
            pETEs->ClockWise = 1;
Packit 98cdb6
        }
Packit 98cdb6
Packit 98cdb6
        /*
Packit 98cdb6
         * don't add horizontal edges to the Edge table.
Packit 98cdb6
         */
Packit 98cdb6
        if (bottom->y != top->y) 
Packit 98cdb6
        {
Packit 98cdb6
            pETEs->ymax = bottom->y-1;  /* -1 so we don't get last scanline */
Packit 98cdb6
Packit 98cdb6
            /*
Packit 98cdb6
             *  initialize integer edge algorithm
Packit 98cdb6
             */
Packit 98cdb6
            dy = bottom->y - top->y;
Packit 98cdb6
            BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
Packit 98cdb6
Packit 98cdb6
            InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock);
Packit 98cdb6
Packit 98cdb6
	    if (PrevPt->y > ET->ymax)
Packit 98cdb6
		ET->ymax = PrevPt->y;
Packit 98cdb6
	    if (PrevPt->y < ET->ymin)
Packit 98cdb6
		ET->ymin = PrevPt->y;
Packit 98cdb6
            pETEs++;
Packit 98cdb6
        }
Packit 98cdb6
Packit 98cdb6
        PrevPt = CurrPt;
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6

Packit 98cdb6
/*
Packit 98cdb6
 *     loadAET
Packit 98cdb6
 *
Packit 98cdb6
 *     This routine moves EdgeTableEntries from the
Packit 98cdb6
 *     EdgeTable into the Active Edge Table,
Packit 98cdb6
 *     leaving them sorted by smaller x coordinate.
Packit 98cdb6
 *
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
loadAET(EdgeTableEntry *AET,
Packit 98cdb6
        EdgeTableEntry *ETEs)
Packit 98cdb6
{
Packit 98cdb6
    EdgeTableEntry *pPrevAET;
Packit 98cdb6
    EdgeTableEntry *tmp;
Packit 98cdb6
Packit 98cdb6
    pPrevAET = AET;
Packit 98cdb6
    AET = AET->next;
Packit 98cdb6
    while (ETEs) 
Packit 98cdb6
    {
Packit 98cdb6
        while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis)) 
Packit 98cdb6
        {
Packit 98cdb6
            pPrevAET = AET;
Packit 98cdb6
            AET = AET->next;
Packit 98cdb6
        }
Packit 98cdb6
        tmp = ETEs->next;
Packit 98cdb6
        ETEs->next = AET;
Packit 98cdb6
        if (AET)
Packit 98cdb6
            AET->back = ETEs;
Packit 98cdb6
        ETEs->back = pPrevAET;
Packit 98cdb6
        pPrevAET->next = ETEs;
Packit 98cdb6
        pPrevAET = ETEs;
Packit 98cdb6
Packit 98cdb6
        ETEs = tmp;
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6

Packit 98cdb6
/*
Packit 98cdb6
 *     computeWAET
Packit 98cdb6
 *
Packit 98cdb6
 *     This routine links the AET by the
Packit 98cdb6
 *     nextWETE (winding EdgeTableEntry) link for
Packit 98cdb6
 *     use by the winding number rule.  The final 
Packit 98cdb6
 *     Active Edge Table (AET) might look something
Packit 98cdb6
 *     like:
Packit 98cdb6
 *
Packit 98cdb6
 *     AET
Packit 98cdb6
 *     ----------  ---------   ---------
Packit 98cdb6
 *     |ymax    |  |ymax    |  |ymax    | 
Packit 98cdb6
 *     | ...    |  |...     |  |...     |
Packit 98cdb6
 *     |next    |->|next    |->|next    |->...
Packit 98cdb6
 *     |nextWETE|  |nextWETE|  |nextWETE|
Packit 98cdb6
 *     ---------   ---------   ^--------
Packit 98cdb6
 *         |                   |       |
Packit 98cdb6
 *         V------------------->       V---> ...
Packit 98cdb6
 *
Packit 98cdb6
 */
Packit 98cdb6
static void
Packit 98cdb6
computeWAET (EdgeTableEntry *AET)
Packit 98cdb6
{
Packit 98cdb6
    EdgeTableEntry *pWETE;
Packit 98cdb6
    int inside = 1;
Packit 98cdb6
    int isInside = 0;
Packit 98cdb6
Packit 98cdb6
    AET->nextWETE = (EdgeTableEntry *)NULL;
Packit 98cdb6
    pWETE = AET;
Packit 98cdb6
    AET = AET->next;
Packit 98cdb6
    while (AET) 
Packit 98cdb6
    {
Packit 98cdb6
        if (AET->ClockWise)
Packit 98cdb6
            isInside++;
Packit 98cdb6
        else
Packit 98cdb6
            isInside--;
Packit 98cdb6
Packit 98cdb6
        if ((!inside && !isInside) ||
Packit 98cdb6
            ( inside &&  isInside)) 
Packit 98cdb6
        {
Packit 98cdb6
            pWETE->nextWETE = AET;
Packit 98cdb6
            pWETE = AET;
Packit 98cdb6
            inside = !inside;
Packit 98cdb6
        }
Packit 98cdb6
        AET = AET->next;
Packit 98cdb6
    }
Packit 98cdb6
    pWETE->nextWETE = (EdgeTableEntry *)NULL;
Packit 98cdb6
}
Packit 98cdb6

Packit 98cdb6
/*
Packit 98cdb6
 *     InsertionSort
Packit 98cdb6
 *
Packit 98cdb6
 *     Just a simple insertion sort using
Packit 98cdb6
 *     pointers and back pointers to sort the Active
Packit 98cdb6
 *     Edge Table.
Packit 98cdb6
 *
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
static int
Packit 98cdb6
InsertionSort (EdgeTableEntry *AET)
Packit 98cdb6
{
Packit 98cdb6
    EdgeTableEntry *pETEchase;
Packit 98cdb6
    EdgeTableEntry *pETEinsert;
Packit 98cdb6
    EdgeTableEntry *pETEchaseBackTMP;
Packit 98cdb6
    int changed = 0;
Packit 98cdb6
Packit 98cdb6
    AET = AET->next;
Packit 98cdb6
    while (AET) 
Packit 98cdb6
    {
Packit 98cdb6
        pETEinsert = AET;
Packit 98cdb6
        pETEchase = AET;
Packit 98cdb6
        while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
Packit 98cdb6
            pETEchase = pETEchase->back;
Packit 98cdb6
Packit 98cdb6
        AET = AET->next;
Packit 98cdb6
        if (pETEchase != pETEinsert) 
Packit 98cdb6
        {
Packit 98cdb6
            pETEchaseBackTMP = pETEchase->back;
Packit 98cdb6
            pETEinsert->back->next = AET;
Packit 98cdb6
            if (AET)
Packit 98cdb6
                AET->back = pETEinsert->back;
Packit 98cdb6
            pETEinsert->next = pETEchase;
Packit 98cdb6
            pETEchase->back->next = pETEinsert;
Packit 98cdb6
            pETEchase->back = pETEinsert;
Packit 98cdb6
            pETEinsert->back = pETEchaseBackTMP;
Packit 98cdb6
            changed = 1;
Packit 98cdb6
        }
Packit 98cdb6
    }
Packit 98cdb6
    return(changed);
Packit 98cdb6
}
Packit 98cdb6

Packit 98cdb6
/*
Packit 98cdb6
 *     Clean up our act.
Packit 98cdb6
 */
Packit 98cdb6
static void
Packit 98cdb6
FreeStorage (ScanLineListBlock *pSLLBlock)
Packit 98cdb6
{
Packit 98cdb6
    ScanLineListBlock   *tmpSLLBlock;
Packit 98cdb6
Packit 98cdb6
    while (pSLLBlock) 
Packit 98cdb6
    {
Packit 98cdb6
        tmpSLLBlock = pSLLBlock->next;
Packit 98cdb6
        g_free (pSLLBlock);
Packit 98cdb6
        pSLLBlock = tmpSLLBlock;
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/*
Packit 98cdb6
 *     Create an array of rectangles from a list of points.
Packit 98cdb6
 *     If indeed these things (POINTS, RECTS) are the same,
Packit 98cdb6
 *     then this proc is still needed, because it allocates
Packit 98cdb6
 *     storage for the array, which was allocated on the
Packit 98cdb6
 *     stack by the calling procedure.
Packit 98cdb6
 *
Packit 98cdb6
 */
Packit 98cdb6
static int
Packit 98cdb6
PtsToRegion (int         numFullPtBlocks,
Packit 98cdb6
             int         iCurPtBlock,
Packit 98cdb6
             POINTBLOCK *FirstPtBlock,
Packit 98cdb6
             GdkRegion  *reg)
Packit 98cdb6
{
Packit 98cdb6
    GdkRegionBox *rects;
Packit 98cdb6
    GdkPoint *pts;
Packit 98cdb6
    POINTBLOCK *CurPtBlock;
Packit 98cdb6
    int i;
Packit 98cdb6
    GdkRegionBox *extents;
Packit 98cdb6
    int numRects;
Packit 98cdb6
Packit 98cdb6
    extents = &reg->extents;
Packit 98cdb6
 
Packit 98cdb6
    numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
Packit 98cdb6
 
Packit 98cdb6
    GROWREGION(reg, numRects);
Packit 98cdb6
Packit 98cdb6
    CurPtBlock = FirstPtBlock;
Packit 98cdb6
    rects = reg->rects - 1;
Packit 98cdb6
    numRects = 0;
Packit 98cdb6
    extents->x1 = G_MAXSHORT,  extents->x2 = G_MINSHORT;
Packit 98cdb6
 
Packit 98cdb6
    for ( ; numFullPtBlocks >= 0; numFullPtBlocks--) {
Packit 98cdb6
	/* the loop uses 2 points per iteration */
Packit 98cdb6
	i = NUMPTSTOBUFFER >> 1;
Packit 98cdb6
	if (!numFullPtBlocks)
Packit 98cdb6
	    i = iCurPtBlock >> 1;
Packit 98cdb6
	for (pts = CurPtBlock->pts; i--; pts += 2) {
Packit 98cdb6
	    if (pts->x == pts[1].x)
Packit 98cdb6
		continue;
Packit 98cdb6
	    if (numRects && pts->x == rects->x1 && pts->y == rects->y2 &&
Packit 98cdb6
		pts[1].x == rects->x2 &&
Packit 98cdb6
		(numRects == 1 || rects[-1].y1 != rects->y1) &&
Packit 98cdb6
		(i && pts[2].y > pts[1].y)) {
Packit 98cdb6
		rects->y2 = pts[1].y + 1;
Packit 98cdb6
		continue;
Packit 98cdb6
	    }
Packit 98cdb6
	    numRects++;
Packit 98cdb6
	    rects++;
Packit 98cdb6
	    rects->x1 = pts->x;  rects->y1 = pts->y;
Packit 98cdb6
	    rects->x2 = pts[1].x;  rects->y2 = pts[1].y + 1;
Packit 98cdb6
	    if (rects->x1 < extents->x1)
Packit 98cdb6
		extents->x1 = rects->x1;
Packit 98cdb6
	    if (rects->x2 > extents->x2)
Packit 98cdb6
		extents->x2 = rects->x2;
Packit 98cdb6
        }
Packit 98cdb6
	CurPtBlock = CurPtBlock->next;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
    if (numRects) {
Packit 98cdb6
	extents->y1 = reg->rects->y1;
Packit 98cdb6
	extents->y2 = rects->y2;
Packit 98cdb6
    } else {
Packit 98cdb6
	extents->x1 = 0;
Packit 98cdb6
	extents->y1 = 0;
Packit 98cdb6
	extents->x2 = 0;
Packit 98cdb6
	extents->y2 = 0;
Packit 98cdb6
    }
Packit 98cdb6
    reg->numRects = numRects;
Packit 98cdb6
 
Packit 98cdb6
    return(TRUE);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_polygon:
Packit 98cdb6
 * @points: an array of #GdkPoint structs
Packit 98cdb6
 * @n_points: the number of elements in the @points array
Packit 98cdb6
 * @fill_rule: specifies which pixels are included in the region when the 
Packit 98cdb6
 *     polygon overlaps itself.
Packit 98cdb6
 * 
Packit 98cdb6
 * Creates a new #GdkRegion using the polygon defined by a 
Packit 98cdb6
 * number of points.
Packit 98cdb6
 *
Packit 98cdb6
 * Returns: a new #GdkRegion based on the given polygon
Packit 98cdb6
 *
Packit 98cdb6
 * Deprecated: 2.22: There is no replacement. For working with paths, please
Packit 98cdb6
 *             use Cairo.
Packit 98cdb6
 */
Packit 98cdb6
GdkRegion *
Packit 98cdb6
gdk_region_polygon (const GdkPoint *points,
Packit 98cdb6
                    gint            n_points,
Packit 98cdb6
                    GdkFillRule     fill_rule)
Packit 98cdb6
{
Packit 98cdb6
    GdkRegion *region;
Packit 98cdb6
    EdgeTableEntry *pAET;   /* Active Edge Table       */
Packit 98cdb6
    int y;                  /* current scanline        */
Packit 98cdb6
    int iPts = 0;           /* number of pts in buffer */
Packit 98cdb6
    EdgeTableEntry *pWETE;  /* Winding Edge Table Entry*/
Packit 98cdb6
    ScanLineList *pSLL;     /* current scanLineList    */
Packit 98cdb6
    GdkPoint *pts;          /* output buffer           */
Packit 98cdb6
    EdgeTableEntry *pPrevAET;        /* ptr to previous AET     */
Packit 98cdb6
    EdgeTable ET;                    /* header node for ET      */
Packit 98cdb6
    EdgeTableEntry AET;              /* header node for AET     */
Packit 98cdb6
    EdgeTableEntry *pETEs;           /* EdgeTableEntries pool   */
Packit 98cdb6
    ScanLineListBlock SLLBlock;      /* header for scanlinelist */
Packit 98cdb6
    int fixWAET = FALSE;
Packit 98cdb6
    POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers    */
Packit 98cdb6
    POINTBLOCK *tmpPtBlock;
Packit 98cdb6
    int numFullPtBlocks = 0;
Packit 98cdb6
 
Packit 98cdb6
    region = gdk_region_new ();
Packit 98cdb6
Packit 98cdb6
    /* special case a rectangle */
Packit 98cdb6
    if (((n_points == 4) ||
Packit 98cdb6
	 ((n_points == 5) && (points[4].x == points[0].x) && (points[4].y == points[0].y))) &&
Packit 98cdb6
	(((points[0].y == points[1].y) &&
Packit 98cdb6
	  (points[1].x == points[2].x) &&
Packit 98cdb6
	  (points[2].y == points[3].y) &&
Packit 98cdb6
	  (points[3].x == points[0].x)) ||
Packit 98cdb6
	 ((points[0].x == points[1].x) &&
Packit 98cdb6
	  (points[1].y == points[2].y) &&
Packit 98cdb6
	  (points[2].x == points[3].x) &&
Packit 98cdb6
	  (points[3].y == points[0].y)))) {
Packit 98cdb6
	region->extents.x1 = MIN(points[0].x, points[2].x);
Packit 98cdb6
	region->extents.y1 = MIN(points[0].y, points[2].y);
Packit 98cdb6
	region->extents.x2 = MAX(points[0].x, points[2].x);
Packit 98cdb6
	region->extents.y2 = MAX(points[0].y, points[2].y);
Packit 98cdb6
	if ((region->extents.x1 != region->extents.x2) &&
Packit 98cdb6
	    (region->extents.y1 != region->extents.y2)) {
Packit 98cdb6
	    region->numRects = 1;
Packit 98cdb6
	    *(region->rects) = region->extents;
Packit 98cdb6
	}
Packit 98cdb6
	return(region);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
    pETEs = g_new (EdgeTableEntry, n_points);
Packit 98cdb6
Packit 98cdb6
    pts = FirstPtBlock.pts;
Packit 98cdb6
    CreateETandAET(n_points, points, &ET, &AET, pETEs, &SLLBlock);
Packit 98cdb6
    pSLL = ET.scanlines.next;
Packit 98cdb6
    curPtBlock = &FirstPtBlock;
Packit 98cdb6
 
Packit 98cdb6
    if (fill_rule == GDK_EVEN_ODD_RULE) {
Packit 98cdb6
        /*
Packit 98cdb6
         *  for each scanline
Packit 98cdb6
         */
Packit 98cdb6
        for (y = ET.ymin; y < ET.ymax; y++) {
Packit 98cdb6
            /*
Packit 98cdb6
             *  Add a new edge to the active edge table when we
Packit 98cdb6
             *  get to the next edge.
Packit 98cdb6
             */
Packit 98cdb6
            if (pSLL != NULL && y == pSLL->scanline) {
Packit 98cdb6
                loadAET(&AET, pSLL->edgelist);
Packit 98cdb6
                pSLL = pSLL->next;
Packit 98cdb6
            }
Packit 98cdb6
            pPrevAET = &AET;
Packit 98cdb6
            pAET = AET.next;
Packit 98cdb6
 
Packit 98cdb6
            /*
Packit 98cdb6
             *  for each active edge
Packit 98cdb6
             */
Packit 98cdb6
            while (pAET) {
Packit 98cdb6
                pts->x = pAET->bres.minor_axis,  pts->y = y;
Packit 98cdb6
                pts++, iPts++;
Packit 98cdb6
 
Packit 98cdb6
                /*
Packit 98cdb6
                 *  send out the buffer
Packit 98cdb6
                 */
Packit 98cdb6
                if (iPts == NUMPTSTOBUFFER) {
Packit 98cdb6
                    tmpPtBlock = (POINTBLOCK *)g_malloc(sizeof(POINTBLOCK));
Packit 98cdb6
		    tmpPtBlock->next = NULL;
Packit 98cdb6
                    curPtBlock->next = tmpPtBlock;
Packit 98cdb6
                    curPtBlock = tmpPtBlock;
Packit 98cdb6
                    pts = curPtBlock->pts;
Packit 98cdb6
                    numFullPtBlocks++;
Packit 98cdb6
                    iPts = 0;
Packit 98cdb6
                }
Packit 98cdb6
                EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
Packit 98cdb6
            }
Packit 98cdb6
            (void) InsertionSort(&AET;;
Packit 98cdb6
        }
Packit 98cdb6
    }
Packit 98cdb6
    else {
Packit 98cdb6
        /*
Packit 98cdb6
         *  for each scanline
Packit 98cdb6
         */
Packit 98cdb6
        for (y = ET.ymin; y < ET.ymax; y++) {
Packit 98cdb6
            /*
Packit 98cdb6
             *  Add a new edge to the active edge table when we
Packit 98cdb6
             *  get to the next edge.
Packit 98cdb6
             */
Packit 98cdb6
            if (pSLL != NULL && y == pSLL->scanline) {
Packit 98cdb6
                loadAET(&AET, pSLL->edgelist);
Packit 98cdb6
                computeWAET(&AET;;
Packit 98cdb6
                pSLL = pSLL->next;
Packit 98cdb6
            }
Packit 98cdb6
            pPrevAET = &AET;
Packit 98cdb6
            pAET = AET.next;
Packit 98cdb6
            pWETE = pAET;
Packit 98cdb6
 
Packit 98cdb6
            /*
Packit 98cdb6
             *  for each active edge
Packit 98cdb6
             */
Packit 98cdb6
            while (pAET) {
Packit 98cdb6
                /*
Packit 98cdb6
                 *  add to the buffer only those edges that
Packit 98cdb6
                 *  are in the Winding active edge table.
Packit 98cdb6
                 */
Packit 98cdb6
                if (pWETE == pAET) {
Packit 98cdb6
                    pts->x = pAET->bres.minor_axis,  pts->y = y;
Packit 98cdb6
                    pts++, iPts++;
Packit 98cdb6
 
Packit 98cdb6
                    /*
Packit 98cdb6
                     *  send out the buffer
Packit 98cdb6
                     */
Packit 98cdb6
                    if (iPts == NUMPTSTOBUFFER) {
Packit 98cdb6
                        tmpPtBlock = (POINTBLOCK *)g_malloc(sizeof(POINTBLOCK));
Packit 98cdb6
			tmpPtBlock->next = NULL;
Packit 98cdb6
                        curPtBlock->next = tmpPtBlock;
Packit 98cdb6
                        curPtBlock = tmpPtBlock;
Packit 98cdb6
                        pts = curPtBlock->pts;
Packit 98cdb6
                        numFullPtBlocks++;    iPts = 0;
Packit 98cdb6
                    }
Packit 98cdb6
                    pWETE = pWETE->nextWETE;
Packit 98cdb6
                }
Packit 98cdb6
                EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
Packit 98cdb6
            }
Packit 98cdb6
 
Packit 98cdb6
            /*
Packit 98cdb6
             *  recompute the winding active edge table if
Packit 98cdb6
             *  we just resorted or have exited an edge.
Packit 98cdb6
             */
Packit 98cdb6
            if (InsertionSort(&AET) || fixWAET) {
Packit 98cdb6
                computeWAET(&AET;;
Packit 98cdb6
                fixWAET = FALSE;
Packit 98cdb6
            }
Packit 98cdb6
        }
Packit 98cdb6
    }
Packit 98cdb6
    FreeStorage(SLLBlock.next);	
Packit 98cdb6
    (void) PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
Packit 98cdb6
    for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
Packit 98cdb6
	tmpPtBlock = curPtBlock->next;
Packit 98cdb6
	g_free (curPtBlock);
Packit 98cdb6
	curPtBlock = tmpPtBlock;
Packit 98cdb6
    }
Packit 98cdb6
    g_free (pETEs);
Packit 98cdb6
    return(region);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
#define __GDK_POLYREG_GENERIC_C__
Packit 98cdb6
#include "gdkaliasdef.c"