xref: /plan9-contrib/sys/src/cmd/unix/drawterm/libmemdraw/line.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1*7dd7cddfSDavid du Colombier #include "../lib9.h"
2*7dd7cddfSDavid du Colombier 
3*7dd7cddfSDavid du Colombier #include "../libdraw/draw.h"
4*7dd7cddfSDavid du Colombier #include "../libmemdraw/memdraw.h"
5*7dd7cddfSDavid du Colombier #include "../libmemlayer/memlayer.h"
6*7dd7cddfSDavid du Colombier 
7*7dd7cddfSDavid du Colombier enum
8*7dd7cddfSDavid du Colombier {
9*7dd7cddfSDavid du Colombier 	Arrow1 = 8,
10*7dd7cddfSDavid du Colombier 	Arrow2 = 10,
11*7dd7cddfSDavid du Colombier 	Arrow3 = 3
12*7dd7cddfSDavid du Colombier };
13*7dd7cddfSDavid du Colombier 
14*7dd7cddfSDavid du Colombier /*
15*7dd7cddfSDavid du Colombier  * not used
16*7dd7cddfSDavid du Colombier static
17*7dd7cddfSDavid du Colombier int
18*7dd7cddfSDavid du Colombier lmin(int a, int b)
19*7dd7cddfSDavid du Colombier {
20*7dd7cddfSDavid du Colombier 	if(a < b)
21*7dd7cddfSDavid du Colombier 		return a;
22*7dd7cddfSDavid du Colombier 	return b;
23*7dd7cddfSDavid du Colombier }
24*7dd7cddfSDavid du Colombier */
25*7dd7cddfSDavid du Colombier 
26*7dd7cddfSDavid du Colombier static
27*7dd7cddfSDavid du Colombier int
28*7dd7cddfSDavid du Colombier lmax(int a, int b)
29*7dd7cddfSDavid du Colombier {
30*7dd7cddfSDavid du Colombier 	if(a > b)
31*7dd7cddfSDavid du Colombier 		return a;
32*7dd7cddfSDavid du Colombier 	return b;
33*7dd7cddfSDavid du Colombier }
34*7dd7cddfSDavid du Colombier 
35*7dd7cddfSDavid du Colombier /*
36*7dd7cddfSDavid du Colombier  * Rather than line clip, we run the Bresenham loop over the full line,
37*7dd7cddfSDavid du Colombier  * and clip on each pixel.  This is more expensive but means that
38*7dd7cddfSDavid du Colombier  * lines look the same regardless of how the windowing has tiled them.
39*7dd7cddfSDavid du Colombier  * For speed, we check for clipping outside the loop and make the
40*7dd7cddfSDavid du Colombier  * test easy when possible.
41*7dd7cddfSDavid du Colombier  */
42*7dd7cddfSDavid du Colombier 
43*7dd7cddfSDavid du Colombier #ifdef NOTUSED
44*7dd7cddfSDavid du Colombier static
45*7dd7cddfSDavid du Colombier void
46*7dd7cddfSDavid du Colombier horline1(Memimage *dst, Point p0, Point p1, int srcval, Rectangle clipr)
47*7dd7cddfSDavid du Colombier {
48*7dd7cddfSDavid du Colombier 	int x, y, dy, deltay, deltax, maxx;
49*7dd7cddfSDavid du Colombier 	int dd, easy, e, bpp, m, m0;
50*7dd7cddfSDavid du Colombier 	uchar *d;
51*7dd7cddfSDavid du Colombier 
52*7dd7cddfSDavid du Colombier 	deltax = p1.x - p0.x;
53*7dd7cddfSDavid du Colombier 	deltay = p1.y - p0.y;
54*7dd7cddfSDavid du Colombier 	dd = dst->width*sizeof(ulong);
55*7dd7cddfSDavid du Colombier 	dy = 1;
56*7dd7cddfSDavid du Colombier 	if(deltay < 0){
57*7dd7cddfSDavid du Colombier 		dd = -dd;
58*7dd7cddfSDavid du Colombier 		deltay = -deltay;
59*7dd7cddfSDavid du Colombier 		dy = -1;
60*7dd7cddfSDavid du Colombier 	}
61*7dd7cddfSDavid du Colombier 	maxx = lmin(p1.x, clipr.max.x-1);
62*7dd7cddfSDavid du Colombier 	bpp = dst->depth;
63*7dd7cddfSDavid du Colombier 	m0 = 0xFF^(0xFF>>bpp);
64*7dd7cddfSDavid du Colombier 	m = m0 >> (p0.x&(7/dst->depth))*bpp;
65*7dd7cddfSDavid du Colombier 	easy = ptinrect(p0, clipr) && ptinrect(p1, clipr);
66*7dd7cddfSDavid du Colombier 	e = 2*deltay - deltax;
67*7dd7cddfSDavid du Colombier 	y = p0.y;
68*7dd7cddfSDavid du Colombier 	d = byteaddr(dst, p0);
69*7dd7cddfSDavid du Colombier 	deltay *= 2;
70*7dd7cddfSDavid du Colombier 	deltax = deltay - 2*deltax;
71*7dd7cddfSDavid du Colombier 	for(x=p0.x; x<=maxx; x++){
72*7dd7cddfSDavid du Colombier 		if(easy || (clipr.min.x<=x && clipr.min.y<=y && y<clipr.max.y))
73*7dd7cddfSDavid du Colombier 			*d ^= (*d^srcval) & m;
74*7dd7cddfSDavid du Colombier 		if(e > 0){
75*7dd7cddfSDavid du Colombier 			y += dy;
76*7dd7cddfSDavid du Colombier 			d += dd;
77*7dd7cddfSDavid du Colombier 			e += deltax;
78*7dd7cddfSDavid du Colombier 		}else
79*7dd7cddfSDavid du Colombier 			e += deltay;
80*7dd7cddfSDavid du Colombier 		d++;
81*7dd7cddfSDavid du Colombier 		m >>= bpp;
82*7dd7cddfSDavid du Colombier 		if(m == 0)
83*7dd7cddfSDavid du Colombier 			m = m0;
84*7dd7cddfSDavid du Colombier 	}
85*7dd7cddfSDavid du Colombier }
86*7dd7cddfSDavid du Colombier 
87*7dd7cddfSDavid du Colombier static
88*7dd7cddfSDavid du Colombier void
89*7dd7cddfSDavid du Colombier verline1(Memimage *dst, Point p0, Point p1, int srcval, Rectangle clipr)
90*7dd7cddfSDavid du Colombier {
91*7dd7cddfSDavid du Colombier 	int x, y, deltay, deltax, maxy;
92*7dd7cddfSDavid du Colombier 	int easy, e, bpp, m, m0, dd;
93*7dd7cddfSDavid du Colombier 	uchar *d;
94*7dd7cddfSDavid du Colombier 
95*7dd7cddfSDavid du Colombier 	deltax = p1.x - p0.x;
96*7dd7cddfSDavid du Colombier 	deltay = p1.y - p0.y;
97*7dd7cddfSDavid du Colombier 	dd = 1;
98*7dd7cddfSDavid du Colombier 	if(deltax < 0){
99*7dd7cddfSDavid du Colombier 		dd = -1;
100*7dd7cddfSDavid du Colombier 		deltax = -deltax;
101*7dd7cddfSDavid du Colombier 	}
102*7dd7cddfSDavid du Colombier 	maxy = lmin(p1.y, clipr.max.y-1);
103*7dd7cddfSDavid du Colombier 	bpp = dst->depth;
104*7dd7cddfSDavid du Colombier 	m0 = 0xFF^(0xFF>>bpp);
105*7dd7cddfSDavid du Colombier 	m = m0 >> (p0.x&(7/dst->depth))*bpp;
106*7dd7cddfSDavid du Colombier 	easy = ptinrect(p0, clipr) && ptinrect(p1, clipr);
107*7dd7cddfSDavid du Colombier 	e = 2*deltax - deltay;
108*7dd7cddfSDavid du Colombier 	x = p0.x;
109*7dd7cddfSDavid du Colombier 	d = byteaddr(dst, p0);
110*7dd7cddfSDavid du Colombier 	deltax *= 2;
111*7dd7cddfSDavid du Colombier 	deltay = deltax - 2*deltay;
112*7dd7cddfSDavid du Colombier 	for(y=p0.y; y<=maxy; y++){
113*7dd7cddfSDavid du Colombier 		if(easy || (clipr.min.y<=y && clipr.min.x<=x && x<clipr.max.x))
114*7dd7cddfSDavid du Colombier 			*d ^= (*d^srcval) & m;
115*7dd7cddfSDavid du Colombier 		if(e > 0){
116*7dd7cddfSDavid du Colombier 			x += dd;
117*7dd7cddfSDavid du Colombier 			d += dd;
118*7dd7cddfSDavid du Colombier 			e += deltay;
119*7dd7cddfSDavid du Colombier 		}else
120*7dd7cddfSDavid du Colombier 			e += deltax;
121*7dd7cddfSDavid du Colombier 		d += dst->width*sizeof(ulong);
122*7dd7cddfSDavid du Colombier 		m >>= bpp;
123*7dd7cddfSDavid du Colombier 		if(m == 0)
124*7dd7cddfSDavid du Colombier 			m = m0;
125*7dd7cddfSDavid du Colombier 	}
126*7dd7cddfSDavid du Colombier }
127*7dd7cddfSDavid du Colombier 
128*7dd7cddfSDavid du Colombier static
129*7dd7cddfSDavid du Colombier void
130*7dd7cddfSDavid du Colombier horliner(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
131*7dd7cddfSDavid du Colombier {
132*7dd7cddfSDavid du Colombier 	int x, y, sx, sy, deltay, deltax, minx, maxx;
133*7dd7cddfSDavid du Colombier 	int bpp, m, m0;
134*7dd7cddfSDavid du Colombier 	uchar *d, *s;
135*7dd7cddfSDavid du Colombier 
136*7dd7cddfSDavid du Colombier 	deltax = p1.x - p0.x;
137*7dd7cddfSDavid du Colombier 	deltay = p1.y - p0.y;
138*7dd7cddfSDavid du Colombier 	sx = drawreplxy(src->r.min.x, src->r.max.x, p0.x+dsrc.x);
139*7dd7cddfSDavid du Colombier 	minx = lmax(p0.x, clipr.min.x);
140*7dd7cddfSDavid du Colombier 	maxx = lmin(p1.x, clipr.max.x-1);
141*7dd7cddfSDavid du Colombier 	bpp = dst->depth;
142*7dd7cddfSDavid du Colombier 	m0 = 0xFF^(0xFF>>bpp);
143*7dd7cddfSDavid du Colombier 	m = m0 >> (minx&(7/dst->depth))*bpp;
144*7dd7cddfSDavid du Colombier 	for(x=minx; x<=maxx; x++){
145*7dd7cddfSDavid du Colombier 		y = p0.y + (deltay*(x-p0.x)+deltax/2)/deltax;
146*7dd7cddfSDavid du Colombier 		if(clipr.min.y<=y && y<clipr.max.y){
147*7dd7cddfSDavid du Colombier 			d = byteaddr(dst, Pt(x, y));
148*7dd7cddfSDavid du Colombier 			sy = drawreplxy(src->r.min.y, src->r.max.y, y+dsrc.y);
149*7dd7cddfSDavid du Colombier 			s = byteaddr(src, Pt(sx, sy));
150*7dd7cddfSDavid du Colombier 			*d ^= (*d^*s) & m;
151*7dd7cddfSDavid du Colombier 		}
152*7dd7cddfSDavid du Colombier 		if(++sx >= src->r.max.x)
153*7dd7cddfSDavid du Colombier 			sx = src->r.min.x;
154*7dd7cddfSDavid du Colombier 		m >>= bpp;
155*7dd7cddfSDavid du Colombier 		if(m == 0)
156*7dd7cddfSDavid du Colombier 			m = m0;
157*7dd7cddfSDavid du Colombier 	}
158*7dd7cddfSDavid du Colombier }
159*7dd7cddfSDavid du Colombier 
160*7dd7cddfSDavid du Colombier static
161*7dd7cddfSDavid du Colombier void
162*7dd7cddfSDavid du Colombier verliner(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
163*7dd7cddfSDavid du Colombier {
164*7dd7cddfSDavid du Colombier 	int x, y, sx, sy, deltay, deltax, miny, maxy;
165*7dd7cddfSDavid du Colombier 	int bpp, m, m0;
166*7dd7cddfSDavid du Colombier 	uchar *d, *s;
167*7dd7cddfSDavid du Colombier 
168*7dd7cddfSDavid du Colombier 	deltax = p1.x - p0.x;
169*7dd7cddfSDavid du Colombier 	deltay = p1.y - p0.y;
170*7dd7cddfSDavid du Colombier 	sy = drawreplxy(src->r.min.y, src->r.max.y, p0.y+dsrc.y);
171*7dd7cddfSDavid du Colombier 	miny = lmax(p0.y, clipr.min.y);
172*7dd7cddfSDavid du Colombier 	maxy = lmin(p1.y, clipr.max.y-1);
173*7dd7cddfSDavid du Colombier 	bpp = dst->depth;
174*7dd7cddfSDavid du Colombier 	m0 = 0xFF^(0xFF>>bpp);
175*7dd7cddfSDavid du Colombier 	for(y=miny; y<=maxy; y++){
176*7dd7cddfSDavid du Colombier 		if(deltay == 0)	/* degenerate line */
177*7dd7cddfSDavid du Colombier 			x = p0.x;
178*7dd7cddfSDavid du Colombier 		else
179*7dd7cddfSDavid du Colombier 			x = p0.x + (deltax*(y-p0.y)+deltay/2)/deltay;
180*7dd7cddfSDavid du Colombier 		if(clipr.min.x<=x && x<clipr.max.x){
181*7dd7cddfSDavid du Colombier 			m = m0 >> (x&(7/dst->depth))*bpp;
182*7dd7cddfSDavid du Colombier 			d = byteaddr(dst, Pt(x, y));
183*7dd7cddfSDavid du Colombier 			sx = drawreplxy(src->r.min.x, src->r.max.x, x+dsrc.x);
184*7dd7cddfSDavid du Colombier 			s = byteaddr(src, Pt(sx, sy));
185*7dd7cddfSDavid du Colombier 			*d ^= (*d^*s) & m;
186*7dd7cddfSDavid du Colombier 		}
187*7dd7cddfSDavid du Colombier 		if(++sy >= src->r.max.y)
188*7dd7cddfSDavid du Colombier 			sy = src->r.min.y;
189*7dd7cddfSDavid du Colombier 	}
190*7dd7cddfSDavid du Colombier }
191*7dd7cddfSDavid du Colombier 
192*7dd7cddfSDavid du Colombier static
193*7dd7cddfSDavid du Colombier void
194*7dd7cddfSDavid du Colombier horline(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
195*7dd7cddfSDavid du Colombier {
196*7dd7cddfSDavid du Colombier 	int x, y, deltay, deltax, minx, maxx;
197*7dd7cddfSDavid du Colombier 	int bpp, m, m0;
198*7dd7cddfSDavid du Colombier 	uchar *d, *s;
199*7dd7cddfSDavid du Colombier 
200*7dd7cddfSDavid du Colombier 	deltax = p1.x - p0.x;
201*7dd7cddfSDavid du Colombier 	deltay = p1.y - p0.y;
202*7dd7cddfSDavid du Colombier 	minx = lmax(p0.x, clipr.min.x);
203*7dd7cddfSDavid du Colombier 	maxx = lmin(p1.x, clipr.max.x-1);
204*7dd7cddfSDavid du Colombier 	bpp = dst->depth;
205*7dd7cddfSDavid du Colombier 	m0 = 0xFF^(0xFF>>bpp);
206*7dd7cddfSDavid du Colombier 	m = m0 >> (minx&(7/dst->depth))*bpp;
207*7dd7cddfSDavid du Colombier 	for(x=minx; x<=maxx; x++){
208*7dd7cddfSDavid du Colombier 		y = p0.y + (deltay*(x-p0.x)+deltay/2)/deltax;
209*7dd7cddfSDavid du Colombier 		if(clipr.min.y<=y && y<clipr.max.y){
210*7dd7cddfSDavid du Colombier 			d = byteaddr(dst, Pt(x, y));
211*7dd7cddfSDavid du Colombier 			s = byteaddr(src, addpt(dsrc, Pt(x, y)));
212*7dd7cddfSDavid du Colombier 			*d ^= (*d^*s) & m;
213*7dd7cddfSDavid du Colombier 		}
214*7dd7cddfSDavid du Colombier 		m >>= bpp;
215*7dd7cddfSDavid du Colombier 		if(m == 0)
216*7dd7cddfSDavid du Colombier 			m = m0;
217*7dd7cddfSDavid du Colombier 	}
218*7dd7cddfSDavid du Colombier }
219*7dd7cddfSDavid du Colombier 
220*7dd7cddfSDavid du Colombier static
221*7dd7cddfSDavid du Colombier void
222*7dd7cddfSDavid du Colombier verline(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
223*7dd7cddfSDavid du Colombier {
224*7dd7cddfSDavid du Colombier 	int x, y, deltay, deltax, miny, maxy;
225*7dd7cddfSDavid du Colombier 	int bpp, m, m0;
226*7dd7cddfSDavid du Colombier 	uchar *d, *s;
227*7dd7cddfSDavid du Colombier 
228*7dd7cddfSDavid du Colombier 	deltax = p1.x - p0.x;
229*7dd7cddfSDavid du Colombier 	deltay = p1.y - p0.y;
230*7dd7cddfSDavid du Colombier 	miny = lmax(p0.y, clipr.min.y);
231*7dd7cddfSDavid du Colombier 	maxy = lmin(p1.y, clipr.max.y-1);
232*7dd7cddfSDavid du Colombier 	bpp = dst->depth;
233*7dd7cddfSDavid du Colombier 	m0 = 0xFF^(0xFF>>bpp);
234*7dd7cddfSDavid du Colombier 	for(y=miny; y<=maxy; y++){
235*7dd7cddfSDavid du Colombier 		if(deltay == 0)	/* degenerate line */
236*7dd7cddfSDavid du Colombier 			x = p0.x;
237*7dd7cddfSDavid du Colombier 		else
238*7dd7cddfSDavid du Colombier 			x = p0.x + deltax*(y-p0.y)/deltay;
239*7dd7cddfSDavid du Colombier 		if(clipr.min.x<=x && x<clipr.max.x){
240*7dd7cddfSDavid du Colombier 			m = m0 >> (x&(7/dst->depth))*bpp;
241*7dd7cddfSDavid du Colombier 			d = byteaddr(dst, Pt(x, y));
242*7dd7cddfSDavid du Colombier 			s = byteaddr(src, addpt(dsrc, Pt(x, y)));
243*7dd7cddfSDavid du Colombier 			*d ^= (*d^*s) & m;
244*7dd7cddfSDavid du Colombier 		}
245*7dd7cddfSDavid du Colombier 	}
246*7dd7cddfSDavid du Colombier }
247*7dd7cddfSDavid du Colombier #endif /* NOTUSED */
248*7dd7cddfSDavid du Colombier 
249*7dd7cddfSDavid du Colombier Memimage*
250*7dd7cddfSDavid du Colombier membrush(int radius)
251*7dd7cddfSDavid du Colombier {
252*7dd7cddfSDavid du Colombier 	static Memimage *brush;
253*7dd7cddfSDavid du Colombier 	static int brushradius;
254*7dd7cddfSDavid du Colombier 
255*7dd7cddfSDavid du Colombier 	if(brush==nil || brushradius!=radius){
256*7dd7cddfSDavid du Colombier 		freememimage(brush);
257*7dd7cddfSDavid du Colombier 		brush = allocmemimage(Rect(0, 0, 2*radius+1, 2*radius+1), memopaque->chan);
258*7dd7cddfSDavid du Colombier 		if(brush != nil){
259*7dd7cddfSDavid du Colombier 			memfillcolor(brush, DTransparent);	/* zeros */
260*7dd7cddfSDavid du Colombier 			memellipse(brush, Pt(radius, radius), radius, radius, -1, memopaque, Pt(radius, radius));
261*7dd7cddfSDavid du Colombier 		}
262*7dd7cddfSDavid du Colombier 		brushradius = radius;
263*7dd7cddfSDavid du Colombier 	}
264*7dd7cddfSDavid du Colombier 	return brush;
265*7dd7cddfSDavid du Colombier }
266*7dd7cddfSDavid du Colombier 
267*7dd7cddfSDavid du Colombier static
268*7dd7cddfSDavid du Colombier void
269*7dd7cddfSDavid du Colombier discend(Point p, int radius, Memimage *dst, Memimage *src, Point dsrc)
270*7dd7cddfSDavid du Colombier {
271*7dd7cddfSDavid du Colombier 	Memimage *disc;
272*7dd7cddfSDavid du Colombier 	Rectangle r;
273*7dd7cddfSDavid du Colombier 
274*7dd7cddfSDavid du Colombier 	disc = membrush(radius);
275*7dd7cddfSDavid du Colombier 	if(disc != nil){
276*7dd7cddfSDavid du Colombier 		r.min.x = p.x - radius;
277*7dd7cddfSDavid du Colombier 		r.min.y = p.y - radius;
278*7dd7cddfSDavid du Colombier 		r.max.x = p.x + radius+1;
279*7dd7cddfSDavid du Colombier 		r.max.y = p.y + radius+1;
280*7dd7cddfSDavid du Colombier 		memdraw(dst, r, src, addpt(r.min, dsrc), disc, Pt(0,0));
281*7dd7cddfSDavid du Colombier 	}
282*7dd7cddfSDavid du Colombier }
283*7dd7cddfSDavid du Colombier 
284*7dd7cddfSDavid du Colombier static
285*7dd7cddfSDavid du Colombier void
286*7dd7cddfSDavid du Colombier arrowend(Point tip, Point *pp, int end, int sin, int cos, int radius)
287*7dd7cddfSDavid du Colombier {
288*7dd7cddfSDavid du Colombier 	int x1, x2, x3;
289*7dd7cddfSDavid du Colombier 
290*7dd7cddfSDavid du Colombier 	/* before rotation */
291*7dd7cddfSDavid du Colombier 	if(end == Endarrow){
292*7dd7cddfSDavid du Colombier 		x1 = Arrow1;
293*7dd7cddfSDavid du Colombier 		x2 = Arrow2;
294*7dd7cddfSDavid du Colombier 		x3 = Arrow3;
295*7dd7cddfSDavid du Colombier 	}else{
296*7dd7cddfSDavid du Colombier 		x1 = (end>>5) & 0x1FF;	/* distance along line from end of line to tip */
297*7dd7cddfSDavid du Colombier 		x2 = (end>>14) & 0x1FF;	/* distance along line from barb to tip */
298*7dd7cddfSDavid du Colombier 		x3 = (end>>23) & 0x1FF;	/* distance perpendicular from edge of line to barb */
299*7dd7cddfSDavid du Colombier 	}
300*7dd7cddfSDavid du Colombier 
301*7dd7cddfSDavid du Colombier 	/* comments follow track of right-facing arrowhead */
302*7dd7cddfSDavid du Colombier 	pp->x = tip.x+((2*radius+1)*sin/2-x1*cos);		/* upper side of shaft */
303*7dd7cddfSDavid du Colombier 	pp->y = tip.y-((2*radius+1)*cos/2+x1*sin);
304*7dd7cddfSDavid du Colombier 	pp++;
305*7dd7cddfSDavid du Colombier 	pp->x = tip.x+((2*radius+2*x3+1)*sin/2-x2*cos);		/* upper barb */
306*7dd7cddfSDavid du Colombier 	pp->y = tip.y-((2*radius+2*x3+1)*cos/2+x2*sin);
307*7dd7cddfSDavid du Colombier 	pp++;
308*7dd7cddfSDavid du Colombier 	pp->x = tip.x;
309*7dd7cddfSDavid du Colombier 	pp->y = tip.y;
310*7dd7cddfSDavid du Colombier 	pp++;
311*7dd7cddfSDavid du Colombier 	pp->x = tip.x+(-(2*radius+2*x3+1)*sin/2-x2*cos);	/* lower barb */
312*7dd7cddfSDavid du Colombier 	pp->y = tip.y-(-(2*radius+2*x3+1)*cos/2+x2*sin);
313*7dd7cddfSDavid du Colombier 	pp++;
314*7dd7cddfSDavid du Colombier 	pp->x = tip.x+(-(2*radius+1)*sin/2-x1*cos);		/* lower side of shaft */
315*7dd7cddfSDavid du Colombier 	pp->y = tip.y+((2*radius+1)*cos/2-x1*sin);
316*7dd7cddfSDavid du Colombier }
317*7dd7cddfSDavid du Colombier 
318*7dd7cddfSDavid du Colombier void
319*7dd7cddfSDavid du Colombier _memimageline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, Rectangle clipr)
320*7dd7cddfSDavid du Colombier {
321*7dd7cddfSDavid du Colombier 	/*
322*7dd7cddfSDavid du Colombier 	 * BUG: We should really really pick off purely horizontal and purely
323*7dd7cddfSDavid du Colombier 	 * vertical lines and handle them separately with calls to memimagedraw
324*7dd7cddfSDavid du Colombier 	 * on rectangles.
325*7dd7cddfSDavid du Colombier 	 */
326*7dd7cddfSDavid du Colombier 
327*7dd7cddfSDavid du Colombier 	int hor;
328*7dd7cddfSDavid du Colombier 	int sin, cos, dx, dy, t;
329*7dd7cddfSDavid du Colombier 	Rectangle oclipr;
330*7dd7cddfSDavid du Colombier 	Point q, pts[10], *pp, d;
331*7dd7cddfSDavid du Colombier 
332*7dd7cddfSDavid du Colombier 	if(radius < 0)
333*7dd7cddfSDavid du Colombier 		return;
334*7dd7cddfSDavid du Colombier 	if(rectclip(&clipr, dst->r) == 0)
335*7dd7cddfSDavid du Colombier 		return;
336*7dd7cddfSDavid du Colombier 	if(rectclip(&clipr, dst->clipr) == 0)
337*7dd7cddfSDavid du Colombier 		return;
338*7dd7cddfSDavid du Colombier 	d = subpt(sp, p0);
339*7dd7cddfSDavid du Colombier 	if(rectclip(&clipr, rectsubpt(src->clipr, d)) == 0)
340*7dd7cddfSDavid du Colombier 		return;
341*7dd7cddfSDavid du Colombier 	if((src->flags&Frepl)==0 && rectclip(&clipr, rectsubpt(src->r, d))==0)
342*7dd7cddfSDavid du Colombier 		return;
343*7dd7cddfSDavid du Colombier 	/* this means that only verline() handles degenerate lines (p0==p1) */
344*7dd7cddfSDavid du Colombier 	hor = (abs(p1.x-p0.x) > abs(p1.y-p0.y));
345*7dd7cddfSDavid du Colombier 	/*
346*7dd7cddfSDavid du Colombier 	 * Clipping is a little peculiar.  We can't use Sutherland-Cohen
347*7dd7cddfSDavid du Colombier 	 * clipping because lines are wide.  But this is probably just fine:
348*7dd7cddfSDavid du Colombier 	 * we do all math with the original p0 and p1, but clip when deciding
349*7dd7cddfSDavid du Colombier 	 * what pixels to draw.  This means the layer code can call this routine,
350*7dd7cddfSDavid du Colombier 	 * using clipr to define the region being written, and get the same set
351*7dd7cddfSDavid du Colombier 	 * of pixels regardless of the dicing.
352*7dd7cddfSDavid du Colombier 	 */
353*7dd7cddfSDavid du Colombier 	if((hor && p0.x>p1.x) || (!hor && p0.y>p1.y)){
354*7dd7cddfSDavid du Colombier 		q = p0;
355*7dd7cddfSDavid du Colombier 		p0 = p1;
356*7dd7cddfSDavid du Colombier 		p1 = q;
357*7dd7cddfSDavid du Colombier 		t = end0;
358*7dd7cddfSDavid du Colombier 		end0 = end1;
359*7dd7cddfSDavid du Colombier 		end1 = t;
360*7dd7cddfSDavid du Colombier 	}
361*7dd7cddfSDavid du Colombier 
362*7dd7cddfSDavid du Colombier /*    Hard: */
363*7dd7cddfSDavid du Colombier 	/* draw thick line using polygon fill */
364*7dd7cddfSDavid du Colombier 	icossin2(p1.x-p0.x, p1.y-p0.y, &cos, &sin);
365*7dd7cddfSDavid du Colombier 	dx = (sin*(2*radius+1))/2;
366*7dd7cddfSDavid du Colombier 	dy = (cos*(2*radius+1))/2;
367*7dd7cddfSDavid du Colombier 	pp = pts;
368*7dd7cddfSDavid du Colombier 	oclipr = dst->clipr;
369*7dd7cddfSDavid du Colombier 	dst->clipr = clipr;
370*7dd7cddfSDavid du Colombier 	q.x = ICOSSCALE*p0.x+ICOSSCALE/2-cos/2;
371*7dd7cddfSDavid du Colombier 	q.y = ICOSSCALE*p0.y+ICOSSCALE/2-sin/2;
372*7dd7cddfSDavid du Colombier 	switch(end0 & 0x1F){
373*7dd7cddfSDavid du Colombier 	case Enddisc:
374*7dd7cddfSDavid du Colombier 		discend(p0, radius, dst, src, d);
375*7dd7cddfSDavid du Colombier 		/* fall through */
376*7dd7cddfSDavid du Colombier 	case Endsquare:
377*7dd7cddfSDavid du Colombier 	default:
378*7dd7cddfSDavid du Colombier 		pp->x = q.x-dx;
379*7dd7cddfSDavid du Colombier 		pp->y = q.y+dy;
380*7dd7cddfSDavid du Colombier 		pp++;
381*7dd7cddfSDavid du Colombier 		pp->x = q.x+dx;
382*7dd7cddfSDavid du Colombier 		pp->y = q.y-dy;
383*7dd7cddfSDavid du Colombier 		pp++;
384*7dd7cddfSDavid du Colombier 		break;
385*7dd7cddfSDavid du Colombier 	case Endarrow:
386*7dd7cddfSDavid du Colombier 		arrowend(q, pp, end0, -sin, -cos, radius);
387*7dd7cddfSDavid du Colombier 		memfillpolysc(dst, pts, 5, ~0, src, addpt(pts[0], mulpt(d, ICOSSCALE)), 1, 10, 1);
388*7dd7cddfSDavid du Colombier 		pp[1] = pp[4];
389*7dd7cddfSDavid du Colombier 		pp += 2;
390*7dd7cddfSDavid du Colombier 	}
391*7dd7cddfSDavid du Colombier 	q.x = ICOSSCALE*p1.x+ICOSSCALE/2+cos/2;
392*7dd7cddfSDavid du Colombier 	q.y = ICOSSCALE*p1.y+ICOSSCALE/2+sin/2;
393*7dd7cddfSDavid du Colombier 	switch(end1 & 0x1F){
394*7dd7cddfSDavid du Colombier 	case Enddisc:
395*7dd7cddfSDavid du Colombier 		discend(p1, radius, dst, src, d);
396*7dd7cddfSDavid du Colombier 		/* fall through */
397*7dd7cddfSDavid du Colombier 	case Endsquare:
398*7dd7cddfSDavid du Colombier 	default:
399*7dd7cddfSDavid du Colombier 		pp->x = q.x+dx;
400*7dd7cddfSDavid du Colombier 		pp->y = q.y-dy;
401*7dd7cddfSDavid du Colombier 		pp++;
402*7dd7cddfSDavid du Colombier 		pp->x = q.x-dx;
403*7dd7cddfSDavid du Colombier 		pp->y = q.y+dy;
404*7dd7cddfSDavid du Colombier 		pp++;
405*7dd7cddfSDavid du Colombier 		break;
406*7dd7cddfSDavid du Colombier 	case Endarrow:
407*7dd7cddfSDavid du Colombier 		arrowend(q, pp, end1, sin, cos, radius);
408*7dd7cddfSDavid du Colombier 		memfillpolysc(dst, pp, 5, ~0, src, addpt(pts[0], mulpt(d, ICOSSCALE)), 1, 10, 1);
409*7dd7cddfSDavid du Colombier 		pp[1] = pp[4];
410*7dd7cddfSDavid du Colombier 		pp += 2;
411*7dd7cddfSDavid du Colombier 	}
412*7dd7cddfSDavid du Colombier 	memfillpolysc(dst, pts, pp-pts, ~0, src, addpt(pts[0], mulpt(d, ICOSSCALE)), 0, 10, 1);
413*7dd7cddfSDavid du Colombier 	dst->clipr = oclipr;
414*7dd7cddfSDavid du Colombier 	return;
415*7dd7cddfSDavid du Colombier }
416*7dd7cddfSDavid du Colombier 
417*7dd7cddfSDavid du Colombier void
418*7dd7cddfSDavid du Colombier memimageline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp)
419*7dd7cddfSDavid du Colombier {
420*7dd7cddfSDavid du Colombier 	_memimageline(dst, p0, p1, end0, end1, radius, src, sp, dst->clipr);
421*7dd7cddfSDavid du Colombier }
422*7dd7cddfSDavid du Colombier 
423*7dd7cddfSDavid du Colombier /*
424*7dd7cddfSDavid du Colombier  * Simple-minded conservative code to compute bounding box of line.
425*7dd7cddfSDavid du Colombier  * Result is probably a little larger than it needs to be.
426*7dd7cddfSDavid du Colombier  */
427*7dd7cddfSDavid du Colombier static
428*7dd7cddfSDavid du Colombier void
429*7dd7cddfSDavid du Colombier addbbox(Rectangle *r, Point p)
430*7dd7cddfSDavid du Colombier {
431*7dd7cddfSDavid du Colombier 	if(r->min.x > p.x)
432*7dd7cddfSDavid du Colombier 		r->min.x = p.x;
433*7dd7cddfSDavid du Colombier 	if(r->min.y > p.y)
434*7dd7cddfSDavid du Colombier 		r->min.y = p.y;
435*7dd7cddfSDavid du Colombier 	if(r->max.x < p.x+1)
436*7dd7cddfSDavid du Colombier 		r->max.x = p.x+1;
437*7dd7cddfSDavid du Colombier 	if(r->max.y < p.y+1)
438*7dd7cddfSDavid du Colombier 		r->max.y = p.y+1;
439*7dd7cddfSDavid du Colombier }
440*7dd7cddfSDavid du Colombier 
441*7dd7cddfSDavid du Colombier int
442*7dd7cddfSDavid du Colombier memlineendsize(int end)
443*7dd7cddfSDavid du Colombier {
444*7dd7cddfSDavid du Colombier 	int x3;
445*7dd7cddfSDavid du Colombier 
446*7dd7cddfSDavid du Colombier 	if((end&0x3F) != Endarrow)
447*7dd7cddfSDavid du Colombier 		return 0;
448*7dd7cddfSDavid du Colombier 	if(end == Endarrow)
449*7dd7cddfSDavid du Colombier 		x3 = Arrow3;
450*7dd7cddfSDavid du Colombier 	else
451*7dd7cddfSDavid du Colombier 		x3 = (end>>23) & 0x1FF;
452*7dd7cddfSDavid du Colombier 	return x3;
453*7dd7cddfSDavid du Colombier }
454*7dd7cddfSDavid du Colombier 
455*7dd7cddfSDavid du Colombier Rectangle
456*7dd7cddfSDavid du Colombier memlinebbox(Point p0, Point p1, int end0, int end1, int radius)
457*7dd7cddfSDavid du Colombier {
458*7dd7cddfSDavid du Colombier 	Rectangle r, r1;
459*7dd7cddfSDavid du Colombier 	int extra;
460*7dd7cddfSDavid du Colombier 
461*7dd7cddfSDavid du Colombier 	r.min.x = 10000000;
462*7dd7cddfSDavid du Colombier 	r.min.y = 10000000;
463*7dd7cddfSDavid du Colombier 	r.max.x = -10000000;
464*7dd7cddfSDavid du Colombier 	r.max.y = -10000000;
465*7dd7cddfSDavid du Colombier 	extra = lmax(memlineendsize(end0), memlineendsize(end1));
466*7dd7cddfSDavid du Colombier 	r1 = insetrect(canonrect(Rpt(p0, p1)), -(radius+extra));
467*7dd7cddfSDavid du Colombier 	addbbox(&r, r1.min);
468*7dd7cddfSDavid du Colombier 	addbbox(&r, r1.max);
469*7dd7cddfSDavid du Colombier 	return r;
470*7dd7cddfSDavid du Colombier }
471