⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fillpoly.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include <u.h>#include <libc.h>#include <draw.h>#include <memdraw.h>#include <memlayer.h>typedef struct Seg	Seg;struct Seg{	Point	p0;	Point	p1;	long	num;	long	den;	long	dz;	long	dzrem;	long	z;	long	zerr;	long	d;};static	void	zsort(Seg **seg, Seg **ep);static	int	ycompare(void*, void*);static	int	xcompare(void*, void*);static	int	zcompare(void*, void*);static	void	xscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int, int, int, int);static	void	yscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int, int);static voidfillcolor(Memimage *dst, int left, int right, int y, Memimage *src, Point p){	int srcval;	USED(src);	srcval = p.x;	p.x = left;	p.y = y;	memset(byteaddr(dst, p), srcval, right-left);}static voidfillline(Memimage *dst, int left, int right, int y, Memimage *src, Point p, int op){	Rectangle r;	r.min.x = left;	r.min.y = y;	r.max.x = right;	r.max.y = y+1;	p.x += left;	p.y += y;	memdraw(dst, r, src, p, memopaque, p, op);}static voidfillpoint(Memimage *dst, int x, int y, Memimage *src, Point p, int op){	Rectangle r;	r.min.x = x;	r.min.y = y;	r.max.x = x+1;	r.max.y = y+1;	p.x += x;	p.y += y;	memdraw(dst, r, src, p, memopaque, p, op);}voidmemfillpoly(Memimage *dst, Point *vert, int nvert, int w, Memimage *src, Point sp, int op){	_memfillpolysc(dst, vert, nvert, w, src, sp, 0, 0, 0, op);}void_memfillpolysc(Memimage *dst, Point *vert, int nvert, int w, Memimage *src, Point sp, int detail, int fixshift, int clipped, int op){	Seg **seg, *segtab;	Point p0;	int i;	if(nvert == 0)		return;	seg = malloc((nvert+2)*sizeof(Seg*));	if(seg == nil)		return;	segtab = malloc((nvert+1)*sizeof(Seg));	if(segtab == nil) {		free(seg);		return;	}	sp.x = (sp.x - vert[0].x) >> fixshift;	sp.y = (sp.y - vert[0].y) >> fixshift;	p0 = vert[nvert-1];	if(!fixshift) {		p0.x <<= 1;		p0.y <<= 1;	}	for(i = 0; i < nvert; i++) {		segtab[i].p0 = p0;		p0 = vert[i];		if(!fixshift) {			p0.x <<= 1;			p0.y <<= 1;		}		segtab[i].p1 = p0;		segtab[i].d = 1;	}	if(!fixshift)		fixshift = 1;	xscan(dst, seg, segtab, nvert, w, src, sp, detail, fixshift, clipped, op);	if(detail)		yscan(dst, seg, segtab, nvert, w, src, sp, fixshift, op);	free(seg);	free(segtab);}static longmod(long x, long y){	long z;	z = x%y;	if((long)(((ulong)z)^((ulong)y)) > 0 || z == 0)		return z;	return z + y;}static longsdiv(long x, long y){	if((long)(((ulong)x)^((ulong)y)) >= 0 || x == 0)		return x/y;	return (x+((y>>30)|1))/y-1;}static longsmuldivmod(long x, long y, long z, long *mod){	vlong vx;	if(x == 0 || y == 0){		*mod = 0;		return 0;	}	vx = x;	vx *= y;	*mod = vx % z;	if(*mod < 0)		*mod += z;	/* z is always >0 */	if((vx < 0) == (z < 0))		return vx/z;	return -((-vx)/z);}static voidxscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int detail, int fixshift, int clipped, int op){	long y, maxy, x, x2, xerr, xden, onehalf;	Seg **ep, **next, **p, **q, *s;	long n, i, iy, cnt, ix, ix2, minx, maxx;	Point pt;	void	(*fill)(Memimage*, int, int, int, Memimage*, Point, int);	fill = fillline;/* * This can only work on 8-bit destinations, since fillcolor is * just using memset on sp.x. * * I'd rather not even enable it then, since then if the general * code is too slow, someone will come up with a better improvement * than this sleazy hack.	-rsc *	if(clipped && (src->flags&Frepl) && src->depth==8 && Dx(src->r)==1 && Dy(src->r)==1) {		fill = fillcolor;		sp.x = membyteval(src);	} * */	USED(clipped);	for(i=0, s=segtab, p=seg; i<nseg; i++, s++) {		*p = s;		if(s->p0.y == s->p1.y)			continue;		if(s->p0.y > s->p1.y) {			pt = s->p0;			s->p0 = s->p1;			s->p1 = pt;			s->d = -s->d;		}		s->num = s->p1.x - s->p0.x;		s->den = s->p1.y - s->p0.y;		s->dz = sdiv(s->num, s->den) << fixshift;		s->dzrem = mod(s->num, s->den) << fixshift;		s->dz += sdiv(s->dzrem, s->den);		s->dzrem = mod(s->dzrem, s->den);		p++;	}	n = p-seg;	if(n == 0)		return;	*p = 0;	qsort(seg, p-seg , sizeof(Seg*), ycompare);	onehalf = 0;	if(fixshift)		onehalf = 1 << (fixshift-1);	minx = dst->clipr.min.x;	maxx = dst->clipr.max.x;	y = seg[0]->p0.y;	if(y < (dst->clipr.min.y << fixshift))		y = dst->clipr.min.y << fixshift;	iy = (y + onehalf) >> fixshift;	y = (iy << fixshift) + onehalf;	maxy = dst->clipr.max.y << fixshift;	ep = next = seg;	while(y<maxy) {		for(q = p = seg; p < ep; p++) {			s = *p;			if(s->p1.y < y)				continue;			s->z += s->dz;			s->zerr += s->dzrem;			if(s->zerr >= s->den) {				s->z++;				s->zerr -= s->den;				if(s->zerr < 0 || s->zerr >= s->den)					print("bad ratzerr1: %ld den %ld dzrem %ld\n", s->zerr, s->den, s->dzrem);			}			*q++ = s;		}		for(p = next; *p; p++) {			s = *p;			if(s->p0.y >= y)				break;			if(s->p1.y < y)				continue;			s->z = s->p0.x;			s->z += smuldivmod(y - s->p0.y, s->num, s->den, &s->zerr);			if(s->zerr < 0 || s->zerr >= s->den)				print("bad ratzerr2: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem);			*q++ = s;		}		ep = q;		next = p;		if(ep == seg) {			if(*next == 0)				break;			iy = (next[0]->p0.y + onehalf) >> fixshift;			y = (iy << fixshift) + onehalf;			continue;		}		zsort(seg, ep);		for(p = seg; p < ep; p++) {			cnt = 0;			x = p[0]->z;			xerr = p[0]->zerr;			xden = p[0]->den;			ix = (x + onehalf) >> fixshift;			if(ix >= maxx)				break;			if(ix < minx)				ix = minx;			cnt += p[0]->d;			p++;			for(;;) {				if(p == ep) {					print("xscan: fill to infinity");					return;				}				cnt += p[0]->d;				if((cnt&wind) == 0)					break;				p++;			}			x2 = p[0]->z;			ix2 = (x2 + onehalf) >> fixshift;			if(ix2 <= minx)				continue;			if(ix2 > maxx)				ix2 = maxx;			if(ix == ix2 && detail) {				if(xerr*p[0]->den + p[0]->zerr*xden > p[0]->den*xden)					x++;				ix = (x + x2) >> (fixshift+1);				ix2 = ix+1;			}			(*fill)(dst, ix, ix2, iy, src, sp, op);		}		y += (1<<fixshift);		iy++;	}}static voidyscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int fixshift, int op){	long x, maxx, y, y2, yerr, yden, onehalf;	Seg **ep, **next, **p, **q, *s;	int n, i, ix, cnt, iy, iy2, miny, maxy;	Point pt;	for(i=0, s=segtab, p=seg; i<nseg; i++, s++) {		*p = s;		if(s->p0.x == s->p1.x)			continue;		if(s->p0.x > s->p1.x) {			pt = s->p0;			s->p0 = s->p1;			s->p1 = pt;			s->d = -s->d;		}		s->num = s->p1.y - s->p0.y;		s->den = s->p1.x - s->p0.x;		s->dz = sdiv(s->num, s->den) << fixshift;		s->dzrem = mod(s->num, s->den) << fixshift;		s->dz += sdiv(s->dzrem, s->den);		s->dzrem = mod(s->dzrem, s->den);		p++;	}	n = p-seg;	if(n == 0)		return;	*p = 0;	qsort(seg, n , sizeof(Seg*), xcompare);	onehalf = 0;	if(fixshift)		onehalf = 1 << (fixshift-1);	miny = dst->clipr.min.y;	maxy = dst->clipr.max.y;	x = seg[0]->p0.x;	if(x < (dst->clipr.min.x << fixshift))		x = dst->clipr.min.x << fixshift;	ix = (x + onehalf) >> fixshift;	x = (ix << fixshift) + onehalf;	maxx = dst->clipr.max.x << fixshift;	ep = next = seg;	while(x<maxx) {		for(q = p = seg; p < ep; p++) {			s = *p;			if(s->p1.x < x)				continue;			s->z += s->dz;			s->zerr += s->dzrem;			if(s->zerr >= s->den) {				s->z++;				s->zerr -= s->den;				if(s->zerr < 0 || s->zerr >= s->den)					print("bad ratzerr1: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem);			}			*q++ = s;		}		for(p = next; *p; p++) {			s = *p;			if(s->p0.x >= x)				break;			if(s->p1.x < x)				continue;			s->z = s->p0.y;			s->z += smuldivmod(x - s->p0.x, s->num, s->den, &s->zerr);			if(s->zerr < 0 || s->zerr >= s->den)				print("bad ratzerr2: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem);			*q++ = s;		}		ep = q;		next = p;		if(ep == seg) {			if(*next == 0)				break;			ix = (next[0]->p0.x + onehalf) >> fixshift;			x = (ix << fixshift) + onehalf;			continue;		}		zsort(seg, ep);		for(p = seg; p < ep; p++) {			cnt = 0;			y = p[0]->z;			yerr = p[0]->zerr;			yden = p[0]->den;			iy = (y + onehalf) >> fixshift;			if(iy >= maxy)				break;			if(iy < miny)				iy = miny;			cnt += p[0]->d;			p++;			for(;;) {				if(p == ep) {					print("yscan: fill to infinity");					return;				}				cnt += p[0]->d;				if((cnt&wind) == 0)					break;				p++;			}			y2 = p[0]->z;			iy2 = (y2 + onehalf) >> fixshift;			if(iy2 <= miny)				continue;			if(iy2 > maxy)				iy2 = maxy;			if(iy == iy2) {				if(yerr*p[0]->den + p[0]->zerr*yden > p[0]->den*yden)					y++;				iy = (y + y2) >> (fixshift+1);				fillpoint(dst, ix, iy, src, sp, op);			}		}		x += (1<<fixshift);		ix++;	}}static voidzsort(Seg **seg, Seg **ep){	int done;	Seg **q, **p, *s;	if(ep-seg < 20) {		/* bubble sort by z - they should be almost sorted already */		q = ep;		do {			done = 1;			q--;			for(p = seg; p < q; p++) {				if(p[0]->z > p[1]->z) {					s = p[0];					p[0] = p[1];					p[1] = s;					done = 0;				}			}		} while(!done);	} else {		q = ep-1;		for(p = seg; p < q; p++) {			if(p[0]->z > p[1]->z) {				qsort(seg, ep-seg, sizeof(Seg*), zcompare);				break;			}		}	}}static intycompare(void *a, void *b){	Seg **s0, **s1;	long y0, y1;	s0 = a;	s1 = b;	y0 = (*s0)->p0.y;	y1 = (*s1)->p0.y;	if(y0 < y1)		return -1;	if(y0 == y1)		return 0;	return 1;}static intxcompare(void *a, void *b){	Seg **s0, **s1;	long x0, x1;	s0 = a;	s1 = b;	x0 = (*s0)->p0.x;	x1 = (*s1)->p0.x;	if(x0 < x1)		return -1;	if(x0 == x1)		return 0;	return 1;}static intzcompare(void *a, void *b){	Seg **s0, **s1;	long z0, z1;	s0 = a;	s1 = b;	z0 = (*s0)->z;	z1 = (*s1)->z;	if(z0 < z1)		return -1;	if(z0 == z1)		return 0;	return 1;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -