plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

fillpoly.c (9946B)


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