Charles.Forsyth20060303a828770d19 years agoHistory
440 lines · 7.4 KB · Brainfuck
RawDownload
implement Polyfill; include "sys.m";	sys: Sys;include "draw.m";	draw: Draw;	Point, Rect, Image, Endsquare: import draw;include "math/polyfill.m"; ∞: con 16r7fffffff; init(){	sys = load Sys Sys->PATH;	draw = load Draw Draw->PATH;} initzbuf(r: Rect): ref Zstate{	if(sys == nil)		init();	s := ref Zstate;	s.r = r;	s.xlen = r.dx();	s.ylen = r.dy();	s.xylen = s.xlen*s.ylen;	s.zbuf0 = array[s.xylen] of int;	s.zbuf1 = array[s.xylen] of int;	return s;} clearzbuf(s: ref Zstate){	b0 := s.zbuf0;	b1 := s.zbuf1;	n := s.xylen;	for(i := 0; i < n; i++)		b0[i] = b1[i] = ∞;} setzbuf(s: ref Zstate, zd: int){	b0 := s.zbuf0;	b1 := s.zbuf1;	n := s.xylen;	for(i := 0; i < n; i++)		b0[i] = b1[i] = zd;} Seg: adt{	p0: Point;	p1: Point;	num: int;	den: int;	dz: int;	dzrem: int;	z: int;	zerr: int;	d: int;}; fillline(dst: ref Image, left: int, right: int, y: int, src: ref Image, p: Point){	p.x += left;	p.y += y;	dst.line((left, y), (right, y), Endsquare, Endsquare, 0, src, p);} filllinez(dst: ref Image, left: int, right: int, y: int, z: int, e: int, dx: int, k: int, zbuf0: array of int, zbuf1: array of int, src: ref Image, p: Point){	prevx := ∞;	for(x := left; x <= right; x++){		if(z+e < zbuf0[k] || (z-e <= zbuf1[k] && x != right && prevx != ∞)){			zbuf0[k] = z-e;			zbuf1[k] = z+e;			if(prevx == ∞)				prevx = x;		}		else if(prevx != ∞){			fillline(dst, prevx, x-1, y, src, p);			prevx = ∞;		}		z += dx;		k++;	}	if(prevx != ∞)		fillline(dst, prevx, right, y, src, p);} fillpoly(dst: ref Image, vert: array of Point, w: int, src: ref Image, sp: Point, zstate: ref Zstate, dc: int, dx: int, dy: int){	p0: Point;	i: int; 	nvert := len vert;	if(nvert == 0)		return;	fixshift := 0;	seg := array[nvert+2] of ref Seg;	if(seg == nil)		return;	segtab := array[nvert+1] of ref Seg;	if(segtab == nil)		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] = ref Seg;		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, zstate, dc, dx, dy, fixshift);} mod(x: int, y: int): int{	z: int; 	z = x%y;	if((z^y) > 0 || z == 0)		return z;	return z + y;} sdiv(x: int, y: int): int{	if((x^y) >= 0 || x == 0)		return x/y;	return (x+((y>>30)|1))/y-1;} smuldivmod(x: int, y: int, z: int): (int, int){	mod: int;	vx: int; 	if(x == 0 || y == 0)		return (0, 0);	vx = x;	vx *= y;	mod = vx % z;	if(mod < 0)		mod += z;	if((vx < 0) == (z < 0))		return (vx/z, mod);	return (-((-vx)/z), mod);} xscan(dst: ref Image, seg: array of ref Seg, segtab: array of ref Seg, nseg: int, wind: int, src: ref Image, spt: Point, zstate: ref Zstate, dc: int, dx: int, dy: int, fixshift: int){	y, maxy, x, x2, onehalf: int;	ep, next, p, q, s: int;	n, i, iy, cnt, ix, ix2, minx, maxx, zinc, k, zv: int;	pt: Point;	sp: ref Seg; 	er := (abs(dx)+abs(dy)+1)/2;	zr := zstate.r;	xlen := zstate.xlen;	zbuf0 := zstate.zbuf0;	zbuf1 := zstate.zbuf1;	s = 0;	p = 0;	for(i=0; i<nseg; i++) {		sp = seg[p] = segtab[s];		if(sp.p0.y == sp.p1.y){			s++;			continue;		}		if(sp.p0.y > sp.p1.y) {			pt = sp.p0;			sp.p0 = sp.p1;			sp.p1 = pt;			sp.d = -sp.d;		}		sp.num = sp.p1.x - sp.p0.x;		sp.den = sp.p1.y - sp.p0.y;		sp.dz = sdiv(sp.num, sp.den) << fixshift;		sp.dzrem = mod(sp.num, sp.den) << fixshift;		sp.dz += sdiv(sp.dzrem, sp.den);		sp.dzrem = mod(sp.dzrem, sp.den);		p++;		s++;	}	n = p;	if(n == 0)		return;	seg[p] = nil;	qsortycompare(seg, p); 	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;	k = (iy-zr.min.y)*xlen;	zv = dc+iy*dy; 	ep = next = 0; 	while(y<maxy) {		for(q = p = 0; p < ep; p++) {			sp = seg[p];			if(sp.p1.y < y)				continue;			sp.z += sp.dz;			sp.zerr += sp.dzrem;			if(sp.zerr >= sp.den) {				sp.z++;				sp.zerr -= sp.den;				if(sp.zerr < 0 || sp.zerr >= sp.den)					sys->print("bad ratzerr1: %d den %d dzrem %d\n", sp.zerr, sp.den, sp.dzrem);			}			seg[q] = sp;			q++;		} 		for(p = next; seg[p] != nil; p++) {			sp = seg[p];			if(sp.p0.y >= y)				break;			if(sp.p1.y < y)				continue;			sp.z = sp.p0.x;			(zinc, sp.zerr) = smuldivmod(y - sp.p0.y, sp.num, sp.den);			sp.z += zinc;			if(sp.zerr < 0 || sp.zerr >= sp.den)				sys->print("bad ratzerr2: %d den %d ratdzrem %d\n", sp.zerr, sp.den, sp.dzrem);			seg[q] = sp;			q++;		}		ep = q;		next = p; 		if(ep == 0) {			if(seg[next] == nil)				break;			iy = (seg[next].p0.y + onehalf) >> fixshift;			y = (iy << fixshift) + onehalf;			k = (iy-zr.min.y)*xlen;			zv = dc+iy*dy;			continue;		} 		zsort(seg, ep); 		for(p = 0; p < ep; p++) {			sp = seg[p];			cnt = 0;			x = sp.z;			ix = (x + onehalf) >> fixshift;			if(ix >= maxx)				break;			if(ix < minx)				ix = minx;			cnt += sp.d;			p++;			sp = seg[p];			for(;;) {				if(p == ep) {					sys->print("xscan: fill to infinity");					return;				}				cnt += sp.d;				if((cnt&wind) == 0)					break;				p++;				sp = seg[p];			}			x2 = sp.z;			ix2 = (x2 + onehalf) >> fixshift;			if(ix2 <= minx)				continue;			if(ix2 > maxx)				ix2 = maxx;			filllinez(dst, ix, ix2, iy, zv+ix*dx, er, dx, k+ix-zr.min.x, zbuf0, zbuf1, src, spt);		}		y += (1<<fixshift);		iy++;		k += xlen;		zv += dy;	}} zsort(seg: array of ref Seg, ep: int){	done: int;	s: ref Seg;	q, p: int; 	if(ep < 20) {		# bubble sort by z - they should be almost sorted already		q = ep;		do {			done = 1;			q--;			for(p = 0; p < q; p++) {				if(seg[p].z > seg[p+1].z) {					s = seg[p];					seg[p] = seg[p+1];					seg[p+1] = s;					done = 0;				}			}		} while(!done);	} else {		q = ep-1;		for(p = 0; p < q; p++) {			if(seg[p].z > seg[p+1].z) {				qsortzcompare(seg, ep);				break;			}		}	}} ycompare(s0: ref Seg, s1: ref Seg): int{	y0, y1: int; 	y0 = s0.p0.y;	y1 = s1.p0.y; 	if(y0 < y1)		return -1;	if(y0 == y1)		return 0;	return 1;} zcompare(s0: ref Seg, s1: ref Seg): int{	z0, z1: int; 	z0 = s0.z;	z1 = s1.z; 	if(z0 < z1)		return -1;	if(z0 == z1)		return 0;	return 1;} qsortycompare(a : array of ref Seg, n : int){	i, j : int;	t : ref Seg; 	while(n > 1) {		i = n>>1;		t = a[0]; a[0] = a[i]; a[i] = t;		i = 0;		j = n;		for(;;) {			do				i++;			while(i < n && ycompare(a[i], a[0]) < 0);			do				j--;			while(j > 0 && ycompare(a[j], a[0]) > 0);			if(j < i)				break;			t = a[i]; a[i] = a[j]; a[j] = t;		}		t = a[0]; a[0] = a[j]; a[j] = t;		n = n-j-1;		if(j >= n) {			qsortycompare(a, j);			a = a[j+1:];		} else {			qsortycompare(a[j+1:], n);			n = j;		}	}} qsortzcompare(a : array of ref Seg, n : int){	i, j : int;	t : ref Seg; 	while(n > 1) {		i = n>>1;		t = a[0]; a[0] = a[i]; a[i] = t;		i = 0;		j = n;		for(;;) {			do				i++;			while(i < n && zcompare(a[i], a[0]) < 0);			do				j--;			while(j > 0 && zcompare(a[j], a[0]) > 0);			if(j < i)				break;			t = a[i]; a[i] = a[j]; a[j] = t;		}		t = a[0]; a[0] = a[j]; a[j] = t;		n = n-j-1;		if(j >= n) {			qsortzcompare(a, j);			a = a[j+1:];		} else {			qsortzcompare(a[j+1:], n);			n = j;		}	}} abs(n: int): int{	if(n < 0)		return -n;	return n;}