xref: /plan9/sys/src/cmd/unix/drawterm/libmemdraw/fillpoly.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1*7dd7cddfSDavid du Colombier #include "../lib9.h"
2*7dd7cddfSDavid du Colombier 
3*7dd7cddfSDavid du Colombier #include "../libdraw/draw.h"
4*7dd7cddfSDavid du Colombier #include "../libmemdraw/memdraw.h"
5*7dd7cddfSDavid du Colombier #include "../libmemlayer/memlayer.h"
6*7dd7cddfSDavid du Colombier 
7*7dd7cddfSDavid du Colombier typedef struct Seg	Seg;
8*7dd7cddfSDavid du Colombier 
9*7dd7cddfSDavid du Colombier struct Seg
10*7dd7cddfSDavid du Colombier {
11*7dd7cddfSDavid du Colombier 	Point	p0;
12*7dd7cddfSDavid du Colombier 	Point	p1;
13*7dd7cddfSDavid du Colombier 	long	num;
14*7dd7cddfSDavid du Colombier 	long	den;
15*7dd7cddfSDavid du Colombier 	long	dz;
16*7dd7cddfSDavid du Colombier 	long	dzrem;
17*7dd7cddfSDavid du Colombier 	long	z;
18*7dd7cddfSDavid du Colombier 	long	zerr;
19*7dd7cddfSDavid du Colombier 	long	d;
20*7dd7cddfSDavid du Colombier };
21*7dd7cddfSDavid du Colombier 
22*7dd7cddfSDavid du Colombier static	void	zsort(Seg **seg, Seg **ep);
23*7dd7cddfSDavid du Colombier static	int	ycompare(void*, void*);
24*7dd7cddfSDavid du Colombier static	int	xcompare(void*, void*);
25*7dd7cddfSDavid du Colombier static	int	zcompare(void*, void*);
26*7dd7cddfSDavid du Colombier static	void	xscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int, int, int);
27*7dd7cddfSDavid du Colombier static	void	yscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int);
28*7dd7cddfSDavid du Colombier 
29*7dd7cddfSDavid du Colombier /*
30*7dd7cddfSDavid du Colombier static void
31*7dd7cddfSDavid du Colombier fillcolor(Memimage *dst, int left, int right, int y, Memimage *src, Point p)
32*7dd7cddfSDavid du Colombier {
33*7dd7cddfSDavid du Colombier 	int srcval;
34*7dd7cddfSDavid du Colombier 
35*7dd7cddfSDavid du Colombier 	USED(src);
36*7dd7cddfSDavid du Colombier 	srcval = p.x;
37*7dd7cddfSDavid du Colombier 	p.x = left;
38*7dd7cddfSDavid du Colombier 	p.y = y;
39*7dd7cddfSDavid du Colombier 	memset(byteaddr(dst, p), srcval, right-left);
40*7dd7cddfSDavid du Colombier }
41*7dd7cddfSDavid du Colombier */
42*7dd7cddfSDavid du Colombier 
43*7dd7cddfSDavid du Colombier static void
44*7dd7cddfSDavid du Colombier fillline(Memimage *dst, int left, int right, int y, Memimage *src, Point p)
45*7dd7cddfSDavid du Colombier {
46*7dd7cddfSDavid du Colombier 	Rectangle r;
47*7dd7cddfSDavid du Colombier 
48*7dd7cddfSDavid du Colombier 	r.min.x = left;
49*7dd7cddfSDavid du Colombier 	r.min.y = y;
50*7dd7cddfSDavid du Colombier 	r.max.x = right;
51*7dd7cddfSDavid du Colombier 	r.max.y = y+1;
52*7dd7cddfSDavid du Colombier 	p.x += left;
53*7dd7cddfSDavid du Colombier 	p.y += y;
54*7dd7cddfSDavid du Colombier 	memdraw(dst, r, src, p, memopaque, p);
55*7dd7cddfSDavid du Colombier }
56*7dd7cddfSDavid du Colombier 
57*7dd7cddfSDavid du Colombier static void
58*7dd7cddfSDavid du Colombier fillpoint(Memimage *dst, int x, int y, Memimage *src, Point p)
59*7dd7cddfSDavid du Colombier {
60*7dd7cddfSDavid du Colombier 	Rectangle r;
61*7dd7cddfSDavid du Colombier 
62*7dd7cddfSDavid du Colombier 	r.min.x = x;
63*7dd7cddfSDavid du Colombier 	r.min.y = y;
64*7dd7cddfSDavid du Colombier 	r.max.x = x+1;
65*7dd7cddfSDavid du Colombier 	r.max.y = y+1;
66*7dd7cddfSDavid du Colombier 	p.x += x;
67*7dd7cddfSDavid du Colombier 	p.y += y;
68*7dd7cddfSDavid du Colombier 	memdraw(dst, r, src, p, memopaque, p);
69*7dd7cddfSDavid du Colombier }
70*7dd7cddfSDavid du Colombier 
71*7dd7cddfSDavid du Colombier void
72*7dd7cddfSDavid du Colombier memfillpoly(Memimage *dst, Point *vert, int nvert, int w, Memimage *src, Point sp)
73*7dd7cddfSDavid du Colombier {
74*7dd7cddfSDavid du Colombier 	memfillpolysc(dst, vert, nvert, w, src, sp, 0, 0, 0);
75*7dd7cddfSDavid du Colombier }
76*7dd7cddfSDavid du Colombier 
77*7dd7cddfSDavid du Colombier void
78*7dd7cddfSDavid du Colombier memfillpolysc(Memimage *dst, Point *vert, int nvert, int w, Memimage *src, Point sp, int detail, int fixshift, int clipped)
79*7dd7cddfSDavid du Colombier {
80*7dd7cddfSDavid du Colombier 	Seg **seg, *segtab;
81*7dd7cddfSDavid du Colombier 	Point p0;
82*7dd7cddfSDavid du Colombier 	int i;
83*7dd7cddfSDavid du Colombier 
84*7dd7cddfSDavid du Colombier 	if(nvert == 0)
85*7dd7cddfSDavid du Colombier 		return;
86*7dd7cddfSDavid du Colombier 
87*7dd7cddfSDavid du Colombier 	seg = malloc((nvert+2)*sizeof(Seg*));
88*7dd7cddfSDavid du Colombier 	if(seg == nil)
89*7dd7cddfSDavid du Colombier 		return;
90*7dd7cddfSDavid du Colombier 	segtab = malloc((nvert+1)*sizeof(Seg));
91*7dd7cddfSDavid du Colombier 	if(segtab == nil) {
92*7dd7cddfSDavid du Colombier 		free(seg);
93*7dd7cddfSDavid du Colombier 		return;
94*7dd7cddfSDavid du Colombier 	}
95*7dd7cddfSDavid du Colombier 
96*7dd7cddfSDavid du Colombier 	sp.x = (sp.x - vert[0].x) >> fixshift;
97*7dd7cddfSDavid du Colombier 	sp.y = (sp.y - vert[0].y) >> fixshift;
98*7dd7cddfSDavid du Colombier 	p0 = vert[nvert-1];
99*7dd7cddfSDavid du Colombier 	if(!fixshift) {
100*7dd7cddfSDavid du Colombier 		p0.x <<= 1;
101*7dd7cddfSDavid du Colombier 		p0.y <<= 1;
102*7dd7cddfSDavid du Colombier 	}
103*7dd7cddfSDavid du Colombier 	for(i = 0; i < nvert; i++) {
104*7dd7cddfSDavid du Colombier 		segtab[i].p0 = p0;
105*7dd7cddfSDavid du Colombier 		p0 = vert[i];
106*7dd7cddfSDavid du Colombier 		if(!fixshift) {
107*7dd7cddfSDavid du Colombier 			p0.x <<= 1;
108*7dd7cddfSDavid du Colombier 			p0.y <<= 1;
109*7dd7cddfSDavid du Colombier 		}
110*7dd7cddfSDavid du Colombier 		segtab[i].p1 = p0;
111*7dd7cddfSDavid du Colombier 		segtab[i].d = 1;
112*7dd7cddfSDavid du Colombier 	}
113*7dd7cddfSDavid du Colombier 	if(!fixshift)
114*7dd7cddfSDavid du Colombier 		fixshift = 1;
115*7dd7cddfSDavid du Colombier 
116*7dd7cddfSDavid du Colombier 	xscan(dst, seg, segtab, nvert, w, src, sp, detail, fixshift, clipped);
117*7dd7cddfSDavid du Colombier 	if(detail)
118*7dd7cddfSDavid du Colombier 		yscan(dst, seg, segtab, nvert, w, src, sp, fixshift);
119*7dd7cddfSDavid du Colombier 
120*7dd7cddfSDavid du Colombier 	free(seg);
121*7dd7cddfSDavid du Colombier 	free(segtab);
122*7dd7cddfSDavid du Colombier }
123*7dd7cddfSDavid du Colombier 
124*7dd7cddfSDavid du Colombier static long
125*7dd7cddfSDavid du Colombier mod(long x, long y)
126*7dd7cddfSDavid du Colombier {
127*7dd7cddfSDavid du Colombier 	long z;
128*7dd7cddfSDavid du Colombier 
129*7dd7cddfSDavid du Colombier 	z = x%y;
130*7dd7cddfSDavid du Colombier 	if((long)(((ulong)z)^((ulong)y)) > 0 || z == 0)
131*7dd7cddfSDavid du Colombier 		return z;
132*7dd7cddfSDavid du Colombier 	return z + y;
133*7dd7cddfSDavid du Colombier }
134*7dd7cddfSDavid du Colombier 
135*7dd7cddfSDavid du Colombier static long
136*7dd7cddfSDavid du Colombier sdiv(long x, long y)
137*7dd7cddfSDavid du Colombier {
138*7dd7cddfSDavid du Colombier 	if((long)(((ulong)x)^((ulong)y)) >= 0 || x == 0)
139*7dd7cddfSDavid du Colombier 		return x/y;
140*7dd7cddfSDavid du Colombier 
141*7dd7cddfSDavid du Colombier 	return (x+((y>>30)|1))/y-1;
142*7dd7cddfSDavid du Colombier }
143*7dd7cddfSDavid du Colombier 
144*7dd7cddfSDavid du Colombier static long
145*7dd7cddfSDavid du Colombier smuldivmod(long x, long y, long z, long *mod)
146*7dd7cddfSDavid du Colombier {
147*7dd7cddfSDavid du Colombier 	vlong vx;
148*7dd7cddfSDavid du Colombier 
149*7dd7cddfSDavid du Colombier 	if(x == 0 || y == 0){
150*7dd7cddfSDavid du Colombier 		*mod = 0;
151*7dd7cddfSDavid du Colombier 		return 0;
152*7dd7cddfSDavid du Colombier 	}
153*7dd7cddfSDavid du Colombier 	vx = x;
154*7dd7cddfSDavid du Colombier 	vx *= y;
155*7dd7cddfSDavid du Colombier 	*mod = vx % z;
156*7dd7cddfSDavid du Colombier 	if(*mod < 0)
157*7dd7cddfSDavid du Colombier 		*mod += z;	/* z is always >0 */
158*7dd7cddfSDavid du Colombier 	if((vx < 0) == (z < 0))
159*7dd7cddfSDavid du Colombier 		return vx/z;
160*7dd7cddfSDavid du Colombier 	return -((-vx)/z);
161*7dd7cddfSDavid du Colombier }
162*7dd7cddfSDavid du Colombier 
163*7dd7cddfSDavid du Colombier static void
164*7dd7cddfSDavid du Colombier xscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int detail, int fixshift, int clipped)
165*7dd7cddfSDavid du Colombier {
166*7dd7cddfSDavid du Colombier 	long y, maxy, x, x2, xerr, xden, onehalf;
167*7dd7cddfSDavid du Colombier 	Seg **ep, **next, **p, **q, *s;
168*7dd7cddfSDavid du Colombier 	long n, i, iy, cnt, ix, ix2, minx, maxx;
169*7dd7cddfSDavid du Colombier 	Point pt;
170*7dd7cddfSDavid du Colombier 	void	(*fill)(Memimage*, int, int, int, Memimage*, Point);
171*7dd7cddfSDavid du Colombier 
172*7dd7cddfSDavid du Colombier 	fill = fillline;
173*7dd7cddfSDavid du Colombier /*
174*7dd7cddfSDavid du Colombier  * This can only work on 8-bit destinations, since fillcolor is
175*7dd7cddfSDavid du Colombier  * just using memset on sp.x.
176*7dd7cddfSDavid du Colombier  *
177*7dd7cddfSDavid du Colombier  * I'd rather not even enable it then, since then if the general
178*7dd7cddfSDavid du Colombier  * code is too slow, someone will come up with a better improvement
179*7dd7cddfSDavid du Colombier  * than this sleazy hack.	-rsc
180*7dd7cddfSDavid du Colombier  *
181*7dd7cddfSDavid du Colombier 	if(clipped && (src->flags&Frepl) && src->depth==8 && Dx(src->r)==1 && Dy(src->r)==1) {
182*7dd7cddfSDavid du Colombier 		fill = fillcolor;
183*7dd7cddfSDavid du Colombier 		sp.x = membyteval(src);
184*7dd7cddfSDavid du Colombier 	}
185*7dd7cddfSDavid du Colombier  *
186*7dd7cddfSDavid du Colombier  */
187*7dd7cddfSDavid du Colombier 	USED(clipped);
188*7dd7cddfSDavid du Colombier 
189*7dd7cddfSDavid du Colombier 
190*7dd7cddfSDavid du Colombier 	for(i=0, s=segtab, p=seg; i<nseg; i++, s++) {
191*7dd7cddfSDavid du Colombier 		*p = s;
192*7dd7cddfSDavid du Colombier 		if(s->p0.y == s->p1.y)
193*7dd7cddfSDavid du Colombier 			continue;
194*7dd7cddfSDavid du Colombier 		if(s->p0.y > s->p1.y) {
195*7dd7cddfSDavid du Colombier 			pt = s->p0;
196*7dd7cddfSDavid du Colombier 			s->p0 = s->p1;
197*7dd7cddfSDavid du Colombier 			s->p1 = pt;
198*7dd7cddfSDavid du Colombier 			s->d = -s->d;
199*7dd7cddfSDavid du Colombier 		}
200*7dd7cddfSDavid du Colombier 		s->num = s->p1.x - s->p0.x;
201*7dd7cddfSDavid du Colombier 		s->den = s->p1.y - s->p0.y;
202*7dd7cddfSDavid du Colombier 		s->dz = sdiv(s->num, s->den) << fixshift;
203*7dd7cddfSDavid du Colombier 		s->dzrem = mod(s->num, s->den) << fixshift;
204*7dd7cddfSDavid du Colombier 		s->dz += sdiv(s->dzrem, s->den);
205*7dd7cddfSDavid du Colombier 		s->dzrem = mod(s->dzrem, s->den);
206*7dd7cddfSDavid du Colombier 		p++;
207*7dd7cddfSDavid du Colombier 	}
208*7dd7cddfSDavid du Colombier 	n = p-seg;
209*7dd7cddfSDavid du Colombier 	if(n == 0)
210*7dd7cddfSDavid du Colombier 		return;
211*7dd7cddfSDavid du Colombier 	*p = 0;
212*7dd7cddfSDavid du Colombier 	qsort(seg, p-seg , sizeof(Seg*),
213*7dd7cddfSDavid du Colombier 		(int(*)(const void*, const void*))ycompare);
214*7dd7cddfSDavid du Colombier 
215*7dd7cddfSDavid du Colombier 	onehalf = 0;
216*7dd7cddfSDavid du Colombier 	if(fixshift)
217*7dd7cddfSDavid du Colombier 		onehalf = 1 << (fixshift-1);
218*7dd7cddfSDavid du Colombier 
219*7dd7cddfSDavid du Colombier 	minx = dst->clipr.min.x;
220*7dd7cddfSDavid du Colombier 	maxx = dst->clipr.max.x;
221*7dd7cddfSDavid du Colombier 
222*7dd7cddfSDavid du Colombier 	y = seg[0]->p0.y;
223*7dd7cddfSDavid du Colombier 	if(y < (dst->clipr.min.y << fixshift))
224*7dd7cddfSDavid du Colombier 		y = dst->clipr.min.y << fixshift;
225*7dd7cddfSDavid du Colombier 	iy = (y + onehalf) >> fixshift;
226*7dd7cddfSDavid du Colombier 	y = (iy << fixshift) + onehalf;
227*7dd7cddfSDavid du Colombier 	maxy = dst->clipr.max.y << fixshift;
228*7dd7cddfSDavid du Colombier 
229*7dd7cddfSDavid du Colombier 	ep = next = seg;
230*7dd7cddfSDavid du Colombier 
231*7dd7cddfSDavid du Colombier 	while(y<maxy) {
232*7dd7cddfSDavid du Colombier 		for(q = p = seg; p < ep; p++) {
233*7dd7cddfSDavid du Colombier 			s = *p;
234*7dd7cddfSDavid du Colombier 			if(s->p1.y < y)
235*7dd7cddfSDavid du Colombier 				continue;
236*7dd7cddfSDavid du Colombier 			s->z += s->dz;
237*7dd7cddfSDavid du Colombier 			s->zerr += s->dzrem;
238*7dd7cddfSDavid du Colombier 			if(s->zerr >= s->den) {
239*7dd7cddfSDavid du Colombier 				s->z++;
240*7dd7cddfSDavid du Colombier 				s->zerr -= s->den;
241*7dd7cddfSDavid du Colombier 				if(s->zerr < 0 || s->zerr >= s->den)
242*7dd7cddfSDavid du Colombier 					print("bad ratzerr1: %ld den %ld dzrem %ld\n", s->zerr, s->den, s->dzrem);
243*7dd7cddfSDavid du Colombier 			}
244*7dd7cddfSDavid du Colombier 			*q++ = s;
245*7dd7cddfSDavid du Colombier 		}
246*7dd7cddfSDavid du Colombier 
247*7dd7cddfSDavid du Colombier 		for(p = next; *p; p++) {
248*7dd7cddfSDavid du Colombier 			s = *p;
249*7dd7cddfSDavid du Colombier 			if(s->p0.y >= y)
250*7dd7cddfSDavid du Colombier 				break;
251*7dd7cddfSDavid du Colombier 			if(s->p1.y < y)
252*7dd7cddfSDavid du Colombier 				continue;
253*7dd7cddfSDavid du Colombier 			s->z = s->p0.x;
254*7dd7cddfSDavid du Colombier 			s->z += smuldivmod(y - s->p0.y, s->num, s->den, &s->zerr);
255*7dd7cddfSDavid du Colombier 			if(s->zerr < 0 || s->zerr >= s->den)
256*7dd7cddfSDavid du Colombier 				print("bad ratzerr2: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem);
257*7dd7cddfSDavid du Colombier 			*q++ = s;
258*7dd7cddfSDavid du Colombier 		}
259*7dd7cddfSDavid du Colombier 		ep = q;
260*7dd7cddfSDavid du Colombier 		next = p;
261*7dd7cddfSDavid du Colombier 
262*7dd7cddfSDavid du Colombier 		if(ep == seg) {
263*7dd7cddfSDavid du Colombier 			if(*next == 0)
264*7dd7cddfSDavid du Colombier 				break;
265*7dd7cddfSDavid du Colombier 			iy = (next[0]->p0.y + onehalf) >> fixshift;
266*7dd7cddfSDavid du Colombier 			y = (iy << fixshift) + onehalf;
267*7dd7cddfSDavid du Colombier 			continue;
268*7dd7cddfSDavid du Colombier 		}
269*7dd7cddfSDavid du Colombier 
270*7dd7cddfSDavid du Colombier 		zsort(seg, ep);
271*7dd7cddfSDavid du Colombier 
272*7dd7cddfSDavid du Colombier 		for(p = seg; p < ep; p++) {
273*7dd7cddfSDavid du Colombier 			cnt = 0;
274*7dd7cddfSDavid du Colombier 			x = p[0]->z;
275*7dd7cddfSDavid du Colombier 			xerr = p[0]->zerr;
276*7dd7cddfSDavid du Colombier 			xden = p[0]->den;
277*7dd7cddfSDavid du Colombier 			ix = (x + onehalf) >> fixshift;
278*7dd7cddfSDavid du Colombier 			if(ix >= maxx)
279*7dd7cddfSDavid du Colombier 				break;
280*7dd7cddfSDavid du Colombier 			if(ix < minx)
281*7dd7cddfSDavid du Colombier 				ix = minx;
282*7dd7cddfSDavid du Colombier 			cnt += p[0]->d;
283*7dd7cddfSDavid du Colombier 			p++;
284*7dd7cddfSDavid du Colombier 			for(;;) {
285*7dd7cddfSDavid du Colombier 				if(p == ep) {
286*7dd7cddfSDavid du Colombier 					print("xscan: fill to infinity");
287*7dd7cddfSDavid du Colombier 					return;
288*7dd7cddfSDavid du Colombier 				}
289*7dd7cddfSDavid du Colombier 				cnt += p[0]->d;
290*7dd7cddfSDavid du Colombier 				if((cnt&wind) == 0)
291*7dd7cddfSDavid du Colombier 					break;
292*7dd7cddfSDavid du Colombier 				p++;
293*7dd7cddfSDavid du Colombier 			}
294*7dd7cddfSDavid du Colombier 			x2 = p[0]->z;
295*7dd7cddfSDavid du Colombier 			ix2 = (x2 + onehalf) >> fixshift;
296*7dd7cddfSDavid du Colombier 			if(ix2 <= minx)
297*7dd7cddfSDavid du Colombier 				continue;
298*7dd7cddfSDavid du Colombier 			if(ix2 > maxx)
299*7dd7cddfSDavid du Colombier 				ix2 = maxx;
300*7dd7cddfSDavid du Colombier 			if(ix == ix2 && detail) {
301*7dd7cddfSDavid du Colombier 				if(xerr*p[0]->den + p[0]->zerr*xden > p[0]->den*xden)
302*7dd7cddfSDavid du Colombier 					x++;
303*7dd7cddfSDavid du Colombier 				ix = (x + x2) >> (fixshift+1);
304*7dd7cddfSDavid du Colombier 				ix2 = ix+1;
305*7dd7cddfSDavid du Colombier 			}
306*7dd7cddfSDavid du Colombier 			(*fill)(dst, ix, ix2, iy, src, sp);
307*7dd7cddfSDavid du Colombier 		}
308*7dd7cddfSDavid du Colombier 		y += (1<<fixshift);
309*7dd7cddfSDavid du Colombier 		iy++;
310*7dd7cddfSDavid du Colombier 	}
311*7dd7cddfSDavid du Colombier }
312*7dd7cddfSDavid du Colombier 
313*7dd7cddfSDavid du Colombier static void
314*7dd7cddfSDavid du Colombier yscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int fixshift)
315*7dd7cddfSDavid du Colombier {
316*7dd7cddfSDavid du Colombier 	long x, maxx, y, y2, yerr, yden, onehalf;
317*7dd7cddfSDavid du Colombier 	Seg **ep, **next, **p, **q, *s;
318*7dd7cddfSDavid du Colombier 	int n, i, ix, cnt, iy, iy2, miny, maxy;
319*7dd7cddfSDavid du Colombier 	Point pt;
320*7dd7cddfSDavid du Colombier 
321*7dd7cddfSDavid du Colombier 	for(i=0, s=segtab, p=seg; i<nseg; i++, s++) {
322*7dd7cddfSDavid du Colombier 		*p = s;
323*7dd7cddfSDavid du Colombier 		if(s->p0.x == s->p1.x)
324*7dd7cddfSDavid du Colombier 			continue;
325*7dd7cddfSDavid du Colombier 		if(s->p0.x > s->p1.x) {
326*7dd7cddfSDavid du Colombier 			pt = s->p0;
327*7dd7cddfSDavid du Colombier 			s->p0 = s->p1;
328*7dd7cddfSDavid du Colombier 			s->p1 = pt;
329*7dd7cddfSDavid du Colombier 			s->d = -s->d;
330*7dd7cddfSDavid du Colombier 		}
331*7dd7cddfSDavid du Colombier 		s->num = s->p1.y - s->p0.y;
332*7dd7cddfSDavid du Colombier 		s->den = s->p1.x - s->p0.x;
333*7dd7cddfSDavid du Colombier 		s->dz = sdiv(s->num, s->den) << fixshift;
334*7dd7cddfSDavid du Colombier 		s->dzrem = mod(s->num, s->den) << fixshift;
335*7dd7cddfSDavid du Colombier 		s->dz += sdiv(s->dzrem, s->den);
336*7dd7cddfSDavid du Colombier 		s->dzrem = mod(s->dzrem, s->den);
337*7dd7cddfSDavid du Colombier 		p++;
338*7dd7cddfSDavid du Colombier 	}
339*7dd7cddfSDavid du Colombier 	n = p-seg;
340*7dd7cddfSDavid du Colombier 	if(n == 0)
341*7dd7cddfSDavid du Colombier 		return;
342*7dd7cddfSDavid du Colombier 	*p = 0;
343*7dd7cddfSDavid du Colombier 	qsort(seg, n , sizeof(Seg*),
344*7dd7cddfSDavid du Colombier 		(int(*)(const void*, const void*))xcompare);
345*7dd7cddfSDavid du Colombier 
346*7dd7cddfSDavid du Colombier 	onehalf = 0;
347*7dd7cddfSDavid du Colombier 	if(fixshift)
348*7dd7cddfSDavid du Colombier 		onehalf = 1 << (fixshift-1);
349*7dd7cddfSDavid du Colombier 
350*7dd7cddfSDavid du Colombier 	miny = dst->clipr.min.y;
351*7dd7cddfSDavid du Colombier 	maxy = dst->clipr.max.y;
352*7dd7cddfSDavid du Colombier 
353*7dd7cddfSDavid du Colombier 	x = seg[0]->p0.x;
354*7dd7cddfSDavid du Colombier 	if(x < (dst->clipr.min.x << fixshift))
355*7dd7cddfSDavid du Colombier 		x = dst->clipr.min.x << fixshift;
356*7dd7cddfSDavid du Colombier 	ix = (x + onehalf) >> fixshift;
357*7dd7cddfSDavid du Colombier 	x = (ix << fixshift) + onehalf;
358*7dd7cddfSDavid du Colombier 	maxx = dst->clipr.max.x << fixshift;
359*7dd7cddfSDavid du Colombier 
360*7dd7cddfSDavid du Colombier 	ep = next = seg;
361*7dd7cddfSDavid du Colombier 
362*7dd7cddfSDavid du Colombier 	while(x<maxx) {
363*7dd7cddfSDavid du Colombier 		for(q = p = seg; p < ep; p++) {
364*7dd7cddfSDavid du Colombier 			s = *p;
365*7dd7cddfSDavid du Colombier 			if(s->p1.x < x)
366*7dd7cddfSDavid du Colombier 				continue;
367*7dd7cddfSDavid du Colombier 			s->z += s->dz;
368*7dd7cddfSDavid du Colombier 			s->zerr += s->dzrem;
369*7dd7cddfSDavid du Colombier 			if(s->zerr >= s->den) {
370*7dd7cddfSDavid du Colombier 				s->z++;
371*7dd7cddfSDavid du Colombier 				s->zerr -= s->den;
372*7dd7cddfSDavid du Colombier 				if(s->zerr < 0 || s->zerr >= s->den)
373*7dd7cddfSDavid du Colombier 					print("bad ratzerr1: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem);
374*7dd7cddfSDavid du Colombier 			}
375*7dd7cddfSDavid du Colombier 			*q++ = s;
376*7dd7cddfSDavid du Colombier 		}
377*7dd7cddfSDavid du Colombier 
378*7dd7cddfSDavid du Colombier 		for(p = next; *p; p++) {
379*7dd7cddfSDavid du Colombier 			s = *p;
380*7dd7cddfSDavid du Colombier 			if(s->p0.x >= x)
381*7dd7cddfSDavid du Colombier 				break;
382*7dd7cddfSDavid du Colombier 			if(s->p1.x < x)
383*7dd7cddfSDavid du Colombier 				continue;
384*7dd7cddfSDavid du Colombier 			s->z = s->p0.y;
385*7dd7cddfSDavid du Colombier 			s->z += smuldivmod(x - s->p0.x, s->num, s->den, &s->zerr);
386*7dd7cddfSDavid du Colombier 			if(s->zerr < 0 || s->zerr >= s->den)
387*7dd7cddfSDavid du Colombier 				print("bad ratzerr2: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem);
388*7dd7cddfSDavid du Colombier 			*q++ = s;
389*7dd7cddfSDavid du Colombier 		}
390*7dd7cddfSDavid du Colombier 		ep = q;
391*7dd7cddfSDavid du Colombier 		next = p;
392*7dd7cddfSDavid du Colombier 
393*7dd7cddfSDavid du Colombier 		if(ep == seg) {
394*7dd7cddfSDavid du Colombier 			if(*next == 0)
395*7dd7cddfSDavid du Colombier 				break;
396*7dd7cddfSDavid du Colombier 			ix = (next[0]->p0.x + onehalf) >> fixshift;
397*7dd7cddfSDavid du Colombier 			x = (ix << fixshift) + onehalf;
398*7dd7cddfSDavid du Colombier 			continue;
399*7dd7cddfSDavid du Colombier 		}
400*7dd7cddfSDavid du Colombier 
401*7dd7cddfSDavid du Colombier 		zsort(seg, ep);
402*7dd7cddfSDavid du Colombier 
403*7dd7cddfSDavid du Colombier 		for(p = seg; p < ep; p++) {
404*7dd7cddfSDavid du Colombier 			cnt = 0;
405*7dd7cddfSDavid du Colombier 			y = p[0]->z;
406*7dd7cddfSDavid du Colombier 			yerr = p[0]->zerr;
407*7dd7cddfSDavid du Colombier 			yden = p[0]->den;
408*7dd7cddfSDavid du Colombier 			iy = (y + onehalf) >> fixshift;
409*7dd7cddfSDavid du Colombier 			if(iy >= maxy)
410*7dd7cddfSDavid du Colombier 				break;
411*7dd7cddfSDavid du Colombier 			if(iy < miny)
412*7dd7cddfSDavid du Colombier 				iy = miny;
413*7dd7cddfSDavid du Colombier 			cnt += p[0]->d;
414*7dd7cddfSDavid du Colombier 			p++;
415*7dd7cddfSDavid du Colombier 			for(;;) {
416*7dd7cddfSDavid du Colombier 				if(p == ep) {
417*7dd7cddfSDavid du Colombier 					print("yscan: fill to infinity");
418*7dd7cddfSDavid du Colombier 					return;
419*7dd7cddfSDavid du Colombier 				}
420*7dd7cddfSDavid du Colombier 				cnt += p[0]->d;
421*7dd7cddfSDavid du Colombier 				if((cnt&wind) == 0)
422*7dd7cddfSDavid du Colombier 					break;
423*7dd7cddfSDavid du Colombier 				p++;
424*7dd7cddfSDavid du Colombier 			}
425*7dd7cddfSDavid du Colombier 			y2 = p[0]->z;
426*7dd7cddfSDavid du Colombier 			iy2 = (y2 + onehalf) >> fixshift;
427*7dd7cddfSDavid du Colombier 			if(iy2 <= miny)
428*7dd7cddfSDavid du Colombier 				continue;
429*7dd7cddfSDavid du Colombier 			if(iy2 > maxy)
430*7dd7cddfSDavid du Colombier 				iy2 = maxy;
431*7dd7cddfSDavid du Colombier 			if(iy == iy2) {
432*7dd7cddfSDavid du Colombier 				if(yerr*p[0]->den + p[0]->zerr*yden > p[0]->den*yden)
433*7dd7cddfSDavid du Colombier 					y++;
434*7dd7cddfSDavid du Colombier 				iy = (y + y2) >> (fixshift+1);
435*7dd7cddfSDavid du Colombier 				fillpoint(dst, ix, iy, src, sp);
436*7dd7cddfSDavid du Colombier 			}
437*7dd7cddfSDavid du Colombier 		}
438*7dd7cddfSDavid du Colombier 		x += (1<<fixshift);
439*7dd7cddfSDavid du Colombier 		ix++;
440*7dd7cddfSDavid du Colombier 	}
441*7dd7cddfSDavid du Colombier }
442*7dd7cddfSDavid du Colombier 
443*7dd7cddfSDavid du Colombier static void
444*7dd7cddfSDavid du Colombier zsort(Seg **seg, Seg **ep)
445*7dd7cddfSDavid du Colombier {
446*7dd7cddfSDavid du Colombier 	int done;
447*7dd7cddfSDavid du Colombier 	Seg **q, **p, *s;
448*7dd7cddfSDavid du Colombier 
449*7dd7cddfSDavid du Colombier 	if(ep-seg < 20) {
450*7dd7cddfSDavid du Colombier 		/* bubble sort by z - they should be almost sorted already */
451*7dd7cddfSDavid du Colombier 		q = ep;
452*7dd7cddfSDavid du Colombier 		do {
453*7dd7cddfSDavid du Colombier 			done = 1;
454*7dd7cddfSDavid du Colombier 			q--;
455*7dd7cddfSDavid du Colombier 			for(p = seg; p < q; p++) {
456*7dd7cddfSDavid du Colombier 				if(p[0]->z > p[1]->z) {
457*7dd7cddfSDavid du Colombier 					s = p[0];
458*7dd7cddfSDavid du Colombier 					p[0] = p[1];
459*7dd7cddfSDavid du Colombier 					p[1] = s;
460*7dd7cddfSDavid du Colombier 					done = 0;
461*7dd7cddfSDavid du Colombier 				}
462*7dd7cddfSDavid du Colombier 			}
463*7dd7cddfSDavid du Colombier 		} while(!done);
464*7dd7cddfSDavid du Colombier 	} else {
465*7dd7cddfSDavid du Colombier 		q = ep-1;
466*7dd7cddfSDavid du Colombier 		for(p = seg; p < q; p++) {
467*7dd7cddfSDavid du Colombier 			if(p[0]->z > p[1]->z) {
468*7dd7cddfSDavid du Colombier 				qsort(seg, ep-seg, sizeof(Seg*),
469*7dd7cddfSDavid du Colombier 					(int(*)(const void*, const void*))zcompare);
470*7dd7cddfSDavid du Colombier 				break;
471*7dd7cddfSDavid du Colombier 			}
472*7dd7cddfSDavid du Colombier 		}
473*7dd7cddfSDavid du Colombier 	}
474*7dd7cddfSDavid du Colombier }
475*7dd7cddfSDavid du Colombier 
476*7dd7cddfSDavid du Colombier static int
477*7dd7cddfSDavid du Colombier ycompare(void *a, void *b)
478*7dd7cddfSDavid du Colombier {
479*7dd7cddfSDavid du Colombier 	Seg **s0, **s1;
480*7dd7cddfSDavid du Colombier 	long y0, y1;
481*7dd7cddfSDavid du Colombier 
482*7dd7cddfSDavid du Colombier 	s0 = a;
483*7dd7cddfSDavid du Colombier 	s1 = b;
484*7dd7cddfSDavid du Colombier 	y0 = (*s0)->p0.y;
485*7dd7cddfSDavid du Colombier 	y1 = (*s1)->p0.y;
486*7dd7cddfSDavid du Colombier 
487*7dd7cddfSDavid du Colombier 	if(y0 < y1)
488*7dd7cddfSDavid du Colombier 		return -1;
489*7dd7cddfSDavid du Colombier 	if(y0 == y1)
490*7dd7cddfSDavid du Colombier 		return 0;
491*7dd7cddfSDavid du Colombier 	return 1;
492*7dd7cddfSDavid du Colombier }
493*7dd7cddfSDavid du Colombier 
494*7dd7cddfSDavid du Colombier static int
495*7dd7cddfSDavid du Colombier xcompare(void *a, void *b)
496*7dd7cddfSDavid du Colombier {
497*7dd7cddfSDavid du Colombier 	Seg **s0, **s1;
498*7dd7cddfSDavid du Colombier 	long x0, x1;
499*7dd7cddfSDavid du Colombier 
500*7dd7cddfSDavid du Colombier 	s0 = a;
501*7dd7cddfSDavid du Colombier 	s1 = b;
502*7dd7cddfSDavid du Colombier 	x0 = (*s0)->p0.x;
503*7dd7cddfSDavid du Colombier 	x1 = (*s1)->p0.x;
504*7dd7cddfSDavid du Colombier 
505*7dd7cddfSDavid du Colombier 	if(x0 < x1)
506*7dd7cddfSDavid du Colombier 		return -1;
507*7dd7cddfSDavid du Colombier 	if(x0 == x1)
508*7dd7cddfSDavid du Colombier 		return 0;
509*7dd7cddfSDavid du Colombier 	return 1;
510*7dd7cddfSDavid du Colombier }
511*7dd7cddfSDavid du Colombier 
512*7dd7cddfSDavid du Colombier static int
513*7dd7cddfSDavid du Colombier zcompare(void *a, void *b)
514*7dd7cddfSDavid du Colombier {
515*7dd7cddfSDavid du Colombier 	Seg **s0, **s1;
516*7dd7cddfSDavid du Colombier 	long z0, z1;
517*7dd7cddfSDavid du Colombier 
518*7dd7cddfSDavid du Colombier 	s0 = a;
519*7dd7cddfSDavid du Colombier 	s1 = b;
520*7dd7cddfSDavid du Colombier 	z0 = (*s0)->z;
521*7dd7cddfSDavid du Colombier 	z1 = (*s1)->z;
522*7dd7cddfSDavid du Colombier 
523*7dd7cddfSDavid du Colombier 	if(z0 < z1)
524*7dd7cddfSDavid du Colombier 		return -1;
525*7dd7cddfSDavid du Colombier 	if(z0 == z1)
526*7dd7cddfSDavid du Colombier 		return 0;
527*7dd7cddfSDavid du Colombier 	return 1;
528*7dd7cddfSDavid du Colombier }
529