summaryrefslogtreecommitdiff
path: root/mi/mipoly.c
diff options
context:
space:
mode:
authorAdam Jackson <ajax@redhat.com>2014-09-26 12:34:15 -0400
committerAdam Jackson <ajax@redhat.com>2014-10-27 15:45:28 -0400
commit3b63900e90f44cf85a4d3391d23407b3bb6db52b (patch)
treed22779fbc3565d7a8505aecbfd32159673b0cc0a /mi/mipoly.c
parent21b041ef48c49ff6fc06f6e4482ffe54cb763493 (diff)
mi: Fold mipolyutil.c into mipoly.c
Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Adam Jackson <ajax@redhat.com>
Diffstat (limited to 'mi/mipoly.c')
-rw-r--r--mi/mipoly.c285
1 files changed, 285 insertions, 0 deletions
diff --git a/mi/mipoly.c b/mi/mipoly.c
index 3d49789b0..0ed2edb44 100644
--- a/mi/mipoly.c
+++ b/mi/mipoly.c
@@ -61,6 +61,291 @@ SOFTWARE.
#include "mipoly.h"
#include "regionstr.h"
+/*
+ * Insert the given edge into the edge table. First we must find the correct
+ * bucket in the Edge table, then find the right slot in the bucket. Finally,
+ * we can insert it.
+ */
+static Bool
+miInsertEdgeInET(EdgeTable * ET, EdgeTableEntry * ETE, int scanline,
+ ScanLineListBlock ** SLLBlock, int *iSLLBlock)
+{
+ EdgeTableEntry *start, *prev;
+ ScanLineList *pSLL, *pPrevSLL;
+ ScanLineListBlock *tmpSLLBlock;
+
+ /*
+ * find the right bucket to put the edge into
+ */
+ pPrevSLL = &ET->scanlines;
+ pSLL = pPrevSLL->next;
+ while (pSLL && (pSLL->scanline < scanline)) {
+ pPrevSLL = pSLL;
+ pSLL = pSLL->next;
+ }
+
+ /*
+ * reassign pSLL (pointer to ScanLineList) if necessary
+ */
+ if ((!pSLL) || (pSLL->scanline > scanline)) {
+ if (*iSLLBlock > SLLSPERBLOCK - 1) {
+ tmpSLLBlock = malloc(sizeof(ScanLineListBlock));
+ if (!tmpSLLBlock)
+ return FALSE;
+ (*SLLBlock)->next = tmpSLLBlock;
+ tmpSLLBlock->next = NULL;
+ *SLLBlock = tmpSLLBlock;
+ *iSLLBlock = 0;
+ }
+ pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
+
+ pSLL->next = pPrevSLL->next;
+ pSLL->edgelist = NULL;
+ pPrevSLL->next = pSLL;
+ }
+ pSLL->scanline = scanline;
+
+ /*
+ * now insert the edge in the right bucket
+ */
+ prev = NULL;
+ start = pSLL->edgelist;
+ while (start && (start->bres.minor < ETE->bres.minor)) {
+ prev = start;
+ start = start->next;
+ }
+ ETE->next = start;
+
+ if (prev)
+ prev->next = ETE;
+ else
+ pSLL->edgelist = ETE;
+ return TRUE;
+}
+
+static void
+miFreeStorage(ScanLineListBlock * pSLLBlock)
+{
+ ScanLineListBlock *tmpSLLBlock;
+
+ while (pSLLBlock) {
+ tmpSLLBlock = pSLLBlock->next;
+ free(pSLLBlock);
+ pSLLBlock = tmpSLLBlock;
+ }
+}
+
+/*
+ * CreateEdgeTable
+ *
+ * This routine creates the edge table for scan converting polygons.
+ * The Edge Table (ET) looks like:
+ *
+ * EdgeTable
+ * --------
+ * | ymax | ScanLineLists
+ * |scanline|-->------------>-------------->...
+ * -------- |scanline| |scanline|
+ * |edgelist| |edgelist|
+ * --------- ---------
+ * | |
+ * | |
+ * V V
+ * list of ETEs list of ETEs
+ *
+ * where ETE is an EdgeTableEntry data structure, and there is one ScanLineList
+ * per scanline at which an edge is initially entered.
+ */
+
+static Bool
+miCreateETandAET(int count, DDXPointPtr pts, EdgeTable * ET,
+ EdgeTableEntry * AET, EdgeTableEntry * pETEs,
+ ScanLineListBlock * pSLLBlock)
+{
+ DDXPointPtr top, bottom;
+ DDXPointPtr PrevPt, CurrPt;
+ int iSLLBlock = 0;
+
+ int dy;
+
+ if (count < 2)
+ return TRUE;
+
+ /*
+ * initialize the Active Edge Table
+ */
+ AET->next = NULL;
+ AET->back = NULL;
+ AET->nextWETE = NULL;
+ AET->bres.minor = MININT;
+
+ /*
+ * initialize the Edge Table.
+ */
+ ET->scanlines.next = NULL;
+ ET->ymax = MININT;
+ ET->ymin = MAXINT;
+ pSLLBlock->next = NULL;
+
+ PrevPt = &pts[count - 1];
+
+ /*
+ * for each vertex in the array of points.
+ * In this loop we are dealing with two vertices at
+ * a time -- these make up one edge of the polygon.
+ */
+ while (count--) {
+ CurrPt = pts++;
+
+ /*
+ * find out which point is above and which is below.
+ */
+ if (PrevPt->y > CurrPt->y) {
+ bottom = PrevPt, top = CurrPt;
+ pETEs->ClockWise = 0;
+ }
+ else {
+ bottom = CurrPt, top = PrevPt;
+ pETEs->ClockWise = 1;
+ }
+
+ /*
+ * don't add horizontal edges to the Edge table.
+ */
+ if (bottom->y != top->y) {
+ pETEs->ymax = bottom->y - 1; /* -1 so we don't get last scanline */
+
+ /*
+ * initialize integer edge algorithm
+ */
+ dy = bottom->y - top->y;
+ BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
+
+ if (!miInsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock)) {
+ miFreeStorage(pSLLBlock->next);
+ return FALSE;
+ }
+
+ ET->ymax = max(ET->ymax, PrevPt->y);
+ ET->ymin = min(ET->ymin, PrevPt->y);
+ pETEs++;
+ }
+
+ PrevPt = CurrPt;
+ }
+ return TRUE;
+}
+
+/*
+ * This routine moves EdgeTableEntries from the EdgeTable into the Active Edge
+ * Table, leaving them sorted by smaller x coordinate.
+ */
+
+static void
+miloadAET(EdgeTableEntry * AET, EdgeTableEntry * ETEs)
+{
+ EdgeTableEntry *pPrevAET;
+ EdgeTableEntry *tmp;
+
+ pPrevAET = AET;
+ AET = AET->next;
+ while (ETEs) {
+ while (AET && (AET->bres.minor < ETEs->bres.minor)) {
+ pPrevAET = AET;
+ AET = AET->next;
+ }
+ tmp = ETEs->next;
+ ETEs->next = AET;
+ if (AET)
+ AET->back = ETEs;
+ ETEs->back = pPrevAET;
+ pPrevAET->next = ETEs;
+ pPrevAET = ETEs;
+
+ ETEs = tmp;
+ }
+}
+
+/*
+ * computeWAET
+ *
+ * This routine links the AET by the nextWETE (winding EdgeTableEntry) link for
+ * use by the winding number rule. The final Active Edge Table (AET) might
+ * look something like:
+ *
+ * AET
+ * ---------- --------- ---------
+ * |ymax | |ymax | |ymax |
+ * | ... | |... | |... |
+ * |next |->|next |->|next |->...
+ * |nextWETE| |nextWETE| |nextWETE|
+ * --------- --------- ^--------
+ * | | |
+ * V-------------------> V---> ...
+ *
+ */
+static void
+micomputeWAET(EdgeTableEntry * AET)
+{
+ EdgeTableEntry *pWETE;
+ int inside = 1;
+ int isInside = 0;
+
+ AET->nextWETE = NULL;
+ pWETE = AET;
+ AET = AET->next;
+ while (AET) {
+ if (AET->ClockWise)
+ isInside++;
+ else
+ isInside--;
+
+ if ((!inside && !isInside) || (inside && isInside)) {
+ pWETE->nextWETE = AET;
+ pWETE = AET;
+ inside = !inside;
+ }
+ AET = AET->next;
+ }
+ pWETE->nextWETE = NULL;
+}
+
+/*
+ * Just a simple insertion sort using pointers and back pointers to sort the
+ * Active Edge Table.
+ */
+
+static int
+miInsertionSort(EdgeTableEntry * AET)
+{
+ EdgeTableEntry *pETEchase;
+ EdgeTableEntry *pETEinsert;
+ EdgeTableEntry *pETEchaseBackTMP;
+ int changed = 0;
+
+ AET = AET->next;
+ while (AET) {
+ pETEinsert = AET;
+ pETEchase = AET;
+ while (pETEchase->back->bres.minor > AET->bres.minor)
+ pETEchase = pETEchase->back;
+
+ AET = AET->next;
+ if (pETEchase != pETEinsert) {
+ pETEchaseBackTMP = pETEchase->back;
+ pETEinsert->back->next = AET;
+ if (AET)
+ AET->back = pETEinsert->back;
+ pETEinsert->next = pETEchase;
+ pETEchase->back->next = pETEinsert;
+ pETEchase->back = pETEinsert;
+ pETEinsert->back = pETEchaseBackTMP;
+ changed = 1;
+ }
+ }
+ return changed;
+}
+
/* Find the index of the point with the smallest y */
static int
getPolyYBounds(DDXPointPtr pts, int n, int *by, int *ty)