xref: /plan9/sys/src/cmd/unix/drawterm/libmemdraw/fillpoly.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1*8ccd4a63SDavid du Colombier #include <u.h>
2*8ccd4a63SDavid du Colombier #include <libc.h>
3*8ccd4a63SDavid du Colombier #include <draw.h>
4*8ccd4a63SDavid du Colombier #include <memdraw.h>
5*8ccd4a63SDavid du Colombier #include <memlayer.h>
67dd7cddfSDavid du Colombier 
77dd7cddfSDavid du Colombier typedef struct Seg	Seg;
87dd7cddfSDavid du Colombier 
97dd7cddfSDavid du Colombier struct Seg
107dd7cddfSDavid du Colombier {
117dd7cddfSDavid du Colombier 	Point	p0;
127dd7cddfSDavid du Colombier 	Point	p1;
137dd7cddfSDavid du Colombier 	long	num;
147dd7cddfSDavid du Colombier 	long	den;
157dd7cddfSDavid du Colombier 	long	dz;
167dd7cddfSDavid du Colombier 	long	dzrem;
177dd7cddfSDavid du Colombier 	long	z;
187dd7cddfSDavid du Colombier 	long	zerr;
197dd7cddfSDavid du Colombier 	long	d;
207dd7cddfSDavid du Colombier };
217dd7cddfSDavid du Colombier 
227dd7cddfSDavid du Colombier static	void	zsort(Seg **seg, Seg **ep);
23*8ccd4a63SDavid du Colombier static	int	ycompare(const void*, const void*);
24*8ccd4a63SDavid du Colombier static	int	xcompare(const void*, const void*);
25*8ccd4a63SDavid du Colombier static	int	zcompare(const void*, const void*);
26*8ccd4a63SDavid du Colombier static	void	xscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int, int, int, int);
27*8ccd4a63SDavid du Colombier static	void	yscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int, int);
287dd7cddfSDavid du Colombier 
29*8ccd4a63SDavid du Colombier #ifdef NOT
307dd7cddfSDavid du Colombier static void
fillcolor(Memimage * dst,int left,int right,int y,Memimage * src,Point p)317dd7cddfSDavid du Colombier fillcolor(Memimage *dst, int left, int right, int y, Memimage *src, Point p)
327dd7cddfSDavid du Colombier {
337dd7cddfSDavid du Colombier 	int srcval;
347dd7cddfSDavid du Colombier 
357dd7cddfSDavid du Colombier 	USED(src);
367dd7cddfSDavid du Colombier 	srcval = p.x;
377dd7cddfSDavid du Colombier 	p.x = left;
387dd7cddfSDavid du Colombier 	p.y = y;
397dd7cddfSDavid du Colombier 	memset(byteaddr(dst, p), srcval, right-left);
407dd7cddfSDavid du Colombier }
41*8ccd4a63SDavid du Colombier #endif
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier static void
fillline(Memimage * dst,int left,int right,int y,Memimage * src,Point p,int op)44*8ccd4a63SDavid du Colombier fillline(Memimage *dst, int left, int right, int y, Memimage *src, Point p, int op)
457dd7cddfSDavid du Colombier {
467dd7cddfSDavid du Colombier 	Rectangle r;
477dd7cddfSDavid du Colombier 
487dd7cddfSDavid du Colombier 	r.min.x = left;
497dd7cddfSDavid du Colombier 	r.min.y = y;
507dd7cddfSDavid du Colombier 	r.max.x = right;
517dd7cddfSDavid du Colombier 	r.max.y = y+1;
527dd7cddfSDavid du Colombier 	p.x += left;
537dd7cddfSDavid du Colombier 	p.y += y;
54*8ccd4a63SDavid du Colombier 	memdraw(dst, r, src, p, memopaque, p, op);
557dd7cddfSDavid du Colombier }
567dd7cddfSDavid du Colombier 
577dd7cddfSDavid du Colombier static void
fillpoint(Memimage * dst,int x,int y,Memimage * src,Point p,int op)58*8ccd4a63SDavid du Colombier fillpoint(Memimage *dst, int x, int y, Memimage *src, Point p, int op)
597dd7cddfSDavid du Colombier {
607dd7cddfSDavid du Colombier 	Rectangle r;
617dd7cddfSDavid du Colombier 
627dd7cddfSDavid du Colombier 	r.min.x = x;
637dd7cddfSDavid du Colombier 	r.min.y = y;
647dd7cddfSDavid du Colombier 	r.max.x = x+1;
657dd7cddfSDavid du Colombier 	r.max.y = y+1;
667dd7cddfSDavid du Colombier 	p.x += x;
677dd7cddfSDavid du Colombier 	p.y += y;
68*8ccd4a63SDavid du Colombier 	memdraw(dst, r, src, p, memopaque, p, op);
697dd7cddfSDavid du Colombier }
707dd7cddfSDavid du Colombier 
717dd7cddfSDavid du Colombier void
memfillpoly(Memimage * dst,Point * vert,int nvert,int w,Memimage * src,Point sp,int op)72*8ccd4a63SDavid du Colombier memfillpoly(Memimage *dst, Point *vert, int nvert, int w, Memimage *src, Point sp, int op)
737dd7cddfSDavid du Colombier {
74*8ccd4a63SDavid du Colombier 	_memfillpolysc(dst, vert, nvert, w, src, sp, 0, 0, 0, op);
757dd7cddfSDavid du Colombier }
767dd7cddfSDavid du Colombier 
777dd7cddfSDavid du Colombier void
_memfillpolysc(Memimage * dst,Point * vert,int nvert,int w,Memimage * src,Point sp,int detail,int fixshift,int clipped,int op)78*8ccd4a63SDavid du Colombier _memfillpolysc(Memimage *dst, Point *vert, int nvert, int w, Memimage *src, Point sp, int detail, int fixshift, int clipped, int op)
797dd7cddfSDavid du Colombier {
807dd7cddfSDavid du Colombier 	Seg **seg, *segtab;
817dd7cddfSDavid du Colombier 	Point p0;
827dd7cddfSDavid du Colombier 	int i;
837dd7cddfSDavid du Colombier 
847dd7cddfSDavid du Colombier 	if(nvert == 0)
857dd7cddfSDavid du Colombier 		return;
867dd7cddfSDavid du Colombier 
877dd7cddfSDavid du Colombier 	seg = malloc((nvert+2)*sizeof(Seg*));
887dd7cddfSDavid du Colombier 	if(seg == nil)
897dd7cddfSDavid du Colombier 		return;
907dd7cddfSDavid du Colombier 	segtab = malloc((nvert+1)*sizeof(Seg));
917dd7cddfSDavid du Colombier 	if(segtab == nil) {
927dd7cddfSDavid du Colombier 		free(seg);
937dd7cddfSDavid du Colombier 		return;
947dd7cddfSDavid du Colombier 	}
957dd7cddfSDavid du Colombier 
967dd7cddfSDavid du Colombier 	sp.x = (sp.x - vert[0].x) >> fixshift;
977dd7cddfSDavid du Colombier 	sp.y = (sp.y - vert[0].y) >> fixshift;
987dd7cddfSDavid du Colombier 	p0 = vert[nvert-1];
997dd7cddfSDavid du Colombier 	if(!fixshift) {
1007dd7cddfSDavid du Colombier 		p0.x <<= 1;
1017dd7cddfSDavid du Colombier 		p0.y <<= 1;
1027dd7cddfSDavid du Colombier 	}
1037dd7cddfSDavid du Colombier 	for(i = 0; i < nvert; i++) {
1047dd7cddfSDavid du Colombier 		segtab[i].p0 = p0;
1057dd7cddfSDavid du Colombier 		p0 = vert[i];
1067dd7cddfSDavid du Colombier 		if(!fixshift) {
1077dd7cddfSDavid du Colombier 			p0.x <<= 1;
1087dd7cddfSDavid du Colombier 			p0.y <<= 1;
1097dd7cddfSDavid du Colombier 		}
1107dd7cddfSDavid du Colombier 		segtab[i].p1 = p0;
1117dd7cddfSDavid du Colombier 		segtab[i].d = 1;
1127dd7cddfSDavid du Colombier 	}
1137dd7cddfSDavid du Colombier 	if(!fixshift)
1147dd7cddfSDavid du Colombier 		fixshift = 1;
1157dd7cddfSDavid du Colombier 
116*8ccd4a63SDavid du Colombier 	xscan(dst, seg, segtab, nvert, w, src, sp, detail, fixshift, clipped, op);
1177dd7cddfSDavid du Colombier 	if(detail)
118*8ccd4a63SDavid du Colombier 		yscan(dst, seg, segtab, nvert, w, src, sp, fixshift, op);
1197dd7cddfSDavid du Colombier 
1207dd7cddfSDavid du Colombier 	free(seg);
1217dd7cddfSDavid du Colombier 	free(segtab);
1227dd7cddfSDavid du Colombier }
1237dd7cddfSDavid du Colombier 
1247dd7cddfSDavid du Colombier static long
mod(long x,long y)1257dd7cddfSDavid du Colombier mod(long x, long y)
1267dd7cddfSDavid du Colombier {
1277dd7cddfSDavid du Colombier 	long z;
1287dd7cddfSDavid du Colombier 
1297dd7cddfSDavid du Colombier 	z = x%y;
1307dd7cddfSDavid du Colombier 	if((long)(((ulong)z)^((ulong)y)) > 0 || z == 0)
1317dd7cddfSDavid du Colombier 		return z;
1327dd7cddfSDavid du Colombier 	return z + y;
1337dd7cddfSDavid du Colombier }
1347dd7cddfSDavid du Colombier 
1357dd7cddfSDavid du Colombier static long
sdiv(long x,long y)1367dd7cddfSDavid du Colombier sdiv(long x, long y)
1377dd7cddfSDavid du Colombier {
1387dd7cddfSDavid du Colombier 	if((long)(((ulong)x)^((ulong)y)) >= 0 || x == 0)
1397dd7cddfSDavid du Colombier 		return x/y;
1407dd7cddfSDavid du Colombier 
1417dd7cddfSDavid du Colombier 	return (x+((y>>30)|1))/y-1;
1427dd7cddfSDavid du Colombier }
1437dd7cddfSDavid du Colombier 
1447dd7cddfSDavid du Colombier static long
smuldivmod(long x,long y,long z,long * mod)1457dd7cddfSDavid du Colombier smuldivmod(long x, long y, long z, long *mod)
1467dd7cddfSDavid du Colombier {
1477dd7cddfSDavid du Colombier 	vlong vx;
1487dd7cddfSDavid du Colombier 
1497dd7cddfSDavid du Colombier 	if(x == 0 || y == 0){
1507dd7cddfSDavid du Colombier 		*mod = 0;
1517dd7cddfSDavid du Colombier 		return 0;
1527dd7cddfSDavid du Colombier 	}
1537dd7cddfSDavid du Colombier 	vx = x;
1547dd7cddfSDavid du Colombier 	vx *= y;
1557dd7cddfSDavid du Colombier 	*mod = vx % z;
1567dd7cddfSDavid du Colombier 	if(*mod < 0)
1577dd7cddfSDavid du Colombier 		*mod += z;	/* z is always >0 */
1587dd7cddfSDavid du Colombier 	if((vx < 0) == (z < 0))
1597dd7cddfSDavid du Colombier 		return vx/z;
1607dd7cddfSDavid du Colombier 	return -((-vx)/z);
1617dd7cddfSDavid du Colombier }
1627dd7cddfSDavid du Colombier 
1637dd7cddfSDavid du Colombier static void
xscan(Memimage * dst,Seg ** seg,Seg * segtab,int nseg,int wind,Memimage * src,Point sp,int detail,int fixshift,int clipped,int op)164*8ccd4a63SDavid du Colombier xscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int detail, int fixshift, int clipped, int op)
1657dd7cddfSDavid du Colombier {
1667dd7cddfSDavid du Colombier 	long y, maxy, x, x2, xerr, xden, onehalf;
1677dd7cddfSDavid du Colombier 	Seg **ep, **next, **p, **q, *s;
1687dd7cddfSDavid du Colombier 	long n, i, iy, cnt, ix, ix2, minx, maxx;
1697dd7cddfSDavid du Colombier 	Point pt;
170*8ccd4a63SDavid du Colombier 	void	(*fill)(Memimage*, int, int, int, Memimage*, Point, int);
1717dd7cddfSDavid du Colombier 
1727dd7cddfSDavid du Colombier 	fill = fillline;
1737dd7cddfSDavid du Colombier /*
1747dd7cddfSDavid du Colombier  * This can only work on 8-bit destinations, since fillcolor is
1757dd7cddfSDavid du Colombier  * just using memset on sp.x.
1767dd7cddfSDavid du Colombier  *
1777dd7cddfSDavid du Colombier  * I'd rather not even enable it then, since then if the general
1787dd7cddfSDavid du Colombier  * code is too slow, someone will come up with a better improvement
1797dd7cddfSDavid du Colombier  * than this sleazy hack.	-rsc
1807dd7cddfSDavid du Colombier  *
1817dd7cddfSDavid du Colombier 	if(clipped && (src->flags&Frepl) && src->depth==8 && Dx(src->r)==1 && Dy(src->r)==1) {
1827dd7cddfSDavid du Colombier 		fill = fillcolor;
1837dd7cddfSDavid du Colombier 		sp.x = membyteval(src);
1847dd7cddfSDavid du Colombier 	}
1857dd7cddfSDavid du Colombier  *
1867dd7cddfSDavid du Colombier  */
1877dd7cddfSDavid du Colombier 	USED(clipped);
1887dd7cddfSDavid du Colombier 
1897dd7cddfSDavid du Colombier 
1907dd7cddfSDavid du Colombier 	for(i=0, s=segtab, p=seg; i<nseg; i++, s++) {
1917dd7cddfSDavid du Colombier 		*p = s;
1927dd7cddfSDavid du Colombier 		if(s->p0.y == s->p1.y)
1937dd7cddfSDavid du Colombier 			continue;
1947dd7cddfSDavid du Colombier 		if(s->p0.y > s->p1.y) {
1957dd7cddfSDavid du Colombier 			pt = s->p0;
1967dd7cddfSDavid du Colombier 			s->p0 = s->p1;
1977dd7cddfSDavid du Colombier 			s->p1 = pt;
1987dd7cddfSDavid du Colombier 			s->d = -s->d;
1997dd7cddfSDavid du Colombier 		}
2007dd7cddfSDavid du Colombier 		s->num = s->p1.x - s->p0.x;
2017dd7cddfSDavid du Colombier 		s->den = s->p1.y - s->p0.y;
2027dd7cddfSDavid du Colombier 		s->dz = sdiv(s->num, s->den) << fixshift;
2037dd7cddfSDavid du Colombier 		s->dzrem = mod(s->num, s->den) << fixshift;
2047dd7cddfSDavid du Colombier 		s->dz += sdiv(s->dzrem, s->den);
2057dd7cddfSDavid du Colombier 		s->dzrem = mod(s->dzrem, s->den);
2067dd7cddfSDavid du Colombier 		p++;
2077dd7cddfSDavid du Colombier 	}
2087dd7cddfSDavid du Colombier 	n = p-seg;
2097dd7cddfSDavid du Colombier 	if(n == 0)
2107dd7cddfSDavid du Colombier 		return;
2117dd7cddfSDavid du Colombier 	*p = 0;
212*8ccd4a63SDavid du Colombier 	qsort(seg, p-seg , sizeof(Seg*), ycompare);
2137dd7cddfSDavid du Colombier 
2147dd7cddfSDavid du Colombier 	onehalf = 0;
2157dd7cddfSDavid du Colombier 	if(fixshift)
2167dd7cddfSDavid du Colombier 		onehalf = 1 << (fixshift-1);
2177dd7cddfSDavid du Colombier 
2187dd7cddfSDavid du Colombier 	minx = dst->clipr.min.x;
2197dd7cddfSDavid du Colombier 	maxx = dst->clipr.max.x;
2207dd7cddfSDavid du Colombier 
2217dd7cddfSDavid du Colombier 	y = seg[0]->p0.y;
2227dd7cddfSDavid du Colombier 	if(y < (dst->clipr.min.y << fixshift))
2237dd7cddfSDavid du Colombier 		y = dst->clipr.min.y << fixshift;
2247dd7cddfSDavid du Colombier 	iy = (y + onehalf) >> fixshift;
2257dd7cddfSDavid du Colombier 	y = (iy << fixshift) + onehalf;
2267dd7cddfSDavid du Colombier 	maxy = dst->clipr.max.y << fixshift;
2277dd7cddfSDavid du Colombier 
2287dd7cddfSDavid du Colombier 	ep = next = seg;
2297dd7cddfSDavid du Colombier 
2307dd7cddfSDavid du Colombier 	while(y<maxy) {
2317dd7cddfSDavid du Colombier 		for(q = p = seg; p < ep; p++) {
2327dd7cddfSDavid du Colombier 			s = *p;
2337dd7cddfSDavid du Colombier 			if(s->p1.y < y)
2347dd7cddfSDavid du Colombier 				continue;
2357dd7cddfSDavid du Colombier 			s->z += s->dz;
2367dd7cddfSDavid du Colombier 			s->zerr += s->dzrem;
2377dd7cddfSDavid du Colombier 			if(s->zerr >= s->den) {
2387dd7cddfSDavid du Colombier 				s->z++;
2397dd7cddfSDavid du Colombier 				s->zerr -= s->den;
2407dd7cddfSDavid du Colombier 				if(s->zerr < 0 || s->zerr >= s->den)
2417dd7cddfSDavid du Colombier 					print("bad ratzerr1: %ld den %ld dzrem %ld\n", s->zerr, s->den, s->dzrem);
2427dd7cddfSDavid du Colombier 			}
2437dd7cddfSDavid du Colombier 			*q++ = s;
2447dd7cddfSDavid du Colombier 		}
2457dd7cddfSDavid du Colombier 
2467dd7cddfSDavid du Colombier 		for(p = next; *p; p++) {
2477dd7cddfSDavid du Colombier 			s = *p;
2487dd7cddfSDavid du Colombier 			if(s->p0.y >= y)
2497dd7cddfSDavid du Colombier 				break;
2507dd7cddfSDavid du Colombier 			if(s->p1.y < y)
2517dd7cddfSDavid du Colombier 				continue;
2527dd7cddfSDavid du Colombier 			s->z = s->p0.x;
2537dd7cddfSDavid du Colombier 			s->z += smuldivmod(y - s->p0.y, s->num, s->den, &s->zerr);
2547dd7cddfSDavid du Colombier 			if(s->zerr < 0 || s->zerr >= s->den)
2557dd7cddfSDavid du Colombier 				print("bad ratzerr2: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem);
2567dd7cddfSDavid du Colombier 			*q++ = s;
2577dd7cddfSDavid du Colombier 		}
2587dd7cddfSDavid du Colombier 		ep = q;
2597dd7cddfSDavid du Colombier 		next = p;
2607dd7cddfSDavid du Colombier 
2617dd7cddfSDavid du Colombier 		if(ep == seg) {
2627dd7cddfSDavid du Colombier 			if(*next == 0)
2637dd7cddfSDavid du Colombier 				break;
2647dd7cddfSDavid du Colombier 			iy = (next[0]->p0.y + onehalf) >> fixshift;
2657dd7cddfSDavid du Colombier 			y = (iy << fixshift) + onehalf;
2667dd7cddfSDavid du Colombier 			continue;
2677dd7cddfSDavid du Colombier 		}
2687dd7cddfSDavid du Colombier 
2697dd7cddfSDavid du Colombier 		zsort(seg, ep);
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier 		for(p = seg; p < ep; p++) {
2727dd7cddfSDavid du Colombier 			cnt = 0;
2737dd7cddfSDavid du Colombier 			x = p[0]->z;
2747dd7cddfSDavid du Colombier 			xerr = p[0]->zerr;
2757dd7cddfSDavid du Colombier 			xden = p[0]->den;
2767dd7cddfSDavid du Colombier 			ix = (x + onehalf) >> fixshift;
2777dd7cddfSDavid du Colombier 			if(ix >= maxx)
2787dd7cddfSDavid du Colombier 				break;
2797dd7cddfSDavid du Colombier 			if(ix < minx)
2807dd7cddfSDavid du Colombier 				ix = minx;
2817dd7cddfSDavid du Colombier 			cnt += p[0]->d;
2827dd7cddfSDavid du Colombier 			p++;
2837dd7cddfSDavid du Colombier 			for(;;) {
2847dd7cddfSDavid du Colombier 				if(p == ep) {
2857dd7cddfSDavid du Colombier 					print("xscan: fill to infinity");
2867dd7cddfSDavid du Colombier 					return;
2877dd7cddfSDavid du Colombier 				}
2887dd7cddfSDavid du Colombier 				cnt += p[0]->d;
2897dd7cddfSDavid du Colombier 				if((cnt&wind) == 0)
2907dd7cddfSDavid du Colombier 					break;
2917dd7cddfSDavid du Colombier 				p++;
2927dd7cddfSDavid du Colombier 			}
2937dd7cddfSDavid du Colombier 			x2 = p[0]->z;
2947dd7cddfSDavid du Colombier 			ix2 = (x2 + onehalf) >> fixshift;
2957dd7cddfSDavid du Colombier 			if(ix2 <= minx)
2967dd7cddfSDavid du Colombier 				continue;
2977dd7cddfSDavid du Colombier 			if(ix2 > maxx)
2987dd7cddfSDavid du Colombier 				ix2 = maxx;
2997dd7cddfSDavid du Colombier 			if(ix == ix2 && detail) {
3007dd7cddfSDavid du Colombier 				if(xerr*p[0]->den + p[0]->zerr*xden > p[0]->den*xden)
3017dd7cddfSDavid du Colombier 					x++;
3027dd7cddfSDavid du Colombier 				ix = (x + x2) >> (fixshift+1);
3037dd7cddfSDavid du Colombier 				ix2 = ix+1;
3047dd7cddfSDavid du Colombier 			}
305*8ccd4a63SDavid du Colombier 			(*fill)(dst, ix, ix2, iy, src, sp, op);
3067dd7cddfSDavid du Colombier 		}
3077dd7cddfSDavid du Colombier 		y += (1<<fixshift);
3087dd7cddfSDavid du Colombier 		iy++;
3097dd7cddfSDavid du Colombier 	}
3107dd7cddfSDavid du Colombier }
3117dd7cddfSDavid du Colombier 
3127dd7cddfSDavid du Colombier static void
yscan(Memimage * dst,Seg ** seg,Seg * segtab,int nseg,int wind,Memimage * src,Point sp,int fixshift,int op)313*8ccd4a63SDavid du Colombier yscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int fixshift, int op)
3147dd7cddfSDavid du Colombier {
3157dd7cddfSDavid du Colombier 	long x, maxx, y, y2, yerr, yden, onehalf;
3167dd7cddfSDavid du Colombier 	Seg **ep, **next, **p, **q, *s;
3177dd7cddfSDavid du Colombier 	int n, i, ix, cnt, iy, iy2, miny, maxy;
3187dd7cddfSDavid du Colombier 	Point pt;
3197dd7cddfSDavid du Colombier 
3207dd7cddfSDavid du Colombier 	for(i=0, s=segtab, p=seg; i<nseg; i++, s++) {
3217dd7cddfSDavid du Colombier 		*p = s;
3227dd7cddfSDavid du Colombier 		if(s->p0.x == s->p1.x)
3237dd7cddfSDavid du Colombier 			continue;
3247dd7cddfSDavid du Colombier 		if(s->p0.x > s->p1.x) {
3257dd7cddfSDavid du Colombier 			pt = s->p0;
3267dd7cddfSDavid du Colombier 			s->p0 = s->p1;
3277dd7cddfSDavid du Colombier 			s->p1 = pt;
3287dd7cddfSDavid du Colombier 			s->d = -s->d;
3297dd7cddfSDavid du Colombier 		}
3307dd7cddfSDavid du Colombier 		s->num = s->p1.y - s->p0.y;
3317dd7cddfSDavid du Colombier 		s->den = s->p1.x - s->p0.x;
3327dd7cddfSDavid du Colombier 		s->dz = sdiv(s->num, s->den) << fixshift;
3337dd7cddfSDavid du Colombier 		s->dzrem = mod(s->num, s->den) << fixshift;
3347dd7cddfSDavid du Colombier 		s->dz += sdiv(s->dzrem, s->den);
3357dd7cddfSDavid du Colombier 		s->dzrem = mod(s->dzrem, s->den);
3367dd7cddfSDavid du Colombier 		p++;
3377dd7cddfSDavid du Colombier 	}
3387dd7cddfSDavid du Colombier 	n = p-seg;
3397dd7cddfSDavid du Colombier 	if(n == 0)
3407dd7cddfSDavid du Colombier 		return;
3417dd7cddfSDavid du Colombier 	*p = 0;
342*8ccd4a63SDavid du Colombier 	qsort(seg, n , sizeof(Seg*), xcompare);
3437dd7cddfSDavid du Colombier 
3447dd7cddfSDavid du Colombier 	onehalf = 0;
3457dd7cddfSDavid du Colombier 	if(fixshift)
3467dd7cddfSDavid du Colombier 		onehalf = 1 << (fixshift-1);
3477dd7cddfSDavid du Colombier 
3487dd7cddfSDavid du Colombier 	miny = dst->clipr.min.y;
3497dd7cddfSDavid du Colombier 	maxy = dst->clipr.max.y;
3507dd7cddfSDavid du Colombier 
3517dd7cddfSDavid du Colombier 	x = seg[0]->p0.x;
3527dd7cddfSDavid du Colombier 	if(x < (dst->clipr.min.x << fixshift))
3537dd7cddfSDavid du Colombier 		x = dst->clipr.min.x << fixshift;
3547dd7cddfSDavid du Colombier 	ix = (x + onehalf) >> fixshift;
3557dd7cddfSDavid du Colombier 	x = (ix << fixshift) + onehalf;
3567dd7cddfSDavid du Colombier 	maxx = dst->clipr.max.x << fixshift;
3577dd7cddfSDavid du Colombier 
3587dd7cddfSDavid du Colombier 	ep = next = seg;
3597dd7cddfSDavid du Colombier 
3607dd7cddfSDavid du Colombier 	while(x<maxx) {
3617dd7cddfSDavid du Colombier 		for(q = p = seg; p < ep; p++) {
3627dd7cddfSDavid du Colombier 			s = *p;
3637dd7cddfSDavid du Colombier 			if(s->p1.x < x)
3647dd7cddfSDavid du Colombier 				continue;
3657dd7cddfSDavid du Colombier 			s->z += s->dz;
3667dd7cddfSDavid du Colombier 			s->zerr += s->dzrem;
3677dd7cddfSDavid du Colombier 			if(s->zerr >= s->den) {
3687dd7cddfSDavid du Colombier 				s->z++;
3697dd7cddfSDavid du Colombier 				s->zerr -= s->den;
3707dd7cddfSDavid du Colombier 				if(s->zerr < 0 || s->zerr >= s->den)
3717dd7cddfSDavid du Colombier 					print("bad ratzerr1: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem);
3727dd7cddfSDavid du Colombier 			}
3737dd7cddfSDavid du Colombier 			*q++ = s;
3747dd7cddfSDavid du Colombier 		}
3757dd7cddfSDavid du Colombier 
3767dd7cddfSDavid du Colombier 		for(p = next; *p; p++) {
3777dd7cddfSDavid du Colombier 			s = *p;
3787dd7cddfSDavid du Colombier 			if(s->p0.x >= x)
3797dd7cddfSDavid du Colombier 				break;
3807dd7cddfSDavid du Colombier 			if(s->p1.x < x)
3817dd7cddfSDavid du Colombier 				continue;
3827dd7cddfSDavid du Colombier 			s->z = s->p0.y;
3837dd7cddfSDavid du Colombier 			s->z += smuldivmod(x - s->p0.x, s->num, s->den, &s->zerr);
3847dd7cddfSDavid du Colombier 			if(s->zerr < 0 || s->zerr >= s->den)
3857dd7cddfSDavid du Colombier 				print("bad ratzerr2: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem);
3867dd7cddfSDavid du Colombier 			*q++ = s;
3877dd7cddfSDavid du Colombier 		}
3887dd7cddfSDavid du Colombier 		ep = q;
3897dd7cddfSDavid du Colombier 		next = p;
3907dd7cddfSDavid du Colombier 
3917dd7cddfSDavid du Colombier 		if(ep == seg) {
3927dd7cddfSDavid du Colombier 			if(*next == 0)
3937dd7cddfSDavid du Colombier 				break;
3947dd7cddfSDavid du Colombier 			ix = (next[0]->p0.x + onehalf) >> fixshift;
3957dd7cddfSDavid du Colombier 			x = (ix << fixshift) + onehalf;
3967dd7cddfSDavid du Colombier 			continue;
3977dd7cddfSDavid du Colombier 		}
3987dd7cddfSDavid du Colombier 
3997dd7cddfSDavid du Colombier 		zsort(seg, ep);
4007dd7cddfSDavid du Colombier 
4017dd7cddfSDavid du Colombier 		for(p = seg; p < ep; p++) {
4027dd7cddfSDavid du Colombier 			cnt = 0;
4037dd7cddfSDavid du Colombier 			y = p[0]->z;
4047dd7cddfSDavid du Colombier 			yerr = p[0]->zerr;
4057dd7cddfSDavid du Colombier 			yden = p[0]->den;
4067dd7cddfSDavid du Colombier 			iy = (y + onehalf) >> fixshift;
4077dd7cddfSDavid du Colombier 			if(iy >= maxy)
4087dd7cddfSDavid du Colombier 				break;
4097dd7cddfSDavid du Colombier 			if(iy < miny)
4107dd7cddfSDavid du Colombier 				iy = miny;
4117dd7cddfSDavid du Colombier 			cnt += p[0]->d;
4127dd7cddfSDavid du Colombier 			p++;
4137dd7cddfSDavid du Colombier 			for(;;) {
4147dd7cddfSDavid du Colombier 				if(p == ep) {
4157dd7cddfSDavid du Colombier 					print("yscan: fill to infinity");
4167dd7cddfSDavid du Colombier 					return;
4177dd7cddfSDavid du Colombier 				}
4187dd7cddfSDavid du Colombier 				cnt += p[0]->d;
4197dd7cddfSDavid du Colombier 				if((cnt&wind) == 0)
4207dd7cddfSDavid du Colombier 					break;
4217dd7cddfSDavid du Colombier 				p++;
4227dd7cddfSDavid du Colombier 			}
4237dd7cddfSDavid du Colombier 			y2 = p[0]->z;
4247dd7cddfSDavid du Colombier 			iy2 = (y2 + onehalf) >> fixshift;
4257dd7cddfSDavid du Colombier 			if(iy2 <= miny)
4267dd7cddfSDavid du Colombier 				continue;
4277dd7cddfSDavid du Colombier 			if(iy2 > maxy)
4287dd7cddfSDavid du Colombier 				iy2 = maxy;
4297dd7cddfSDavid du Colombier 			if(iy == iy2) {
4307dd7cddfSDavid du Colombier 				if(yerr*p[0]->den + p[0]->zerr*yden > p[0]->den*yden)
4317dd7cddfSDavid du Colombier 					y++;
4327dd7cddfSDavid du Colombier 				iy = (y + y2) >> (fixshift+1);
433*8ccd4a63SDavid du Colombier 				fillpoint(dst, ix, iy, src, sp, op);
4347dd7cddfSDavid du Colombier 			}
4357dd7cddfSDavid du Colombier 		}
4367dd7cddfSDavid du Colombier 		x += (1<<fixshift);
4377dd7cddfSDavid du Colombier 		ix++;
4387dd7cddfSDavid du Colombier 	}
4397dd7cddfSDavid du Colombier }
4407dd7cddfSDavid du Colombier 
4417dd7cddfSDavid du Colombier static void
zsort(Seg ** seg,Seg ** ep)4427dd7cddfSDavid du Colombier zsort(Seg **seg, Seg **ep)
4437dd7cddfSDavid du Colombier {
4447dd7cddfSDavid du Colombier 	int done;
4457dd7cddfSDavid du Colombier 	Seg **q, **p, *s;
4467dd7cddfSDavid du Colombier 
4477dd7cddfSDavid du Colombier 	if(ep-seg < 20) {
4487dd7cddfSDavid du Colombier 		/* bubble sort by z - they should be almost sorted already */
4497dd7cddfSDavid du Colombier 		q = ep;
4507dd7cddfSDavid du Colombier 		do {
4517dd7cddfSDavid du Colombier 			done = 1;
4527dd7cddfSDavid du Colombier 			q--;
4537dd7cddfSDavid du Colombier 			for(p = seg; p < q; p++) {
4547dd7cddfSDavid du Colombier 				if(p[0]->z > p[1]->z) {
4557dd7cddfSDavid du Colombier 					s = p[0];
4567dd7cddfSDavid du Colombier 					p[0] = p[1];
4577dd7cddfSDavid du Colombier 					p[1] = s;
4587dd7cddfSDavid du Colombier 					done = 0;
4597dd7cddfSDavid du Colombier 				}
4607dd7cddfSDavid du Colombier 			}
4617dd7cddfSDavid du Colombier 		} while(!done);
4627dd7cddfSDavid du Colombier 	} else {
4637dd7cddfSDavid du Colombier 		q = ep-1;
4647dd7cddfSDavid du Colombier 		for(p = seg; p < q; p++) {
4657dd7cddfSDavid du Colombier 			if(p[0]->z > p[1]->z) {
466*8ccd4a63SDavid du Colombier 				qsort(seg, ep-seg, sizeof(Seg*), zcompare);
4677dd7cddfSDavid du Colombier 				break;
4687dd7cddfSDavid du Colombier 			}
4697dd7cddfSDavid du Colombier 		}
4707dd7cddfSDavid du Colombier 	}
4717dd7cddfSDavid du Colombier }
4727dd7cddfSDavid du Colombier 
4737dd7cddfSDavid du Colombier static int
ycompare(const void * a,const void * b)474*8ccd4a63SDavid du Colombier ycompare(const void *a, const void *b)
4757dd7cddfSDavid du Colombier {
4767dd7cddfSDavid du Colombier 	Seg **s0, **s1;
4777dd7cddfSDavid du Colombier 	long y0, y1;
4787dd7cddfSDavid du Colombier 
479*8ccd4a63SDavid du Colombier 	s0 = (Seg**)a;
480*8ccd4a63SDavid du Colombier 	s1 = (Seg**)b;
4817dd7cddfSDavid du Colombier 	y0 = (*s0)->p0.y;
4827dd7cddfSDavid du Colombier 	y1 = (*s1)->p0.y;
4837dd7cddfSDavid du Colombier 
4847dd7cddfSDavid du Colombier 	if(y0 < y1)
4857dd7cddfSDavid du Colombier 		return -1;
4867dd7cddfSDavid du Colombier 	if(y0 == y1)
4877dd7cddfSDavid du Colombier 		return 0;
4887dd7cddfSDavid du Colombier 	return 1;
4897dd7cddfSDavid du Colombier }
4907dd7cddfSDavid du Colombier 
4917dd7cddfSDavid du Colombier static int
xcompare(const void * a,const void * b)492*8ccd4a63SDavid du Colombier xcompare(const void *a, const void *b)
4937dd7cddfSDavid du Colombier {
4947dd7cddfSDavid du Colombier 	Seg **s0, **s1;
4957dd7cddfSDavid du Colombier 	long x0, x1;
4967dd7cddfSDavid du Colombier 
497*8ccd4a63SDavid du Colombier 	s0 = (Seg**)a;
498*8ccd4a63SDavid du Colombier 	s1 = (Seg**)b;
4997dd7cddfSDavid du Colombier 	x0 = (*s0)->p0.x;
5007dd7cddfSDavid du Colombier 	x1 = (*s1)->p0.x;
5017dd7cddfSDavid du Colombier 
5027dd7cddfSDavid du Colombier 	if(x0 < x1)
5037dd7cddfSDavid du Colombier 		return -1;
5047dd7cddfSDavid du Colombier 	if(x0 == x1)
5057dd7cddfSDavid du Colombier 		return 0;
5067dd7cddfSDavid du Colombier 	return 1;
5077dd7cddfSDavid du Colombier }
5087dd7cddfSDavid du Colombier 
5097dd7cddfSDavid du Colombier static int
zcompare(const void * a,const void * b)510*8ccd4a63SDavid du Colombier zcompare(const void *a, const void *b)
5117dd7cddfSDavid du Colombier {
5127dd7cddfSDavid du Colombier 	Seg **s0, **s1;
5137dd7cddfSDavid du Colombier 	long z0, z1;
5147dd7cddfSDavid du Colombier 
515*8ccd4a63SDavid du Colombier 	s0 = (Seg**)a;
516*8ccd4a63SDavid du Colombier 	s1 = (Seg**)b;
5177dd7cddfSDavid du Colombier 	z0 = (*s0)->z;
5187dd7cddfSDavid du Colombier 	z1 = (*s1)->z;
5197dd7cddfSDavid du Colombier 
5207dd7cddfSDavid du Colombier 	if(z0 < z1)
5217dd7cddfSDavid du Colombier 		return -1;
5227dd7cddfSDavid du Colombier 	if(z0 == z1)
5237dd7cddfSDavid du Colombier 		return 0;
5247dd7cddfSDavid du Colombier 	return 1;
5257dd7cddfSDavid du Colombier }
526