/** * Draw a polygon in the foreground color, applying clipping if necessary. * The polygon is only closed if the first point is repeated at the end. * Some care is taken to plot the endpoints correctly if the current * drawing mode is XOR. However, internal crossings are not handled * correctly. * * @param psd Drawing surface. * @param count Number of points in polygon. * @param points The array of points. */ void GdPoly(PSD psd, int count, MWPOINT *points) { MWCOORD firstx; MWCOORD firsty; MWBOOL didline; if (count < 2) return; firstx = points->x; firsty = points->y; didline = FALSE; while (count-- > 1) { if (didline && (gr_mode == MWMODE_XOR)) drawpoint(psd, points->x, points->y); /* note: change to drawline*/ GdLine(psd, points[0].x, points[0].y, points[1].x, points[1].y, TRUE); points++; didline = TRUE; } if (gr_mode == MWMODE_XOR) { points--; if (points->x == firstx && points->y == firsty) drawpoint(psd, points->x, points->y); } GdFixCursor(psd); }
void GdFillPoly(PSD psd, int count, MWPOINT *points) { MWPOINT *pp; /* current point */ MWCOORD miny; /* minimum row */ MWCOORD maxy; /* maximum row */ MWCOORD minx; /* minimum column */ MWCOORD maxx; /* maximum column */ int i; /* counter */ if (count <= 0) return; /* First determine the minimum and maximum rows for the polygon. */ pp = points; miny = pp->y; maxy = pp->y; for (i = count; i-- > 0; pp++) { if (miny > pp->y) miny = pp->y; if (maxy < pp->y) maxy = pp->y; } if (miny < 0) miny = 0; if (maxy >= psd->yvirtres) maxy = psd->yvirtres - 1; if (miny > maxy) return; /* Now for each row, scan the list of points and determine the * minimum and maximum x coordinate for each line, and plot the row. * The last point connects with the first point automatically. */ for (; miny <= maxy; miny++) { minx = MAX_MWCOORD; maxx = MIN_MWCOORD; pp = points; for (i = count; --i > 0; pp++) extendrow(miny, pp[0].x, pp[0].y, pp[1].x, pp[1].y, &minx, &maxx); extendrow(miny, pp[0].x, pp[0].y, points[0].x, points[0].y, &minx, &maxx); if (minx <= maxx) drawrow(psd, minx, maxx, miny); } GdFixCursor(psd); }
static void debug_putchar_graphics (void *arg, short ch) { PSD psd = (PSD) arg; MWCOORD width; /* width of text area */ MWCOORD height; /* height of text area */ MWCOORD base; /* baseline of text */ const MWIMAGEBITS *bitmap; /* bitmap for characters */ MWPIXELVAL saved_foreground; MWPIXELVAL saved_background; MWBOOL saved_usebg; int saved_mode; extern MWPIXELVAL gr_foreground; extern MWBOOL gr_usebg; /* Use default system FIXED font. */ gen_gettextbits ((PMWFONT) &gen_fonts[1], ch, &bitmap, &width, &height, &base); /* Put character, move cursor. */ switch (ch) { case '\n': debug_x = 0; debug_y += height; break; case '\r': debug_x = 0; break; case '\t': /* Tab stops at every 4 char heights. */ debug_x = ((debug_x / height) + 4) / 4 * 4 * height; break; case '\b': if (debug_x >= width) debug_x -= width; break; default: /* Draw in COPY mode with black background. */ saved_foreground = gr_foreground; saved_background = gr_background; saved_usebg = gr_usebg; saved_mode = gr_mode; gr_foreground = ~0L; gr_background = 0; gr_usebg = TRUE; gr_mode = MWMODE_COPY; drawbitmap (psd, debug_x, debug_y, width, height, bitmap); gr_foreground = saved_foreground; gr_background = saved_background; gr_usebg = saved_usebg; gr_mode = saved_mode; GdFixCursor (psd); debug_x += width; break; } if (debug_x + width > psd->xvirtres) { /* Roll over right margin. */ debug_x = 0; debug_y += height; } if (debug_y + height > psd->yvirtres) { /* Roll over the screen. */ debug_y = 0; } }
/** * Draw a filled polygon. * * @param psd Drawing surface. * @param count Number of points in polygon. * @param pointtable The array of points. */ void GdFillPoly(PSD psd, int count, MWPOINT * pointtable) { edge_t *get; /* global edge table */ int nge = 0; /* num global edges */ int cge = 0; /* cur global edge */ edge_t *aet; /* active edge table */ int nae = 0; /* num active edges */ int i, y; if (count < 3) { /* error, polygons require at least three edges (a triangle) */ return; } get = (edge_t *) calloc(count, sizeof(edge_t)); aet = (edge_t *) calloc(count, sizeof(edge_t)); if ((get == 0) || (aet == 0)) { /* error, couldn't allocate one or both of the needed tables */ if (get) free(get); if (aet) free(aet); return; } /* setup the global edge table */ for (i = 0; i < count; ++i) { get[nge].x1 = pointtable[i].x; get[nge].y1 = pointtable[i].y; get[nge].x2 = pointtable[(i + 1) % count].x; get[nge].y2 = pointtable[(i + 1) % count].y; if (get[nge].y1 != get[nge].y2) { if (get[nge].y1 > get[nge].y2) { swap(get[nge].x1, get[nge].x2); swap(get[nge].y1, get[nge].y2); } #if USE_FLOAT get[nge].x = get[nge].x1; get[nge].m = get[nge].x2 - get[nge].x1; get[nge].m /= get[nge].y2 - get[nge].y1; #else get[nge].cx = get[nge].x1; get[nge].mn = get[nge].x2 - get[nge].x1; get[nge].d = get[nge].y2 - get[nge].y1; get[nge].fn = get[nge].mn / 2; #endif ++nge; } } qsort(get, nge, sizeof(get[0]), edge_cmp); /* start with the lowest y in the table */ y = get[0].y1; do { /* add edges to the active table from the global table */ while ((nge > 0) && (get[cge].y1 == y)) { aet[nae] = get[cge++]; --nge; aet[nae++].y1 = 0; } qsort(aet, nae, sizeof(aet[0]), edge_cmp); /* using odd parity, render alternating line segments */ for (i = 1; i < nae; i += 2) { #if USE_FLOAT int l = (int)aet[i - 1].x; int r = (int)aet[i].x; #else int l = (int)aet[i - 1].cx; int r = (int)aet[i].cx; #endif if (r > l) drawrow(psd, l, r - 1, y); } /* prepare for the next scan line */ ++y; /* remove inactive edges from the active edge table */ /* or update the current x position of active edges */ for (i = 0; i < nae; ++i) { if (aet[i].y2 == y) aet[i--] = aet[--nae]; else { #if USE_FLOAT aet[i].x += aet[i].m; #else aet[i].fn += aet[i].mn; if (aet[i].fn < 0) { aet[i].cx += aet[i].fn / aet[i].d - 1; aet[i].fn %= aet[i].d; aet[i].fn += aet[i].d; } if (aet[i].fn >= aet[i].d) { aet[i].cx += aet[i].fn / aet[i].d; aet[i].fn %= aet[i].d; } #endif } } /* keep doing this while there are any edges left */ } while ((nae > 0) || (nge > 0)); /* all done, free the edge tables */ free(get); free(aet); GdFixCursor(psd); }
void GdFillPoly(PSD psd, int count, MWPOINT *pointtable) { MWCOORD xl = 0, xr = 0; /* x vals of left and right edges */ int dl = 0, dr = 0; /* decision variables */ int ml = 0, m1l = 0; /* left edge slope and slope+1 */ int mr = 0, m1r = 0; /* right edge slope and slope+1 */ int incr1l = 0, incr2l = 0; /* left edge error increments */ int incr1r = 0, incr2r = 0; /* right edge error increments */ int dy; /* delta y */ MWCOORD y; /* current scanline */ int left, right; /* indices to first endpoints */ int i; /* loop counter */ int nextleft, nextright; /* indices to second endpoints */ MWPOINT *ptsOut, *FirstPoint;/* output buffer */ MWCOORD *width, *FirstWidth;/* output buffer */ int imin; /* index of smallest vertex (in y)*/ int ymin; /* y-extents of polygon */ int ymax; /* * find leftx, bottomy, rightx, topy, and the index * of bottomy. */ imin = getPolyYBounds(pointtable, count, &ymin, &ymax); if (gr_fillmode != MWFILL_SOLID) { int xmin, xmax; getPolyXBounds(pointtable, count, &xmin, &xmax); set_ts_origin(xmin, ymin); } dy = ymax - ymin + 1; if ((count < 3) || (dy < 0)) return; ptsOut = FirstPoint = (MWPOINT *)ALLOCA(sizeof(MWPOINT) * dy); width = FirstWidth = (MWCOORD *)ALLOCA(sizeof(MWCOORD) * dy); if(!FirstPoint || !FirstWidth) { if (FirstWidth) FREEA(FirstWidth); if (FirstPoint) FREEA(FirstPoint); return; } nextleft = nextright = imin; y = pointtable[nextleft].y; /* * loop through all edges of the polygon */ do { /* * add a left edge if we need to */ if (pointtable[nextleft].y == y) { left = nextleft; /* * find the next edge, considering the end * conditions of the array. */ nextleft++; if (nextleft >= count) nextleft = 0; /* * now compute all of the random information * needed to run the iterative algorithm. */ BRESINITPGON(pointtable[nextleft].y-pointtable[left].y, pointtable[left].x,pointtable[nextleft].x, xl, dl, ml, m1l, incr1l, incr2l); } /* * add a right edge if we need to */ if (pointtable[nextright].y == y) { right = nextright; /* * find the next edge, considering the end * conditions of the array. */ nextright--; if (nextright < 0) nextright = count-1; /* * now compute all of the random information * needed to run the iterative algorithm. */ BRESINITPGON(pointtable[nextright].y-pointtable[right].y, pointtable[right].x,pointtable[nextright].x, xr, dr, mr, m1r, incr1r, incr2r); } /* * generate scans to fill while we still have * a right edge as well as a left edge. */ i = MWMIN(pointtable[nextleft].y, pointtable[nextright].y) - y; /* in case we're called with non-convex polygon */ if(i < 0) { FREEA(FirstWidth); FREEA(FirstPoint); return; } while (i-- > 0) { ptsOut->y = y; /* * reverse the edges if necessary */ if (xl < xr) { *(width++) = xr - xl; (ptsOut++)->x = xl; } else { *(width++) = xl - xr; (ptsOut++)->x = xr; } y++; /* increment down the edges */ BRESINCRPGON(dl, xl, ml, m1l, incr1l, incr2l); BRESINCRPGON(dr, xr, mr, m1r, incr1r, incr2r); } } while (y != ymax); /* * Finally, fill the spans */ i = ptsOut-FirstPoint; ptsOut = FirstPoint; width = FirstWidth; while (--i >= 0) { /* calc x extent from width*/ int e = *width++ - 1; if (e >= 0) { if (gr_fillmode != MWFILL_SOLID) ts_drawrow(psd, ptsOut->x, ptsOut->x + e, ptsOut->y); else drawrow(psd, ptsOut->x, ptsOut->x + e, ptsOut->y); } ++ptsOut; } FREEA(FirstWidth); FREEA(FirstPoint); GdFixCursor(psd); }