xref: /plan9/sys/src/libmemdraw/line.c (revision e5b1f7dde43c88534ab5bb52aa101ce2f496062a)
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 enum
87dd7cddfSDavid du Colombier {
97dd7cddfSDavid du Colombier 	Arrow1 = 8,
107dd7cddfSDavid du Colombier 	Arrow2 = 10,
117dd7cddfSDavid du Colombier 	Arrow3 = 3,
127dd7cddfSDavid du Colombier };
137dd7cddfSDavid du Colombier 
147dd7cddfSDavid du Colombier static
157dd7cddfSDavid du Colombier int
lmin(int a,int b)167dd7cddfSDavid du Colombier lmin(int a, int b)
177dd7cddfSDavid du Colombier {
187dd7cddfSDavid du Colombier 	if(a < b)
197dd7cddfSDavid du Colombier 		return a;
207dd7cddfSDavid du Colombier 	return b;
217dd7cddfSDavid du Colombier }
227dd7cddfSDavid du Colombier 
237dd7cddfSDavid du Colombier static
247dd7cddfSDavid du Colombier int
lmax(int a,int b)257dd7cddfSDavid du Colombier lmax(int a, int b)
267dd7cddfSDavid du Colombier {
277dd7cddfSDavid du Colombier 	if(a > b)
287dd7cddfSDavid du Colombier 		return a;
297dd7cddfSDavid du Colombier 	return b;
307dd7cddfSDavid du Colombier }
317dd7cddfSDavid du Colombier 
326a9fc400SDavid du Colombier #ifdef NOTUSED
337dd7cddfSDavid du Colombier /*
347dd7cddfSDavid du Colombier  * Rather than line clip, we run the Bresenham loop over the full line,
357dd7cddfSDavid du Colombier  * and clip on each pixel.  This is more expensive but means that
367dd7cddfSDavid du Colombier  * lines look the same regardless of how the windowing has tiled them.
377dd7cddfSDavid du Colombier  * For speed, we check for clipping outside the loop and make the
387dd7cddfSDavid du Colombier  * test easy when possible.
397dd7cddfSDavid du Colombier  */
407dd7cddfSDavid du Colombier 
417dd7cddfSDavid du Colombier static
427dd7cddfSDavid du Colombier void
horline1(Memimage * dst,Point p0,Point p1,int srcval,Rectangle clipr)437dd7cddfSDavid du Colombier horline1(Memimage *dst, Point p0, Point p1, int srcval, Rectangle clipr)
447dd7cddfSDavid du Colombier {
457dd7cddfSDavid du Colombier 	int x, y, dy, deltay, deltax, maxx;
467dd7cddfSDavid du Colombier 	int dd, easy, e, bpp, m, m0;
477dd7cddfSDavid du Colombier 	uchar *d;
487dd7cddfSDavid du Colombier 
497dd7cddfSDavid du Colombier 	deltax = p1.x - p0.x;
507dd7cddfSDavid du Colombier 	deltay = p1.y - p0.y;
517dd7cddfSDavid du Colombier 	dd = dst->width*sizeof(ulong);
527dd7cddfSDavid du Colombier 	dy = 1;
537dd7cddfSDavid du Colombier 	if(deltay < 0){
547dd7cddfSDavid du Colombier 		dd = -dd;
557dd7cddfSDavid du Colombier 		deltay = -deltay;
567dd7cddfSDavid du Colombier 		dy = -1;
577dd7cddfSDavid du Colombier 	}
587dd7cddfSDavid du Colombier 	maxx = lmin(p1.x, clipr.max.x-1);
597dd7cddfSDavid du Colombier 	bpp = dst->depth;
607dd7cddfSDavid du Colombier 	m0 = 0xFF^(0xFF>>bpp);
617dd7cddfSDavid du Colombier 	m = m0 >> (p0.x&(7/dst->depth))*bpp;
627dd7cddfSDavid du Colombier 	easy = ptinrect(p0, clipr) && ptinrect(p1, clipr);
637dd7cddfSDavid du Colombier 	e = 2*deltay - deltax;
647dd7cddfSDavid du Colombier 	y = p0.y;
657dd7cddfSDavid du Colombier 	d = byteaddr(dst, p0);
667dd7cddfSDavid du Colombier 	deltay *= 2;
677dd7cddfSDavid du Colombier 	deltax = deltay - 2*deltax;
687dd7cddfSDavid du Colombier 	for(x=p0.x; x<=maxx; x++){
697dd7cddfSDavid du Colombier 		if(easy || (clipr.min.x<=x && clipr.min.y<=y && y<clipr.max.y))
707dd7cddfSDavid du Colombier 			*d ^= (*d^srcval) & m;
717dd7cddfSDavid du Colombier 		if(e > 0){
727dd7cddfSDavid du Colombier 			y += dy;
737dd7cddfSDavid du Colombier 			d += dd;
747dd7cddfSDavid du Colombier 			e += deltax;
757dd7cddfSDavid du Colombier 		}else
767dd7cddfSDavid du Colombier 			e += deltay;
777dd7cddfSDavid du Colombier 		d++;
787dd7cddfSDavid du Colombier 		m >>= bpp;
797dd7cddfSDavid du Colombier 		if(m == 0)
807dd7cddfSDavid du Colombier 			m = m0;
817dd7cddfSDavid du Colombier 	}
827dd7cddfSDavid du Colombier }
837dd7cddfSDavid du Colombier 
847dd7cddfSDavid du Colombier static
857dd7cddfSDavid du Colombier void
verline1(Memimage * dst,Point p0,Point p1,int srcval,Rectangle clipr)867dd7cddfSDavid du Colombier verline1(Memimage *dst, Point p0, Point p1, int srcval, Rectangle clipr)
877dd7cddfSDavid du Colombier {
887dd7cddfSDavid du Colombier 	int x, y, deltay, deltax, maxy;
897dd7cddfSDavid du Colombier 	int easy, e, bpp, m, m0, dd;
907dd7cddfSDavid du Colombier 	uchar *d;
917dd7cddfSDavid du Colombier 
927dd7cddfSDavid du Colombier 	deltax = p1.x - p0.x;
937dd7cddfSDavid du Colombier 	deltay = p1.y - p0.y;
947dd7cddfSDavid du Colombier 	dd = 1;
957dd7cddfSDavid du Colombier 	if(deltax < 0){
967dd7cddfSDavid du Colombier 		dd = -1;
977dd7cddfSDavid du Colombier 		deltax = -deltax;
987dd7cddfSDavid du Colombier 	}
997dd7cddfSDavid du Colombier 	maxy = lmin(p1.y, clipr.max.y-1);
1007dd7cddfSDavid du Colombier 	bpp = dst->depth;
1017dd7cddfSDavid du Colombier 	m0 = 0xFF^(0xFF>>bpp);
1027dd7cddfSDavid du Colombier 	m = m0 >> (p0.x&(7/dst->depth))*bpp;
1037dd7cddfSDavid du Colombier 	easy = ptinrect(p0, clipr) && ptinrect(p1, clipr);
1047dd7cddfSDavid du Colombier 	e = 2*deltax - deltay;
1057dd7cddfSDavid du Colombier 	x = p0.x;
1067dd7cddfSDavid du Colombier 	d = byteaddr(dst, p0);
1077dd7cddfSDavid du Colombier 	deltax *= 2;
1087dd7cddfSDavid du Colombier 	deltay = deltax - 2*deltay;
1097dd7cddfSDavid du Colombier 	for(y=p0.y; y<=maxy; y++){
1107dd7cddfSDavid du Colombier 		if(easy || (clipr.min.y<=y && clipr.min.x<=x && x<clipr.max.x))
1117dd7cddfSDavid du Colombier 			*d ^= (*d^srcval) & m;
1127dd7cddfSDavid du Colombier 		if(e > 0){
1137dd7cddfSDavid du Colombier 			x += dd;
1147dd7cddfSDavid du Colombier 			d += dd;
1157dd7cddfSDavid du Colombier 			e += deltay;
1167dd7cddfSDavid du Colombier 		}else
1177dd7cddfSDavid du Colombier 			e += deltax;
1187dd7cddfSDavid du Colombier 		d += dst->width*sizeof(ulong);
1197dd7cddfSDavid du Colombier 		m >>= bpp;
1207dd7cddfSDavid du Colombier 		if(m == 0)
1217dd7cddfSDavid du Colombier 			m = m0;
1227dd7cddfSDavid du Colombier 	}
1237dd7cddfSDavid du Colombier }
1247dd7cddfSDavid du Colombier 
1257dd7cddfSDavid du Colombier static
1267dd7cddfSDavid du Colombier void
horliner(Memimage * dst,Point p0,Point p1,Memimage * src,Point dsrc,Rectangle clipr)1277dd7cddfSDavid du Colombier horliner(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
1287dd7cddfSDavid du Colombier {
1297dd7cddfSDavid du Colombier 	int x, y, sx, sy, deltay, deltax, minx, maxx;
1307dd7cddfSDavid du Colombier 	int bpp, m, m0;
1317dd7cddfSDavid du Colombier 	uchar *d, *s;
1327dd7cddfSDavid du Colombier 
1337dd7cddfSDavid du Colombier 	deltax = p1.x - p0.x;
1347dd7cddfSDavid du Colombier 	deltay = p1.y - p0.y;
1357dd7cddfSDavid du Colombier 	sx = drawreplxy(src->r.min.x, src->r.max.x, p0.x+dsrc.x);
1367dd7cddfSDavid du Colombier 	minx = lmax(p0.x, clipr.min.x);
1377dd7cddfSDavid du Colombier 	maxx = lmin(p1.x, clipr.max.x-1);
1387dd7cddfSDavid du Colombier 	bpp = dst->depth;
1397dd7cddfSDavid du Colombier 	m0 = 0xFF^(0xFF>>bpp);
1407dd7cddfSDavid du Colombier 	m = m0 >> (minx&(7/dst->depth))*bpp;
1417dd7cddfSDavid du Colombier 	for(x=minx; x<=maxx; x++){
1427dd7cddfSDavid du Colombier 		y = p0.y + (deltay*(x-p0.x)+deltax/2)/deltax;
1437dd7cddfSDavid du Colombier 		if(clipr.min.y<=y && y<clipr.max.y){
1447dd7cddfSDavid du Colombier 			d = byteaddr(dst, Pt(x, y));
1457dd7cddfSDavid du Colombier 			sy = drawreplxy(src->r.min.y, src->r.max.y, y+dsrc.y);
1467dd7cddfSDavid du Colombier 			s = byteaddr(src, Pt(sx, sy));
1477dd7cddfSDavid du Colombier 			*d ^= (*d^*s) & m;
1487dd7cddfSDavid du Colombier 		}
1497dd7cddfSDavid du Colombier 		if(++sx >= src->r.max.x)
1507dd7cddfSDavid du Colombier 			sx = src->r.min.x;
1517dd7cddfSDavid du Colombier 		m >>= bpp;
1527dd7cddfSDavid du Colombier 		if(m == 0)
1537dd7cddfSDavid du Colombier 			m = m0;
1547dd7cddfSDavid du Colombier 	}
1557dd7cddfSDavid du Colombier }
1567dd7cddfSDavid du Colombier 
1577dd7cddfSDavid du Colombier static
1587dd7cddfSDavid du Colombier void
verliner(Memimage * dst,Point p0,Point p1,Memimage * src,Point dsrc,Rectangle clipr)1597dd7cddfSDavid du Colombier verliner(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
1607dd7cddfSDavid du Colombier {
1617dd7cddfSDavid du Colombier 	int x, y, sx, sy, deltay, deltax, miny, maxy;
1627dd7cddfSDavid du Colombier 	int bpp, m, m0;
1637dd7cddfSDavid du Colombier 	uchar *d, *s;
1647dd7cddfSDavid du Colombier 
1657dd7cddfSDavid du Colombier 	deltax = p1.x - p0.x;
1667dd7cddfSDavid du Colombier 	deltay = p1.y - p0.y;
1677dd7cddfSDavid du Colombier 	sy = drawreplxy(src->r.min.y, src->r.max.y, p0.y+dsrc.y);
1687dd7cddfSDavid du Colombier 	miny = lmax(p0.y, clipr.min.y);
1697dd7cddfSDavid du Colombier 	maxy = lmin(p1.y, clipr.max.y-1);
1707dd7cddfSDavid du Colombier 	bpp = dst->depth;
1717dd7cddfSDavid du Colombier 	m0 = 0xFF^(0xFF>>bpp);
1727dd7cddfSDavid du Colombier 	for(y=miny; y<=maxy; y++){
1737dd7cddfSDavid du Colombier 		if(deltay == 0)	/* degenerate line */
1747dd7cddfSDavid du Colombier 			x = p0.x;
1757dd7cddfSDavid du Colombier 		else
1767dd7cddfSDavid du Colombier 			x = p0.x + (deltax*(y-p0.y)+deltay/2)/deltay;
1777dd7cddfSDavid du Colombier 		if(clipr.min.x<=x && x<clipr.max.x){
1787dd7cddfSDavid du Colombier 			m = m0 >> (x&(7/dst->depth))*bpp;
1797dd7cddfSDavid du Colombier 			d = byteaddr(dst, Pt(x, y));
1807dd7cddfSDavid du Colombier 			sx = drawreplxy(src->r.min.x, src->r.max.x, x+dsrc.x);
1817dd7cddfSDavid du Colombier 			s = byteaddr(src, Pt(sx, sy));
1827dd7cddfSDavid du Colombier 			*d ^= (*d^*s) & m;
1837dd7cddfSDavid du Colombier 		}
1847dd7cddfSDavid du Colombier 		if(++sy >= src->r.max.y)
1857dd7cddfSDavid du Colombier 			sy = src->r.min.y;
1867dd7cddfSDavid du Colombier 	}
1877dd7cddfSDavid du Colombier }
1887dd7cddfSDavid du Colombier 
1897dd7cddfSDavid du Colombier static
1907dd7cddfSDavid du Colombier void
horline(Memimage * dst,Point p0,Point p1,Memimage * src,Point dsrc,Rectangle clipr)1917dd7cddfSDavid du Colombier horline(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
1927dd7cddfSDavid du Colombier {
1937dd7cddfSDavid du Colombier 	int x, y, deltay, deltax, minx, maxx;
1947dd7cddfSDavid du Colombier 	int bpp, m, m0;
1957dd7cddfSDavid du Colombier 	uchar *d, *s;
1967dd7cddfSDavid du Colombier 
1977dd7cddfSDavid du Colombier 	deltax = p1.x - p0.x;
1987dd7cddfSDavid du Colombier 	deltay = p1.y - p0.y;
1997dd7cddfSDavid du Colombier 	minx = lmax(p0.x, clipr.min.x);
2007dd7cddfSDavid du Colombier 	maxx = lmin(p1.x, clipr.max.x-1);
2017dd7cddfSDavid du Colombier 	bpp = dst->depth;
2027dd7cddfSDavid du Colombier 	m0 = 0xFF^(0xFF>>bpp);
2037dd7cddfSDavid du Colombier 	m = m0 >> (minx&(7/dst->depth))*bpp;
2047dd7cddfSDavid du Colombier 	for(x=minx; x<=maxx; x++){
2057dd7cddfSDavid du Colombier 		y = p0.y + (deltay*(x-p0.x)+deltay/2)/deltax;
2067dd7cddfSDavid du Colombier 		if(clipr.min.y<=y && y<clipr.max.y){
2077dd7cddfSDavid du Colombier 			d = byteaddr(dst, Pt(x, y));
2087dd7cddfSDavid du Colombier 			s = byteaddr(src, addpt(dsrc, Pt(x, y)));
2097dd7cddfSDavid du Colombier 			*d ^= (*d^*s) & m;
2107dd7cddfSDavid du Colombier 		}
2117dd7cddfSDavid du Colombier 		m >>= bpp;
2127dd7cddfSDavid du Colombier 		if(m == 0)
2137dd7cddfSDavid du Colombier 			m = m0;
2147dd7cddfSDavid du Colombier 	}
2157dd7cddfSDavid du Colombier }
2167dd7cddfSDavid du Colombier 
2177dd7cddfSDavid du Colombier static
2187dd7cddfSDavid du Colombier void
verline(Memimage * dst,Point p0,Point p1,Memimage * src,Point dsrc,Rectangle clipr)2197dd7cddfSDavid du Colombier verline(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
2207dd7cddfSDavid du Colombier {
2217dd7cddfSDavid du Colombier 	int x, y, deltay, deltax, miny, maxy;
2227dd7cddfSDavid du Colombier 	int bpp, m, m0;
2237dd7cddfSDavid du Colombier 	uchar *d, *s;
2247dd7cddfSDavid du Colombier 
2257dd7cddfSDavid du Colombier 	deltax = p1.x - p0.x;
2267dd7cddfSDavid du Colombier 	deltay = p1.y - p0.y;
2277dd7cddfSDavid du Colombier 	miny = lmax(p0.y, clipr.min.y);
2287dd7cddfSDavid du Colombier 	maxy = lmin(p1.y, clipr.max.y-1);
2297dd7cddfSDavid du Colombier 	bpp = dst->depth;
2307dd7cddfSDavid du Colombier 	m0 = 0xFF^(0xFF>>bpp);
2317dd7cddfSDavid du Colombier 	for(y=miny; y<=maxy; y++){
2327dd7cddfSDavid du Colombier 		if(deltay == 0)	/* degenerate line */
2337dd7cddfSDavid du Colombier 			x = p0.x;
2347dd7cddfSDavid du Colombier 		else
2357dd7cddfSDavid du Colombier 			x = p0.x + deltax*(y-p0.y)/deltay;
2367dd7cddfSDavid du Colombier 		if(clipr.min.x<=x && x<clipr.max.x){
2377dd7cddfSDavid du Colombier 			m = m0 >> (x&(7/dst->depth))*bpp;
2387dd7cddfSDavid du Colombier 			d = byteaddr(dst, Pt(x, y));
2397dd7cddfSDavid du Colombier 			s = byteaddr(src, addpt(dsrc, Pt(x, y)));
2407dd7cddfSDavid du Colombier 			*d ^= (*d^*s) & m;
2417dd7cddfSDavid du Colombier 		}
2427dd7cddfSDavid du Colombier 	}
2437dd7cddfSDavid du Colombier }
2446a9fc400SDavid du Colombier #endif /* NOTUSED */
2457dd7cddfSDavid du Colombier 
2467dd7cddfSDavid du Colombier static Memimage*
membrush(int radius)2477dd7cddfSDavid du Colombier membrush(int radius)
2487dd7cddfSDavid du Colombier {
2497dd7cddfSDavid du Colombier 	static Memimage *brush;
2507dd7cddfSDavid du Colombier 	static int brushradius;
2517dd7cddfSDavid du Colombier 
2527dd7cddfSDavid du Colombier 	if(brush==nil || brushradius!=radius){
2537dd7cddfSDavid du Colombier 		freememimage(brush);
2547dd7cddfSDavid du Colombier 		brush = allocmemimage(Rect(0, 0, 2*radius+1, 2*radius+1), memopaque->chan);
2557dd7cddfSDavid du Colombier 		if(brush != nil){
2567dd7cddfSDavid du Colombier 			memfillcolor(brush, DTransparent);	/* zeros */
2576a9fc400SDavid du Colombier 			memellipse(brush, Pt(radius, radius), radius, radius, -1, memopaque, Pt(radius, radius), S);
2587dd7cddfSDavid du Colombier 		}
2597dd7cddfSDavid du Colombier 		brushradius = radius;
2607dd7cddfSDavid du Colombier 	}
2617dd7cddfSDavid du Colombier 	return brush;
2627dd7cddfSDavid du Colombier }
2637dd7cddfSDavid du Colombier 
2647dd7cddfSDavid du Colombier static
2657dd7cddfSDavid du Colombier void
discend(Point p,int radius,Memimage * dst,Memimage * src,Point dsrc,int op)2666a9fc400SDavid du Colombier discend(Point p, int radius, Memimage *dst, Memimage *src, Point dsrc, int op)
2677dd7cddfSDavid du Colombier {
2687dd7cddfSDavid du Colombier 	Memimage *disc;
2697dd7cddfSDavid du Colombier 	Rectangle r;
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier 	disc = membrush(radius);
2727dd7cddfSDavid du Colombier 	if(disc != nil){
2737dd7cddfSDavid du Colombier 		r.min.x = p.x - radius;
2747dd7cddfSDavid du Colombier 		r.min.y = p.y - radius;
2757dd7cddfSDavid du Colombier 		r.max.x = p.x + radius+1;
2767dd7cddfSDavid du Colombier 		r.max.y = p.y + radius+1;
2776a9fc400SDavid du Colombier 		memdraw(dst, r, src, addpt(r.min, dsrc), disc, Pt(0,0), op);
2787dd7cddfSDavid du Colombier 	}
2797dd7cddfSDavid du Colombier }
2807dd7cddfSDavid du Colombier 
2817dd7cddfSDavid du Colombier static
2827dd7cddfSDavid du Colombier void
arrowend(Point tip,Point * pp,int end,int sin,int cos,int radius)2837dd7cddfSDavid du Colombier arrowend(Point tip, Point *pp, int end, int sin, int cos, int radius)
2847dd7cddfSDavid du Colombier {
2857dd7cddfSDavid du Colombier 	int x1, x2, x3;
2867dd7cddfSDavid du Colombier 
2877dd7cddfSDavid du Colombier 	/* before rotation */
2887dd7cddfSDavid du Colombier 	if(end == Endarrow){
2897dd7cddfSDavid du Colombier 		x1 = Arrow1;
2907dd7cddfSDavid du Colombier 		x2 = Arrow2;
2917dd7cddfSDavid du Colombier 		x3 = Arrow3;
2927dd7cddfSDavid du Colombier 	}else{
2937dd7cddfSDavid du Colombier 		x1 = (end>>5) & 0x1FF;	/* distance along line from end of line to tip */
2947dd7cddfSDavid du Colombier 		x2 = (end>>14) & 0x1FF;	/* distance along line from barb to tip */
2957dd7cddfSDavid du Colombier 		x3 = (end>>23) & 0x1FF;	/* distance perpendicular from edge of line to barb */
2967dd7cddfSDavid du Colombier 	}
2977dd7cddfSDavid du Colombier 
2987dd7cddfSDavid du Colombier 	/* comments follow track of right-facing arrowhead */
2997dd7cddfSDavid du Colombier 	pp->x = tip.x+((2*radius+1)*sin/2-x1*cos);		/* upper side of shaft */
3007dd7cddfSDavid du Colombier 	pp->y = tip.y-((2*radius+1)*cos/2+x1*sin);
3017dd7cddfSDavid du Colombier 	pp++;
3027dd7cddfSDavid du Colombier 	pp->x = tip.x+((2*radius+2*x3+1)*sin/2-x2*cos);		/* upper barb */
3037dd7cddfSDavid du Colombier 	pp->y = tip.y-((2*radius+2*x3+1)*cos/2+x2*sin);
3047dd7cddfSDavid du Colombier 	pp++;
3057dd7cddfSDavid du Colombier 	pp->x = tip.x;
3067dd7cddfSDavid du Colombier 	pp->y = tip.y;
3077dd7cddfSDavid du Colombier 	pp++;
3087dd7cddfSDavid du Colombier 	pp->x = tip.x+(-(2*radius+2*x3+1)*sin/2-x2*cos);	/* lower barb */
3097dd7cddfSDavid du Colombier 	pp->y = tip.y-(-(2*radius+2*x3+1)*cos/2+x2*sin);
3107dd7cddfSDavid du Colombier 	pp++;
3117dd7cddfSDavid du Colombier 	pp->x = tip.x+(-(2*radius+1)*sin/2-x1*cos);		/* lower side of shaft */
3127dd7cddfSDavid du Colombier 	pp->y = tip.y+((2*radius+1)*cos/2-x1*sin);
3137dd7cddfSDavid du Colombier }
3147dd7cddfSDavid du Colombier 
3157dd7cddfSDavid du Colombier void
_memimageline(Memimage * dst,Point p0,Point p1,int end0,int end1,int radius,Memimage * src,Point sp,Rectangle clipr,int op)3166a9fc400SDavid du Colombier _memimageline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, Rectangle clipr, int op)
3177dd7cddfSDavid du Colombier {
3187dd7cddfSDavid du Colombier 	/*
3197dd7cddfSDavid du Colombier 	 * BUG: We should really really pick off purely horizontal and purely
3207dd7cddfSDavid du Colombier 	 * vertical lines and handle them separately with calls to memimagedraw
3217dd7cddfSDavid du Colombier 	 * on rectangles.
3227dd7cddfSDavid du Colombier 	 */
3237dd7cddfSDavid du Colombier 
3247dd7cddfSDavid du Colombier 	int hor;
3257dd7cddfSDavid du Colombier 	int sin, cos, dx, dy, t;
3266a9fc400SDavid du Colombier 	Rectangle oclipr, r;
3277dd7cddfSDavid du Colombier 	Point q, pts[10], *pp, d;
3287dd7cddfSDavid du Colombier 
3297dd7cddfSDavid du Colombier 	if(radius < 0)
3307dd7cddfSDavid du Colombier 		return;
3317dd7cddfSDavid du Colombier 	if(rectclip(&clipr, dst->r) == 0)
3327dd7cddfSDavid du Colombier 		return;
3337dd7cddfSDavid du Colombier 	if(rectclip(&clipr, dst->clipr) == 0)
3347dd7cddfSDavid du Colombier 		return;
3357dd7cddfSDavid du Colombier 	d = subpt(sp, p0);
3367dd7cddfSDavid du Colombier 	if(rectclip(&clipr, rectsubpt(src->clipr, d)) == 0)
3377dd7cddfSDavid du Colombier 		return;
3387dd7cddfSDavid du Colombier 	if((src->flags&Frepl)==0 && rectclip(&clipr, rectsubpt(src->r, d))==0)
3397dd7cddfSDavid du Colombier 		return;
3407dd7cddfSDavid du Colombier 	/* this means that only verline() handles degenerate lines (p0==p1) */
3417dd7cddfSDavid du Colombier 	hor = (abs(p1.x-p0.x) > abs(p1.y-p0.y));
3427dd7cddfSDavid du Colombier 	/*
3437dd7cddfSDavid du Colombier 	 * Clipping is a little peculiar.  We can't use Sutherland-Cohen
3447dd7cddfSDavid du Colombier 	 * clipping because lines are wide.  But this is probably just fine:
3457dd7cddfSDavid du Colombier 	 * we do all math with the original p0 and p1, but clip when deciding
3467dd7cddfSDavid du Colombier 	 * what pixels to draw.  This means the layer code can call this routine,
3477dd7cddfSDavid du Colombier 	 * using clipr to define the region being written, and get the same set
3487dd7cddfSDavid du Colombier 	 * of pixels regardless of the dicing.
3497dd7cddfSDavid du Colombier 	 */
3507dd7cddfSDavid du Colombier 	if((hor && p0.x>p1.x) || (!hor && p0.y>p1.y)){
3517dd7cddfSDavid du Colombier 		q = p0;
3527dd7cddfSDavid du Colombier 		p0 = p1;
3537dd7cddfSDavid du Colombier 		p1 = q;
3547dd7cddfSDavid du Colombier 		t = end0;
3557dd7cddfSDavid du Colombier 		end0 = end1;
3567dd7cddfSDavid du Colombier 		end1 = t;
3577dd7cddfSDavid du Colombier 	}
3587dd7cddfSDavid du Colombier 
3596a9fc400SDavid du Colombier 	if((p0.x == p1.x || p0.y == p1.y) && (end0&0x1F) == Endsquare && (end1&0x1F) == Endsquare){
3606a9fc400SDavid du Colombier 		r.min = p0;
3616a9fc400SDavid du Colombier 		r.max = p1;
3626a9fc400SDavid du Colombier 		if(p0.x == p1.x){
3636a9fc400SDavid du Colombier 			r.min.x -= radius;
3646a9fc400SDavid du Colombier 			r.max.x += radius+1;
3656a9fc400SDavid du Colombier 		}
3666a9fc400SDavid du Colombier 		else{
3676a9fc400SDavid du Colombier 			r.min.y -= radius;
3686a9fc400SDavid du Colombier 			r.max.y += radius+1;
3696a9fc400SDavid du Colombier 		}
3706a9fc400SDavid du Colombier 		oclipr = dst->clipr;
371*e5b1f7ddSDavid du Colombier 		sp = addpt(r.min, d);
3726a9fc400SDavid du Colombier 		dst->clipr = clipr;
3736a9fc400SDavid du Colombier 		memimagedraw(dst, r, src, sp, memopaque, sp, op);
3746a9fc400SDavid du Colombier 		dst->clipr = oclipr;
3756a9fc400SDavid du Colombier 		return;
3766a9fc400SDavid du Colombier 	}
3776a9fc400SDavid du Colombier 
3787dd7cddfSDavid du Colombier /*    Hard: */
3797dd7cddfSDavid du Colombier 	/* draw thick line using polygon fill */
3807dd7cddfSDavid du Colombier 	icossin2(p1.x-p0.x, p1.y-p0.y, &cos, &sin);
3817dd7cddfSDavid du Colombier 	dx = (sin*(2*radius+1))/2;
3827dd7cddfSDavid du Colombier 	dy = (cos*(2*radius+1))/2;
3837dd7cddfSDavid du Colombier 	pp = pts;
3847dd7cddfSDavid du Colombier 	oclipr = dst->clipr;
3857dd7cddfSDavid du Colombier 	dst->clipr = clipr;
3867dd7cddfSDavid du Colombier 	q.x = ICOSSCALE*p0.x+ICOSSCALE/2-cos/2;
3877dd7cddfSDavid du Colombier 	q.y = ICOSSCALE*p0.y+ICOSSCALE/2-sin/2;
3887dd7cddfSDavid du Colombier 	switch(end0 & 0x1F){
3897dd7cddfSDavid du Colombier 	case Enddisc:
3906a9fc400SDavid du Colombier 		discend(p0, radius, dst, src, d, op);
3917dd7cddfSDavid du Colombier 		/* fall through */
3927dd7cddfSDavid du Colombier 	case Endsquare:
3937dd7cddfSDavid du Colombier 	default:
3947dd7cddfSDavid du Colombier 		pp->x = q.x-dx;
3957dd7cddfSDavid du Colombier 		pp->y = q.y+dy;
3967dd7cddfSDavid du Colombier 		pp++;
3977dd7cddfSDavid du Colombier 		pp->x = q.x+dx;
3987dd7cddfSDavid du Colombier 		pp->y = q.y-dy;
3997dd7cddfSDavid du Colombier 		pp++;
4007dd7cddfSDavid du Colombier 		break;
4017dd7cddfSDavid du Colombier 	case Endarrow:
4027dd7cddfSDavid du Colombier 		arrowend(q, pp, end0, -sin, -cos, radius);
4036a9fc400SDavid du Colombier 		_memfillpolysc(dst, pts, 5, ~0, src, addpt(pts[0], mulpt(d, ICOSSCALE)), 1, 10, 1, op);
4047dd7cddfSDavid du Colombier 		pp[1] = pp[4];
4057dd7cddfSDavid du Colombier 		pp += 2;
4067dd7cddfSDavid du Colombier 	}
4077dd7cddfSDavid du Colombier 	q.x = ICOSSCALE*p1.x+ICOSSCALE/2+cos/2;
4087dd7cddfSDavid du Colombier 	q.y = ICOSSCALE*p1.y+ICOSSCALE/2+sin/2;
4097dd7cddfSDavid du Colombier 	switch(end1 & 0x1F){
4107dd7cddfSDavid du Colombier 	case Enddisc:
4116a9fc400SDavid du Colombier 		discend(p1, radius, dst, src, d, op);
4127dd7cddfSDavid du Colombier 		/* fall through */
4137dd7cddfSDavid du Colombier 	case Endsquare:
4147dd7cddfSDavid du Colombier 	default:
4157dd7cddfSDavid du Colombier 		pp->x = q.x+dx;
4167dd7cddfSDavid du Colombier 		pp->y = q.y-dy;
4177dd7cddfSDavid du Colombier 		pp++;
4187dd7cddfSDavid du Colombier 		pp->x = q.x-dx;
4197dd7cddfSDavid du Colombier 		pp->y = q.y+dy;
4207dd7cddfSDavid du Colombier 		pp++;
4217dd7cddfSDavid du Colombier 		break;
4227dd7cddfSDavid du Colombier 	case Endarrow:
4237dd7cddfSDavid du Colombier 		arrowend(q, pp, end1, sin, cos, radius);
424843560e6SDavid du Colombier 		_memfillpolysc(dst, pp, 5, ~0, src, addpt(pp[0], mulpt(d, ICOSSCALE)), 1, 10, 1, op);
4257dd7cddfSDavid du Colombier 		pp[1] = pp[4];
4267dd7cddfSDavid du Colombier 		pp += 2;
4277dd7cddfSDavid du Colombier 	}
4286a9fc400SDavid du Colombier 	_memfillpolysc(dst, pts, pp-pts, ~0, src, addpt(pts[0], mulpt(d, ICOSSCALE)), 0, 10, 1, op);
4297dd7cddfSDavid du Colombier 	dst->clipr = oclipr;
4307dd7cddfSDavid du Colombier 	return;
4317dd7cddfSDavid du Colombier }
4327dd7cddfSDavid du Colombier 
4337dd7cddfSDavid du Colombier void
memimageline(Memimage * dst,Point p0,Point p1,int end0,int end1,int radius,Memimage * src,Point sp,int op)4346a9fc400SDavid du Colombier memimageline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, int op)
4357dd7cddfSDavid du Colombier {
4366a9fc400SDavid du Colombier 	_memimageline(dst, p0, p1, end0, end1, radius, src, sp, dst->clipr, op);
4377dd7cddfSDavid du Colombier }
4387dd7cddfSDavid du Colombier 
4397dd7cddfSDavid du Colombier /*
4407dd7cddfSDavid du Colombier  * Simple-minded conservative code to compute bounding box of line.
4417dd7cddfSDavid du Colombier  * Result is probably a little larger than it needs to be.
4427dd7cddfSDavid du Colombier  */
4437dd7cddfSDavid du Colombier static
4447dd7cddfSDavid du Colombier void
addbbox(Rectangle * r,Point p)4457dd7cddfSDavid du Colombier addbbox(Rectangle *r, Point p)
4467dd7cddfSDavid du Colombier {
4477dd7cddfSDavid du Colombier 	if(r->min.x > p.x)
4487dd7cddfSDavid du Colombier 		r->min.x = p.x;
4497dd7cddfSDavid du Colombier 	if(r->min.y > p.y)
4507dd7cddfSDavid du Colombier 		r->min.y = p.y;
4517dd7cddfSDavid du Colombier 	if(r->max.x < p.x+1)
4527dd7cddfSDavid du Colombier 		r->max.x = p.x+1;
4537dd7cddfSDavid du Colombier 	if(r->max.y < p.y+1)
4547dd7cddfSDavid du Colombier 		r->max.y = p.y+1;
4557dd7cddfSDavid du Colombier }
4567dd7cddfSDavid du Colombier 
4577dd7cddfSDavid du Colombier int
memlineendsize(int end)4587dd7cddfSDavid du Colombier memlineendsize(int end)
4597dd7cddfSDavid du Colombier {
4607dd7cddfSDavid du Colombier 	int x3;
4617dd7cddfSDavid du Colombier 
4627dd7cddfSDavid du Colombier 	if((end&0x3F) != Endarrow)
4637dd7cddfSDavid du Colombier 		return 0;
4647dd7cddfSDavid du Colombier 	if(end == Endarrow)
4657dd7cddfSDavid du Colombier 		x3 = Arrow3;
4667dd7cddfSDavid du Colombier 	else
4677dd7cddfSDavid du Colombier 		x3 = (end>>23) & 0x1FF;
4687dd7cddfSDavid du Colombier 	return x3;
4697dd7cddfSDavid du Colombier }
4707dd7cddfSDavid du Colombier 
4717dd7cddfSDavid du Colombier Rectangle
memlinebbox(Point p0,Point p1,int end0,int end1,int radius)4727dd7cddfSDavid du Colombier memlinebbox(Point p0, Point p1, int end0, int end1, int radius)
4737dd7cddfSDavid du Colombier {
4747dd7cddfSDavid du Colombier 	Rectangle r, r1;
4757dd7cddfSDavid du Colombier 	int extra;
4767dd7cddfSDavid du Colombier 
4777dd7cddfSDavid du Colombier 	r.min.x = 10000000;
4787dd7cddfSDavid du Colombier 	r.min.y = 10000000;
4797dd7cddfSDavid du Colombier 	r.max.x = -10000000;
4807dd7cddfSDavid du Colombier 	r.max.y = -10000000;
4817dd7cddfSDavid du Colombier 	extra = lmax(memlineendsize(end0), memlineendsize(end1));
4827dd7cddfSDavid du Colombier 	r1 = insetrect(canonrect(Rpt(p0, p1)), -(radius+extra));
4837dd7cddfSDavid du Colombier 	addbbox(&r, r1.min);
4847dd7cddfSDavid du Colombier 	addbbox(&r, r1.max);
4857dd7cddfSDavid du Colombier 	return r;
4867dd7cddfSDavid du Colombier }
487