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