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