/* * polytoregion * * Scan converts a polygon by returning a run-length * encoding of the resultant bitmap -- the run-length * encoding is in the form of an array of rectangles. */ Region XPolygonRegion( XPoint *Pts, /* the pts */ int Count, /* number of pts */ int rule) /* winding rule */ { Region region; register EdgeTableEntry *pAET; /* Active Edge Table */ register int y; /* current scanline */ register int iPts = 0; /* number of pts in buffer */ register EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/ register ScanLineList *pSLL; /* current scanLineList */ register XPoint *pts; /* output buffer */ EdgeTableEntry *pPrevAET; /* ptr to previous AET */ EdgeTable ET; /* header node for ET */ EdgeTableEntry AET; /* header node for AET */ EdgeTableEntry *pETEs; /* EdgeTableEntries pool */ ScanLineListBlock SLLBlock; /* header for scanlinelist */ int fixWAET = FALSE; POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */ POINTBLOCK *tmpPtBlock; int numFullPtBlocks = 0; if (! (region = XCreateRegion())) return (Region) NULL; /* special case a rectangle */ pts = Pts; if (((Count == 4) || ((Count == 5) && (pts[4].x == pts[0].x) && (pts[4].y == pts[0].y))) && (((pts[0].y == pts[1].y) && (pts[1].x == pts[2].x) && (pts[2].y == pts[3].y) && (pts[3].x == pts[0].x)) || ((pts[0].x == pts[1].x) && (pts[1].y == pts[2].y) && (pts[2].x == pts[3].x) && (pts[3].y == pts[0].y)))) { region->extents.x1 = min(pts[0].x, pts[2].x); region->extents.y1 = min(pts[0].y, pts[2].y); region->extents.x2 = max(pts[0].x, pts[2].x); region->extents.y2 = max(pts[0].y, pts[2].y); if ((region->extents.x1 != region->extents.x2) && (region->extents.y1 != region->extents.y2)) { region->numRects = 1; *(region->rects) = region->extents; } return(region); } if (Count < 2) return region; if (! (pETEs = Xmalloc(sizeof(EdgeTableEntry) * Count))) { XDestroyRegion(region); return (Region) NULL; } pts = FirstPtBlock.pts; CreateETandAET(Count, Pts, &ET, &AET, pETEs, &SLLBlock); pSLL = ET.scanlines.next; curPtBlock = &FirstPtBlock; if (rule == EvenOddRule) { /* * for each scanline */ for (y = ET.ymin; y < ET.ymax; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL != NULL && y == pSLL->scanline) { loadAET(&AET, pSLL->edgelist); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; /* * for each active edge */ while (pAET) { pts->x = pAET->bres.minor_axis, pts->y = y; pts++, iPts++; /* * send out the buffer */ if (iPts == NUMPTSTOBUFFER) { tmpPtBlock = Xmalloc(sizeof(POINTBLOCK)); curPtBlock->next = tmpPtBlock; curPtBlock = tmpPtBlock; pts = curPtBlock->pts; numFullPtBlocks++; iPts = 0; } EVALUATEEDGEEVENODD(pAET, pPrevAET, y); } (void) InsertionSort(&AET); } } else { /* * for each scanline */ for (y = ET.ymin; y < ET.ymax; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL != NULL && y == pSLL->scanline) { loadAET(&AET, pSLL->edgelist); computeWAET(&AET); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; pWETE = pAET; /* * for each active edge */ while (pAET) { /* * add to the buffer only those edges that * are in the Winding active edge table. */ if (pWETE == pAET) { pts->x = pAET->bres.minor_axis, pts->y = y; pts++, iPts++; /* * send out the buffer */ if (iPts == NUMPTSTOBUFFER) { tmpPtBlock = Xmalloc(sizeof(POINTBLOCK)); curPtBlock->next = tmpPtBlock; curPtBlock = tmpPtBlock; pts = curPtBlock->pts; numFullPtBlocks++; iPts = 0; } pWETE = pWETE->nextWETE; } EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET); } /* * recompute the winding active edge table if * we just resorted or have exited an edge. */ if (InsertionSort(&AET) || fixWAET) { computeWAET(&AET); fixWAET = FALSE; } } } FreeStorage(SLLBlock.next); (void) PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region); for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) { tmpPtBlock = curPtBlock->next; Xfree(curPtBlock); curPtBlock = tmpPtBlock; } Xfree(pETEs); return(region); }
/* * GdAllocPolyPolygonRegion */ MWCLIPREGION * GdAllocPolyPolygonRegion(MWPOINT *points, int *count, int nbpolygons, int mode) { MWCLIPREGION *rgn; EdgeTableEntry *pAET; /* Active Edge Table */ int y; /* current scanline */ int iPts = 0; /* number of pts in buffer */ EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/ ScanLineList *pSLL; /* current scanLineList */ MWPOINT *pts; /* output buffer */ EdgeTableEntry *pPrevAET; /* ptr to previous AET */ EdgeTable ET; /* header node for ET */ EdgeTableEntry AET; /* header node for AET */ EdgeTableEntry *pETEs; /* EdgeTableEntries pool */ ScanLineListBlock SLLBlock; /* header for scanlinelist */ int fixWAET = FALSE; POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */ POINTBLOCK *tmpPtBlock; int numFullPtBlocks = 0; int poly, total; if(!(rgn = GdAllocRegion())) return NULL; /* special case a rectangle */ if (((nbpolygons == 1) && ((*count == 4) || ((*count == 5) && (points[4].x == points[0].x) && (points[4].y == points[0].y)))) && (((points[0].y == points[1].y) && (points[1].x == points[2].x) && (points[2].y == points[3].y) && (points[3].x == points[0].x)) || ((points[0].x == points[1].x) && (points[1].y == points[2].y) && (points[2].x == points[3].x) && (points[3].y == points[0].y)))) { GdSetRectRegion( rgn, MWMIN(points[0].x, points[2].x), MWMIN(points[0].y, points[2].y), MWMAX(points[0].x, points[2].x), MWMAX(points[0].y, points[2].y) ); return rgn; } for(poly = total = 0; poly < nbpolygons; poly++) total += count[poly]; if (! (pETEs = malloc( sizeof(EdgeTableEntry) * total ))) { GdDestroyRegion( rgn ); return 0; } pts = FirstPtBlock.pts; REGION_CreateETandAET(count, nbpolygons, points, &ET, &AET, pETEs, &SLLBlock); pSLL = ET.scanlines.next; curPtBlock = &FirstPtBlock; if (mode != MWPOLY_WINDING) { /* * for each scanline */ for (y = ET.ymin; y < ET.ymax; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL != NULL && y == pSLL->scanline) { REGION_loadAET(&AET, pSLL->edgelist); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; /* * for each active edge */ while (pAET) { pts->x = pAET->bres.minor_axis, pts->y = y; pts++, iPts++; /* * send out the buffer */ if (iPts == NUMPTSTOBUFFER) { tmpPtBlock = malloc( sizeof(POINTBLOCK)); if(!tmpPtBlock) { return 0; } curPtBlock->next = tmpPtBlock; curPtBlock = tmpPtBlock; pts = curPtBlock->pts; numFullPtBlocks++; iPts = 0; } EVALUATEEDGEEVENODD(pAET, pPrevAET, y); } REGION_InsertionSort(&AET); } } else { /* * for each scanline */ for (y = ET.ymin; y < ET.ymax; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL != NULL && y == pSLL->scanline) { REGION_loadAET(&AET, pSLL->edgelist); REGION_computeWAET(&AET); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; pWETE = pAET; /* * for each active edge */ while (pAET) { /* * add to the buffer only those edges that * are in the Winding active edge table. */ if (pWETE == pAET) { pts->x = pAET->bres.minor_axis, pts->y = y; pts++, iPts++; /* * send out the buffer */ if (iPts == NUMPTSTOBUFFER) { tmpPtBlock = malloc( sizeof(POINTBLOCK) ); if(!tmpPtBlock) { return 0; } curPtBlock->next = tmpPtBlock; curPtBlock = tmpPtBlock; pts = curPtBlock->pts; numFullPtBlocks++; iPts = 0; } pWETE = pWETE->nextWETE; } EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET); } /* * recompute the winding active edge table if * we just resorted or have exited an edge. */ if (REGION_InsertionSort(&AET) || fixWAET) { REGION_computeWAET(&AET); fixWAET = FALSE; } } } REGION_FreeStorage(SLLBlock.next); REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, rgn); for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) { tmpPtBlock = curPtBlock->next; free( curPtBlock ); curPtBlock = tmpPtBlock; } free( pETEs ); return rgn; }
/* * Written by Brian Kelleher; Oct. 1985 * * Routine to fill a polygon. Two fill rules are supported: frWINDING and * frEVENODD. */ static Bool miFillGeneralPoly(DrawablePtr dst, GCPtr pgc, int count, DDXPointPtr ptsIn) { EdgeTableEntry *pAET; /* the Active Edge Table */ int y; /* the current scanline */ int nPts = 0; /* number of pts in buffer */ EdgeTableEntry *pWETE; /* Winding Edge Table */ ScanLineList *pSLL; /* Current ScanLineList */ DDXPointPtr ptsOut; /* ptr to output buffers */ int *width; DDXPointRec FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */ int FirstWidth[NUMPTSTOBUFFER]; EdgeTableEntry *pPrevAET; /* previous AET entry */ EdgeTable ET; /* Edge Table header node */ EdgeTableEntry AET; /* Active ET header node */ EdgeTableEntry *pETEs; /* Edge Table Entries buff */ ScanLineListBlock SLLBlock; /* header for ScanLineList */ int fixWAET = 0; if (count < 3) return TRUE; if (!(pETEs = malloc(sizeof(EdgeTableEntry) * count))) return FALSE; ptsOut = FirstPoint; width = FirstWidth; if (!miCreateETandAET(count, ptsIn, &ET, &AET, pETEs, &SLLBlock)) { free(pETEs); return FALSE; } pSLL = ET.scanlines.next; if (pgc->fillRule == EvenOddRule) { /* * for each scanline */ for (y = ET.ymin; y < ET.ymax; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL && y == pSLL->scanline) { miloadAET(&AET, pSLL->edgelist); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; /* * for each active edge */ while (pAET) { ptsOut->x = pAET->bres.minor; ptsOut++->y = y; *width++ = pAET->next->bres.minor - pAET->bres.minor; nPts++; /* * send out the buffer when its full */ if (nPts == NUMPTSTOBUFFER) { (*pgc->ops->FillSpans) (dst, pgc, nPts, FirstPoint, FirstWidth, 1); ptsOut = FirstPoint; width = FirstWidth; nPts = 0; } EVALUATEEDGEEVENODD(pAET, pPrevAET, y); EVALUATEEDGEEVENODD(pAET, pPrevAET, y); } miInsertionSort(&AET); } } else { /* default to WindingNumber */ /* * for each scanline */ for (y = ET.ymin; y < ET.ymax; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL && y == pSLL->scanline) { miloadAET(&AET, pSLL->edgelist); micomputeWAET(&AET); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; pWETE = pAET; /* * for each active edge */ while (pAET) { /* * if the next edge in the active edge table is * also the next edge in the winding active edge * table. */ if (pWETE == pAET) { ptsOut->x = pAET->bres.minor; ptsOut++->y = y; *width++ = pAET->nextWETE->bres.minor - pAET->bres.minor; nPts++; /* * send out the buffer */ if (nPts == NUMPTSTOBUFFER) { (*pgc->ops->FillSpans) (dst, pgc, nPts, FirstPoint, FirstWidth, 1); ptsOut = FirstPoint; width = FirstWidth; nPts = 0; } pWETE = pWETE->nextWETE; while (pWETE != pAET) EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET); pWETE = pWETE->nextWETE; } EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET); } /* * reevaluate the Winding active edge table if we * just had to resort it or if we just exited an edge. */ if (miInsertionSort(&AET) || fixWAET) { micomputeWAET(&AET); fixWAET = 0; } } } /* * Get any spans that we missed by buffering */ (*pgc->ops->FillSpans) (dst, pgc, nPts, FirstPoint, FirstWidth, 1); free(pETEs); miFreeStorage(SLLBlock.next); return TRUE; }
/* ARGS: count = number of points, ptsIn = the points */ void miFillGeneralPoly (miPaintedSet *paintedSet, const miGC *pGC, int count, const miPoint *ptsIn) { EdgeTableEntry *pAET; /* the Active Edge Table */ int y; /* the current scanline */ int nPts = 0; /* number of pts in buffer */ EdgeTableEntry *pWETE; /* Winding Edge Table */ ScanLineList *pSLL; /* Current ScanLineList */ miPoint *ptsOut; /* ptr to output buffers */ unsigned int *width; miPoint FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */ unsigned int FirstWidth[NUMPTSTOBUFFER]; EdgeTableEntry *pPrevAET; /* previous AET entry */ EdgeTable ET; /* Edge Table header node */ EdgeTableEntry AET; /* Active ET header node */ EdgeTableEntry *pETEs; /* Edge Table Entries buff */ ScanLineListBlock SLLBlock; /* header for ScanLineList */ bool fixWAET = false; if (count <= 2) return; pETEs = (EdgeTableEntry *) mi_xmalloc(sizeof(EdgeTableEntry) * count); ptsOut = FirstPoint; width = FirstWidth; miCreateETandAET (count, ptsIn, &ET, &AET, pETEs, &SLLBlock); pSLL = ET.scanlines.next; if (pGC->fillRule == (int)MI_EVEN_ODD_RULE) { /* * for each scanline */ for (y = ET.ymin; y < ET.ymax; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL && y == pSLL->scanline) { miloadAET(&AET, pSLL->edgelist); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; /* * for each active edge */ while (pAET) { ptsOut->x = pAET->bres.minor_axis; ptsOut++->y = y; *width++ = (unsigned int)(pAET->next->bres.minor_axis - pAET->bres.minor_axis); nPts++; /* * send out the buffer when its full */ if (nPts == NUMPTSTOBUFFER) { MI_COPY_AND_PAINT_SPANS(paintedSet, pGC->pixels[1], nPts, FirstPoint, FirstWidth) ptsOut = FirstPoint; width = FirstWidth; nPts = 0; } EVALUATEEDGEEVENODD(pAET, pPrevAET, y) EVALUATEEDGEEVENODD(pAET, pPrevAET, y); } miInsertionSort(&AET); } } else /* default to WindingNumber */ { /* * for each scanline */ for (y = ET.ymin; y < ET.ymax; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL && y == pSLL->scanline) { miloadAET(&AET, pSLL->edgelist); micomputeWAET(&AET); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; pWETE = pAET; /* * for each active edge */ while (pAET) { /* * if the next edge in the active edge table is * also the next edge in the winding active edge * table. */ if (pWETE == pAET) { ptsOut->x = pAET->bres.minor_axis; ptsOut++->y = y; *width++ = (unsigned int)(pAET->nextWETE->bres.minor_axis - pAET->bres.minor_axis); nPts++; /* * send out the buffer */ if (nPts == NUMPTSTOBUFFER) { MI_COPY_AND_PAINT_SPANS(paintedSet, pGC->pixels[1], nPts, FirstPoint, FirstWidth) ptsOut = FirstPoint; width = FirstWidth; nPts = 0; } pWETE = pWETE->nextWETE; while (pWETE != pAET) EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET); pWETE = pWETE->nextWETE; } EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET); } /* * reevaluate the Winding active edge table if we * just had to resort it or if we just exited an edge. */ if (miInsertionSort(&AET) || fixWAET) { micomputeWAET(&AET); fixWAET = false; } } } /* * Get any spans that we missed by buffering */ MI_COPY_AND_PAINT_SPANS(paintedSet, pGC->pixels[1], nPts, FirstPoint, FirstWidth) free (pETEs); miFreeStorage(SLLBlock.next); }