xref: /inferno-os/libdraw/bezier.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsyth #include "lib9.h"
2*37da2899SCharles.Forsyth #include "draw.h"
3*37da2899SCharles.Forsyth 
4*37da2899SCharles.Forsyth #define	PINC	32		/* realloc granularity */
5*37da2899SCharles.Forsyth 
6*37da2899SCharles.Forsyth typedef struct Plist Plist;
7*37da2899SCharles.Forsyth struct Plist
8*37da2899SCharles.Forsyth {
9*37da2899SCharles.Forsyth 	Point *p;
10*37da2899SCharles.Forsyth 	int np;			/* -1 if malloc/realloc failed */
11*37da2899SCharles.Forsyth };
12*37da2899SCharles.Forsyth 
13*37da2899SCharles.Forsyth static void
appendpt(Plist * l,Point p)14*37da2899SCharles.Forsyth appendpt(Plist *l, Point p)
15*37da2899SCharles.Forsyth {
16*37da2899SCharles.Forsyth 	if(l->np == -1)
17*37da2899SCharles.Forsyth 		return;
18*37da2899SCharles.Forsyth 	if(l->np == 0)
19*37da2899SCharles.Forsyth 		l->p = malloc(PINC*sizeof(Point));
20*37da2899SCharles.Forsyth 	else if(l->np%PINC == 0)
21*37da2899SCharles.Forsyth 		l->p = realloc(l->p, (l->np+PINC)*sizeof(Point));
22*37da2899SCharles.Forsyth 	if(l->p == 0){
23*37da2899SCharles.Forsyth 		l->np = -1;
24*37da2899SCharles.Forsyth 		return;
25*37da2899SCharles.Forsyth 	}
26*37da2899SCharles.Forsyth 	l->p[l->np++] = p;
27*37da2899SCharles.Forsyth }
28*37da2899SCharles.Forsyth 
29*37da2899SCharles.Forsyth static int
normsq(Point p)30*37da2899SCharles.Forsyth normsq(Point p)
31*37da2899SCharles.Forsyth {
32*37da2899SCharles.Forsyth 	return p.x*p.x+p.y*p.y;
33*37da2899SCharles.Forsyth }
34*37da2899SCharles.Forsyth 
35*37da2899SCharles.Forsyth static int
psdist(Point p,Point a,Point b)36*37da2899SCharles.Forsyth psdist(Point p, Point a, Point b)
37*37da2899SCharles.Forsyth {
38*37da2899SCharles.Forsyth 	int num, den;
39*37da2899SCharles.Forsyth 
40*37da2899SCharles.Forsyth 	p = subpt(p, a);
41*37da2899SCharles.Forsyth 	b = subpt(b, a);
42*37da2899SCharles.Forsyth 	num = p.x*b.x + p.y*b.y;
43*37da2899SCharles.Forsyth 	if(num <= 0)
44*37da2899SCharles.Forsyth 		return normsq(p);
45*37da2899SCharles.Forsyth 	den = normsq(b);
46*37da2899SCharles.Forsyth 	if(num >= den)
47*37da2899SCharles.Forsyth 		return normsq(subpt(b, p));
48*37da2899SCharles.Forsyth 	return normsq(subpt(divpt(mulpt(b, num), den), p));
49*37da2899SCharles.Forsyth }
50*37da2899SCharles.Forsyth 
51*37da2899SCharles.Forsyth /*
52*37da2899SCharles.Forsyth  * Convert cubic Bezier curve control points to polyline
53*37da2899SCharles.Forsyth  * vertices.  Leaves the last vertex off, so you can continue
54*37da2899SCharles.Forsyth  * with another curve.
55*37da2899SCharles.Forsyth  */
56*37da2899SCharles.Forsyth static void
bpts1(Plist * l,Point p0,Point p1,Point p2,Point p3,int scale)57*37da2899SCharles.Forsyth bpts1(Plist *l, Point p0, Point p1, Point p2, Point p3, int scale)
58*37da2899SCharles.Forsyth {
59*37da2899SCharles.Forsyth 	Point p01, p12, p23, p012, p123, p0123;
60*37da2899SCharles.Forsyth 	Point tp0, tp1, tp2, tp3;
61*37da2899SCharles.Forsyth 	tp0=divpt(p0, scale);
62*37da2899SCharles.Forsyth 	tp1=divpt(p1, scale);
63*37da2899SCharles.Forsyth 	tp2=divpt(p2, scale);
64*37da2899SCharles.Forsyth 	tp3=divpt(p3, scale);
65*37da2899SCharles.Forsyth 	if(psdist(tp1, tp0, tp3)<=1 && psdist(tp2, tp0, tp3)<=1){
66*37da2899SCharles.Forsyth 		appendpt(l, tp0);
67*37da2899SCharles.Forsyth 		appendpt(l, tp1);
68*37da2899SCharles.Forsyth 		appendpt(l, tp2);
69*37da2899SCharles.Forsyth 	}
70*37da2899SCharles.Forsyth 	else{
71*37da2899SCharles.Forsyth 		/*
72*37da2899SCharles.Forsyth 		 * if scale factor is getting too big for comfort,
73*37da2899SCharles.Forsyth 		 * rescale now & concede the rounding error
74*37da2899SCharles.Forsyth 		 */
75*37da2899SCharles.Forsyth 		if(scale>(1<<12)){
76*37da2899SCharles.Forsyth 			p0=tp0;
77*37da2899SCharles.Forsyth 			p1=tp1;
78*37da2899SCharles.Forsyth 			p2=tp2;
79*37da2899SCharles.Forsyth 			p3=tp3;
80*37da2899SCharles.Forsyth 			scale=1;
81*37da2899SCharles.Forsyth 		}
82*37da2899SCharles.Forsyth 		p01=addpt(p0, p1);
83*37da2899SCharles.Forsyth 		p12=addpt(p1, p2);
84*37da2899SCharles.Forsyth 		p23=addpt(p2, p3);
85*37da2899SCharles.Forsyth 		p012=addpt(p01, p12);
86*37da2899SCharles.Forsyth 		p123=addpt(p12, p23);
87*37da2899SCharles.Forsyth 		p0123=addpt(p012, p123);
88*37da2899SCharles.Forsyth 		bpts1(l, mulpt(p0, 8), mulpt(p01, 4), mulpt(p012, 2), p0123, scale*8);
89*37da2899SCharles.Forsyth 		bpts1(l, p0123, mulpt(p123, 2), mulpt(p23, 4), mulpt(p3, 8), scale*8);
90*37da2899SCharles.Forsyth 	}
91*37da2899SCharles.Forsyth }
92*37da2899SCharles.Forsyth 
93*37da2899SCharles.Forsyth static void
bpts(Plist * l,Point p0,Point p1,Point p2,Point p3)94*37da2899SCharles.Forsyth bpts(Plist *l, Point p0, Point p1, Point p2, Point p3)
95*37da2899SCharles.Forsyth {
96*37da2899SCharles.Forsyth 	bpts1(l, p0, p1, p2, p3, 1);
97*37da2899SCharles.Forsyth }
98*37da2899SCharles.Forsyth 
99*37da2899SCharles.Forsyth static void
bezierpts(Plist * l,Point p0,Point p1,Point p2,Point p3)100*37da2899SCharles.Forsyth bezierpts(Plist *l, Point p0, Point p1, Point p2, Point p3)
101*37da2899SCharles.Forsyth {
102*37da2899SCharles.Forsyth 	bpts(l, p0, p1, p2, p3);
103*37da2899SCharles.Forsyth 	appendpt(l, p3);
104*37da2899SCharles.Forsyth }
105*37da2899SCharles.Forsyth 
106*37da2899SCharles.Forsyth static void
bezsplinepts(Plist * l,Point * pt,int npt)107*37da2899SCharles.Forsyth bezsplinepts(Plist *l, Point *pt, int npt)
108*37da2899SCharles.Forsyth {
109*37da2899SCharles.Forsyth 	Point *p, *ep;
110*37da2899SCharles.Forsyth 	Point a, b, c, d;
111*37da2899SCharles.Forsyth 	int periodic;
112*37da2899SCharles.Forsyth 
113*37da2899SCharles.Forsyth 	if(npt<3)
114*37da2899SCharles.Forsyth 		return;
115*37da2899SCharles.Forsyth 	ep = &pt[npt-3];
116*37da2899SCharles.Forsyth 	periodic = eqpt(pt[0], ep[2]);
117*37da2899SCharles.Forsyth 	if(periodic){
118*37da2899SCharles.Forsyth 		a = divpt(addpt(ep[1], pt[0]), 2);
119*37da2899SCharles.Forsyth 		b = divpt(addpt(ep[1], mulpt(pt[0], 5)), 6);
120*37da2899SCharles.Forsyth 		c = divpt(addpt(mulpt(pt[0], 5), pt[1]), 6);
121*37da2899SCharles.Forsyth 		d = divpt(addpt(pt[0], pt[1]), 2);
122*37da2899SCharles.Forsyth 		bpts(l, a, b, c, d);
123*37da2899SCharles.Forsyth 	}
124*37da2899SCharles.Forsyth 	for(p=pt; p<=ep; p++){
125*37da2899SCharles.Forsyth 		if(p==pt && !periodic){
126*37da2899SCharles.Forsyth 			a = p[0];
127*37da2899SCharles.Forsyth 			b = divpt(addpt(p[0], mulpt(p[1], 2)), 3);
128*37da2899SCharles.Forsyth 		}
129*37da2899SCharles.Forsyth 		else{
130*37da2899SCharles.Forsyth 			a = divpt(addpt(p[0], p[1]), 2);
131*37da2899SCharles.Forsyth 			b = divpt(addpt(p[0], mulpt(p[1], 5)), 6);
132*37da2899SCharles.Forsyth 		}
133*37da2899SCharles.Forsyth 		if(p==ep && !periodic){
134*37da2899SCharles.Forsyth 			c = divpt(addpt(mulpt(p[1], 2), p[2]), 3);
135*37da2899SCharles.Forsyth 			d = p[2];
136*37da2899SCharles.Forsyth 		}
137*37da2899SCharles.Forsyth 		else{
138*37da2899SCharles.Forsyth 			c = divpt(addpt(mulpt(p[1], 5), p[2]), 6);
139*37da2899SCharles.Forsyth 			d = divpt(addpt(p[1], p[2]), 2);
140*37da2899SCharles.Forsyth 		}
141*37da2899SCharles.Forsyth 		bpts(l, a, b, c, d);
142*37da2899SCharles.Forsyth 	}
143*37da2899SCharles.Forsyth 	appendpt(l, d);
144*37da2899SCharles.Forsyth }
145*37da2899SCharles.Forsyth 
146*37da2899SCharles.Forsyth int
getbezsplinepts(Point * pt,int npt,Point ** pp)147*37da2899SCharles.Forsyth getbezsplinepts(Point *pt, int npt, Point **pp)
148*37da2899SCharles.Forsyth {
149*37da2899SCharles.Forsyth 	Plist l;
150*37da2899SCharles.Forsyth 	l.np = 0;
151*37da2899SCharles.Forsyth 	l.p = nil;
152*37da2899SCharles.Forsyth 	bezsplinepts(&l, pt, npt);
153*37da2899SCharles.Forsyth 	*pp  = l.p;
154*37da2899SCharles.Forsyth 	return l.np;
155*37da2899SCharles.Forsyth }
156*37da2899SCharles.Forsyth 
157*37da2899SCharles.Forsyth int
bezier(Image * dst,Point p0,Point p1,Point p2,Point p3,int end0,int end1,int radius,Image * src,Point sp)158*37da2899SCharles.Forsyth bezier(Image *dst, Point p0, Point p1, Point p2, Point p3, int end0, int end1, int radius, Image *src, Point sp)
159*37da2899SCharles.Forsyth {
160*37da2899SCharles.Forsyth 	return bezierop(dst, p0, p1, p2, p3, end0, end1, radius, src, sp, SoverD);
161*37da2899SCharles.Forsyth }
162*37da2899SCharles.Forsyth 
163*37da2899SCharles.Forsyth int
bezierop(Image * dst,Point p0,Point p1,Point p2,Point p3,int end0,int end1,int radius,Image * src,Point sp,Drawop op)164*37da2899SCharles.Forsyth bezierop(Image *dst, Point p0, Point p1, Point p2, Point p3, int end0, int end1, int radius, Image *src, Point sp, Drawop op)
165*37da2899SCharles.Forsyth {
166*37da2899SCharles.Forsyth 	Plist l;
167*37da2899SCharles.Forsyth 
168*37da2899SCharles.Forsyth 	l.np = 0;
169*37da2899SCharles.Forsyth 	bezierpts(&l, p0, p1, p2, p3);
170*37da2899SCharles.Forsyth 	if(l.np == -1)
171*37da2899SCharles.Forsyth 		return 0;
172*37da2899SCharles.Forsyth 	if(l.np != 0){
173*37da2899SCharles.Forsyth 		polyop(dst, l.p, l.np, end0, end1, radius, src, addpt(subpt(sp, p0), l.p[0]), op);
174*37da2899SCharles.Forsyth 		free(l.p);
175*37da2899SCharles.Forsyth 	}
176*37da2899SCharles.Forsyth 	return 1;
177*37da2899SCharles.Forsyth }
178*37da2899SCharles.Forsyth 
179*37da2899SCharles.Forsyth int
bezspline(Image * dst,Point * pt,int npt,int end0,int end1,int radius,Image * src,Point sp)180*37da2899SCharles.Forsyth bezspline(Image *dst, Point *pt, int npt, int end0, int end1, int radius, Image *src, Point sp)
181*37da2899SCharles.Forsyth {
182*37da2899SCharles.Forsyth 	return bezsplineop(dst, pt, npt, end0, end1, radius, src, sp, SoverD);
183*37da2899SCharles.Forsyth }
184*37da2899SCharles.Forsyth 
185*37da2899SCharles.Forsyth int
bezsplineop(Image * dst,Point * pt,int npt,int end0,int end1,int radius,Image * src,Point sp,Drawop op)186*37da2899SCharles.Forsyth bezsplineop(Image *dst, Point *pt, int npt, int end0, int end1, int radius, Image *src, Point sp, Drawop op)
187*37da2899SCharles.Forsyth {
188*37da2899SCharles.Forsyth 	Plist l;
189*37da2899SCharles.Forsyth 
190*37da2899SCharles.Forsyth 	l.np = 0;
191*37da2899SCharles.Forsyth 	bezsplinepts(&l, pt, npt);
192*37da2899SCharles.Forsyth 	if(l.np==-1)
193*37da2899SCharles.Forsyth 		return 0;
194*37da2899SCharles.Forsyth 	if(l.np != 0){
195*37da2899SCharles.Forsyth 		polyop(dst, l.p, l.np, end0, end1, radius, src, addpt(subpt(sp, pt[0]), l.p[0]), op);
196*37da2899SCharles.Forsyth 		free(l.p);
197*37da2899SCharles.Forsyth 	}
198*37da2899SCharles.Forsyth 	return 1;
199*37da2899SCharles.Forsyth }
200*37da2899SCharles.Forsyth 
201*37da2899SCharles.Forsyth int
fillbezier(Image * dst,Point p0,Point p1,Point p2,Point p3,int w,Image * src,Point sp)202*37da2899SCharles.Forsyth fillbezier(Image *dst, Point p0, Point p1, Point p2, Point p3, int w, Image *src, Point sp)
203*37da2899SCharles.Forsyth {
204*37da2899SCharles.Forsyth 	return fillbezierop(dst, p0, p1, p2, p3, w, src, sp, SoverD);
205*37da2899SCharles.Forsyth }
206*37da2899SCharles.Forsyth 
207*37da2899SCharles.Forsyth int
fillbezierop(Image * dst,Point p0,Point p1,Point p2,Point p3,int w,Image * src,Point sp,Drawop op)208*37da2899SCharles.Forsyth fillbezierop(Image *dst, Point p0, Point p1, Point p2, Point p3, int w, Image *src, Point sp, Drawop op)
209*37da2899SCharles.Forsyth {
210*37da2899SCharles.Forsyth 	Plist l;
211*37da2899SCharles.Forsyth 
212*37da2899SCharles.Forsyth 	l.np = 0;
213*37da2899SCharles.Forsyth 	bezierpts(&l, p0, p1, p2, p3);
214*37da2899SCharles.Forsyth 	if(l.np == -1)
215*37da2899SCharles.Forsyth 		return 0;
216*37da2899SCharles.Forsyth 	if(l.np != 0){
217*37da2899SCharles.Forsyth 		fillpolyop(dst, l.p, l.np, w, src, addpt(subpt(sp, p0), l.p[0]), op);
218*37da2899SCharles.Forsyth 		free(l.p);
219*37da2899SCharles.Forsyth 	}
220*37da2899SCharles.Forsyth 	return 1;
221*37da2899SCharles.Forsyth }
222*37da2899SCharles.Forsyth 
223*37da2899SCharles.Forsyth int
fillbezspline(Image * dst,Point * pt,int npt,int w,Image * src,Point sp)224*37da2899SCharles.Forsyth fillbezspline(Image *dst, Point *pt, int npt, int w, Image *src, Point sp)
225*37da2899SCharles.Forsyth {
226*37da2899SCharles.Forsyth 	return fillbezsplineop(dst, pt, npt, w, src, sp, SoverD);
227*37da2899SCharles.Forsyth }
228*37da2899SCharles.Forsyth 
229*37da2899SCharles.Forsyth int
fillbezsplineop(Image * dst,Point * pt,int npt,int w,Image * src,Point sp,Drawop op)230*37da2899SCharles.Forsyth fillbezsplineop(Image *dst, Point *pt, int npt, int w, Image *src, Point sp, Drawop op)
231*37da2899SCharles.Forsyth {
232*37da2899SCharles.Forsyth 	Plist l;
233*37da2899SCharles.Forsyth 
234*37da2899SCharles.Forsyth 	l.np = 0;
235*37da2899SCharles.Forsyth 	bezsplinepts(&l, pt, npt);
236*37da2899SCharles.Forsyth 	if(l.np == -1)
237*37da2899SCharles.Forsyth 		return 0;
238*37da2899SCharles.Forsyth 	if(l.np > 0){
239*37da2899SCharles.Forsyth 		fillpolyop(dst, l.p, l.np, w, src, addpt(subpt(sp, pt[0]), l.p[0]), op);
240*37da2899SCharles.Forsyth 		free(l.p);
241*37da2899SCharles.Forsyth 	}
242*37da2899SCharles.Forsyth 	return 1;
243*37da2899SCharles.Forsyth }
244