xref: /inferno-os/libmemdraw/arc.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsyth #include "lib9.h"
2*37da2899SCharles.Forsyth #include "draw.h"
3*37da2899SCharles.Forsyth #include "memdraw.h"
4*37da2899SCharles.Forsyth #include "memlayer.h"
5*37da2899SCharles.Forsyth 
6*37da2899SCharles.Forsyth /*
7*37da2899SCharles.Forsyth  * elarc(dst,c,a,b,t,src,sp,alpha,phi)
8*37da2899SCharles.Forsyth  *   draws the part of an ellipse between rays at angles alpha and alpha+phi
9*37da2899SCharles.Forsyth  *   measured counterclockwise from the positive x axis. other
10*37da2899SCharles.Forsyth  *   arguments are as for ellipse(dst,c,a,b,t,src,sp)
11*37da2899SCharles.Forsyth  */
12*37da2899SCharles.Forsyth 
13*37da2899SCharles.Forsyth enum
14*37da2899SCharles.Forsyth {
15*37da2899SCharles.Forsyth 	R, T, L, B	/* right, top, left, bottom */
16*37da2899SCharles.Forsyth };
17*37da2899SCharles.Forsyth 
18*37da2899SCharles.Forsyth static
19*37da2899SCharles.Forsyth Point corners[] = {
20*37da2899SCharles.Forsyth 	{1,1},
21*37da2899SCharles.Forsyth 	{-1,1},
22*37da2899SCharles.Forsyth 	{-1,-1},
23*37da2899SCharles.Forsyth 	{1,-1}
24*37da2899SCharles.Forsyth };
25*37da2899SCharles.Forsyth 
26*37da2899SCharles.Forsyth static
27*37da2899SCharles.Forsyth Point p00;
28*37da2899SCharles.Forsyth 
29*37da2899SCharles.Forsyth /*
30*37da2899SCharles.Forsyth  * make a "wedge" mask covering the desired angle and contained in
31*37da2899SCharles.Forsyth  * a surrounding square; draw a full ellipse; intersect that with the
32*37da2899SCharles.Forsyth  * wedge to make a mask through which to copy src to dst.
33*37da2899SCharles.Forsyth  */
34*37da2899SCharles.Forsyth void
memarc(Memimage * dst,Point c,int a,int b,int t,Memimage * src,Point sp,int alpha,int phi,int op)35*37da2899SCharles.Forsyth memarc(Memimage *dst, Point c, int a, int b, int t, Memimage *src, Point sp, int alpha, int phi, int op)
36*37da2899SCharles.Forsyth {
37*37da2899SCharles.Forsyth 	int i, w, beta, tmp, c1, c2, m, m1;
38*37da2899SCharles.Forsyth 	Rectangle rect;
39*37da2899SCharles.Forsyth 	Point p,	bnd[8];
40*37da2899SCharles.Forsyth 	Memimage *wedge, *figure, *mask;
41*37da2899SCharles.Forsyth 
42*37da2899SCharles.Forsyth 	if(a < 0)
43*37da2899SCharles.Forsyth 		a = -a;
44*37da2899SCharles.Forsyth 	if(b < 0)
45*37da2899SCharles.Forsyth 		b = -b;
46*37da2899SCharles.Forsyth 	w = t;
47*37da2899SCharles.Forsyth 	if(w < 0)
48*37da2899SCharles.Forsyth 		w = 0;
49*37da2899SCharles.Forsyth 	alpha = -alpha;		/* compensate for upside-down coords */
50*37da2899SCharles.Forsyth 	phi = -phi;
51*37da2899SCharles.Forsyth 	beta = alpha + phi;
52*37da2899SCharles.Forsyth 	if(phi < 0){
53*37da2899SCharles.Forsyth 		tmp = alpha;
54*37da2899SCharles.Forsyth 		alpha = beta;
55*37da2899SCharles.Forsyth 		beta = tmp;
56*37da2899SCharles.Forsyth 		phi = -phi;
57*37da2899SCharles.Forsyth 	}
58*37da2899SCharles.Forsyth 	if(phi >= 360){
59*37da2899SCharles.Forsyth 		memellipse(dst, c, a, b, t, src, sp, op);
60*37da2899SCharles.Forsyth 		return;
61*37da2899SCharles.Forsyth 	}
62*37da2899SCharles.Forsyth 	while(alpha < 0)
63*37da2899SCharles.Forsyth 		alpha += 360;
64*37da2899SCharles.Forsyth 	while(beta < 0)
65*37da2899SCharles.Forsyth 		beta += 360;
66*37da2899SCharles.Forsyth 	c1 = alpha/90 & 3;	/* number of nearest corner */
67*37da2899SCharles.Forsyth 	c2 = beta/90 & 3;
68*37da2899SCharles.Forsyth 		/*
69*37da2899SCharles.Forsyth 		 * icossin returns point at radius ICOSSCALE.
70*37da2899SCharles.Forsyth 		 * multiplying by m1 moves it outside the ellipse
71*37da2899SCharles.Forsyth 		*/
72*37da2899SCharles.Forsyth 	rect = Rect(-a-w, -b-w, a+w+1, b+w+1);
73*37da2899SCharles.Forsyth 	m = rect.max.x;	/* inradius of bounding square */
74*37da2899SCharles.Forsyth 	if(m < rect.max.y)
75*37da2899SCharles.Forsyth 		m = rect.max.y;
76*37da2899SCharles.Forsyth 	m1 = (m+ICOSSCALE-1) >> 10;
77*37da2899SCharles.Forsyth 	m = m1 << 10;		/* assure m1*cossin is inside */
78*37da2899SCharles.Forsyth 	i = 0;
79*37da2899SCharles.Forsyth 	bnd[i++] = Pt(0,0);
80*37da2899SCharles.Forsyth 	icossin(alpha, &p.x, &p.y);
81*37da2899SCharles.Forsyth 	bnd[i++] = mulpt(p, m1);
82*37da2899SCharles.Forsyth 	for(;;) {
83*37da2899SCharles.Forsyth 		bnd[i++] = mulpt(corners[c1], m);
84*37da2899SCharles.Forsyth 		if(c1==c2 && phi<180)
85*37da2899SCharles.Forsyth 			break;
86*37da2899SCharles.Forsyth 		c1 = (c1+1) & 3;
87*37da2899SCharles.Forsyth 		phi -= 90;
88*37da2899SCharles.Forsyth 	}
89*37da2899SCharles.Forsyth 	icossin(beta, &p.x, &p.y);
90*37da2899SCharles.Forsyth 	bnd[i++] = mulpt(p, m1);
91*37da2899SCharles.Forsyth 
92*37da2899SCharles.Forsyth 	figure = nil;
93*37da2899SCharles.Forsyth 	mask = nil;
94*37da2899SCharles.Forsyth 	wedge = allocmemimage(rect, GREY1);
95*37da2899SCharles.Forsyth 	if(wedge == nil)
96*37da2899SCharles.Forsyth 		goto Return;
97*37da2899SCharles.Forsyth 	memfillcolor(wedge, DTransparent);
98*37da2899SCharles.Forsyth 	memfillpoly(wedge, bnd, i, ~0, memopaque, p00, S);
99*37da2899SCharles.Forsyth 	figure = allocmemimage(rect, GREY1);
100*37da2899SCharles.Forsyth 	if(figure == nil)
101*37da2899SCharles.Forsyth 		goto Return;
102*37da2899SCharles.Forsyth 	memfillcolor(figure, DTransparent);
103*37da2899SCharles.Forsyth 	memellipse(figure, p00, a, b, t, memopaque, p00, S);
104*37da2899SCharles.Forsyth 	mask = allocmemimage(rect, GREY1);
105*37da2899SCharles.Forsyth 	if(mask == nil)
106*37da2899SCharles.Forsyth 		goto Return;
107*37da2899SCharles.Forsyth 	memfillcolor(mask, DTransparent);
108*37da2899SCharles.Forsyth 	memimagedraw(mask, rect, figure, rect.min, wedge, rect.min, S);
109*37da2899SCharles.Forsyth 	c = subpt(c, dst->r.min);
110*37da2899SCharles.Forsyth 	memdraw(dst, dst->r, src, subpt(sp, c), mask, subpt(p00, c), op);
111*37da2899SCharles.Forsyth 
112*37da2899SCharles.Forsyth     Return:
113*37da2899SCharles.Forsyth 	freememimage(wedge);
114*37da2899SCharles.Forsyth 	freememimage(figure);
115*37da2899SCharles.Forsyth 	freememimage(mask);
116*37da2899SCharles.Forsyth }
117