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