#include #include "line.h" /* Digital Line Drawing by Paul Heckbert from "Graphics Gems", Academic Press, 1990 * * Updated for interpolation along the line (same style as * in Paul Heckberts generic convex polygon scan convertor) * by Philippe Bekaert, 17 Apr 95 * * Updated to be independent of vertex order by PhB 24 Apr 95 */ /* * digline: draw digital line from (x1,y1) to (x2,y2), * calling a user-supplied procedure at each pixel. * Does no clipping. Uses Bresenham's algorithm. * Paul Heckbert 3 Sep 85 */ #define ABS(x) ((x) < 0 ? -(x) : (x)) #define SGN(x) ((x) < 0 ? -1 : 1) /* * incrementalize_y: put intersection of line Y=y+.5 with edge * between points p1 and p2 in p, put change with respect to y in dp */ static void incrementalize_y(float *p1, float *p2, float *p, float *dp, int y, int mask) { float dy, frac; dy = ((Poly_vert *)p2)->sy - ((Poly_vert *)p1)->sy; if (dy==0.) dy = 1.; frac = y+.5 - ((Poly_vert *)p1)->sy; for (; mask!=0; mask>>=1, p1++, p2++, p++, dp++) if (mask&1) { *dp = (*p2 - *p1) / dy; *p = *p1 + *dp * frac; } } /* * incrementalize_x: put intersection of line X=x+.5 with * edge between points p1 and p2 in p, * put change with respect to x in dp */ static void incrementalize_x(float *p1, float *p2, float *p, float *dp, int x, int mask) { float dx, frac; dx = ((Poly_vert *)p2)->sx - ((Poly_vert *)p1)->sx; if (dx==0.) dx = 1.; frac = x+.5 - ((Poly_vert *)p1)->sx; for (; mask!=0; mask>>=1, p1++, p2++, p++, dp++) if (mask&1) { *dp = (*p2 - *p1) / dx; *p = *p1 + *dp * frac; } } static void increment(float *v, float *dv, int mask) { for (; mask; mask>>=1, v++, dv++) if (mask&1) *v += *dv; } void line_scan(Line *line, void (*dotproc)(int x, int y, Poly_vert *v)) { int x1, x2, y1, y2; int d, x, y, ax, ay, sx, sy, dx, dy; Poly_vert v1, v2, v, dv; x1 = (int)line->v1.sx; x2 = (int)line->v2.sx; y1 = (int)line->v1.sy; y2 = (int)line->v2.sy; dx = x2-x1; ax = ABS(dx)<<1; dy = y2-y1; ay = ABS(dy)<<1; if (ax>ay) { /* x dominant */ if (x1 > x2) { /* make x increase */ v1=line->v2; v2=line->v1; x=x1; x1=x2; x2=x; dx = -dx; y=y1; y1=y2; y2=y; dy = -dy; } else { v1=line->v1; v2=line->v2; } sy = SGN(dy); x = x1; y = y1; incrementalize_x((float *)&v1, (float *)&v2, (float *)&v, (float *)&dv, x1, line->mask); d = ay-(ax>>1); for (;;) { (*dotproc)(x, y, &v); increment((float *)&v, (float *)&dv, line->mask); if (x==x2) break; if (d>=0) { y += sy; d -= ax; } x ++; d += ay; } } else { /* y dominant */ if (y1 > y2) { /* make y increase */ v1=line->v2; v2=line->v1; x=x1; x1=x2; x2=x; dx = -dx; y=y1; y1=y2; y2=y; dy = -dy; } else { v1=line->v1; v2=line->v2; } sx = SGN(dx); x = x1; y = y1; incrementalize_y((float *)&line->v1, (float *)&line->v2, (float *)&v, (float *)&dv, y1, line->mask); d = ax-(ay>>1); for (;;) { (*dotproc)(x, y, &v); increment((float *)&v, (float *)&dv, line->mask); if (y==y2) break; if (d>=0) { x += sx; d -= ay; } y ++; d += ax; } } }