|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <draw.h> | 
|  |  | 
|  | #define	PINC	32		/* realloc granularity */ | 
|  |  | 
|  | typedef struct Plist Plist; | 
|  | struct Plist | 
|  | { | 
|  | Point *p; | 
|  | int np;			/* -1 if malloc/realloc failed */ | 
|  | }; | 
|  |  | 
|  | static void | 
|  | appendpt(Plist *l, Point p) | 
|  | { | 
|  | if(l->np == -1) | 
|  | return; | 
|  | if(l->np == 0) | 
|  | l->p = malloc(PINC*sizeof(Point)); | 
|  | else if(l->np%PINC == 0) | 
|  | l->p = realloc(l->p, (l->np+PINC)*sizeof(Point)); | 
|  | if(l->p == 0){ | 
|  | l->np = -1; | 
|  | return; | 
|  | } | 
|  | l->p[l->np++] = p; | 
|  | } | 
|  |  | 
|  | static int | 
|  | normsq(Point p) | 
|  | { | 
|  | return p.x*p.x+p.y*p.y; | 
|  | } | 
|  |  | 
|  | static int | 
|  | psdist(Point p, Point a, Point b) | 
|  | { | 
|  | int num, den; | 
|  |  | 
|  | p = subpt(p, a); | 
|  | b = subpt(b, a); | 
|  | num = p.x*b.x + p.y*b.y; | 
|  | if(num <= 0) | 
|  | return normsq(p); | 
|  | den = normsq(b); | 
|  | if(num >= den) | 
|  | return normsq(subpt(b, p)); | 
|  | return normsq(subpt(divpt(mulpt(b, num), den), p)); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Convert cubic Bezier curve control points to polyline | 
|  | * vertices.  Leaves the last vertex off, so you can continue | 
|  | * with another curve. | 
|  | */ | 
|  | static void | 
|  | bpts1(Plist *l, Point p0, Point p1, Point p2, Point p3, int scale) | 
|  | { | 
|  | Point p01, p12, p23, p012, p123, p0123; | 
|  | Point tp0, tp1, tp2, tp3; | 
|  | tp0=divpt(p0, scale); | 
|  | tp1=divpt(p1, scale); | 
|  | tp2=divpt(p2, scale); | 
|  | tp3=divpt(p3, scale); | 
|  | if(psdist(tp1, tp0, tp3)<=1 && psdist(tp2, tp0, tp3)<=1){ | 
|  | appendpt(l, tp0); | 
|  | appendpt(l, tp1); | 
|  | appendpt(l, tp2); | 
|  | } | 
|  | else{ | 
|  | /* | 
|  | * if scale factor is getting too big for comfort, | 
|  | * rescale now & concede the rounding error | 
|  | */ | 
|  | if(scale>(1<<12)){ | 
|  | p0=tp0; | 
|  | p1=tp1; | 
|  | p2=tp2; | 
|  | p3=tp3; | 
|  | scale=1; | 
|  | } | 
|  | p01=addpt(p0, p1); | 
|  | p12=addpt(p1, p2); | 
|  | p23=addpt(p2, p3); | 
|  | p012=addpt(p01, p12); | 
|  | p123=addpt(p12, p23); | 
|  | p0123=addpt(p012, p123); | 
|  | bpts1(l, mulpt(p0, 8), mulpt(p01, 4), mulpt(p012, 2), p0123, scale*8); | 
|  | bpts1(l, p0123, mulpt(p123, 2), mulpt(p23, 4), mulpt(p3, 8), scale*8); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | bpts(Plist *l, Point p0, Point p1, Point p2, Point p3) | 
|  | { | 
|  | bpts1(l, p0, p1, p2, p3, 1); | 
|  | } | 
|  |  | 
|  | static void | 
|  | bezierpts(Plist *l, Point p0, Point p1, Point p2, Point p3) | 
|  | { | 
|  | bpts(l, p0, p1, p2, p3); | 
|  | appendpt(l, p3); | 
|  | } | 
|  |  | 
|  | static void | 
|  | _bezsplinepts(Plist *l, Point *pt, int npt) | 
|  | { | 
|  | Point *p, *ep; | 
|  | Point a, b, c, d; | 
|  | int periodic; | 
|  |  | 
|  | if(npt<3) | 
|  | return; | 
|  | ep = &pt[npt-3]; | 
|  | periodic = eqpt(pt[0], ep[2]); | 
|  | if(periodic){ | 
|  | a = divpt(addpt(ep[1], pt[0]), 2); | 
|  | b = divpt(addpt(ep[1], mulpt(pt[0], 5)), 6); | 
|  | c = divpt(addpt(mulpt(pt[0], 5), pt[1]), 6); | 
|  | d = divpt(addpt(pt[0], pt[1]), 2); | 
|  | bpts(l, a, b, c, d); | 
|  | } | 
|  | for(p=pt; p<=ep; p++){ | 
|  | if(p==pt && !periodic){ | 
|  | a = p[0]; | 
|  | b = divpt(addpt(p[0], mulpt(p[1], 2)), 3); | 
|  | } | 
|  | else{ | 
|  | a = divpt(addpt(p[0], p[1]), 2); | 
|  | b = divpt(addpt(p[0], mulpt(p[1], 5)), 6); | 
|  | } | 
|  | if(p==ep && !periodic){ | 
|  | c = divpt(addpt(mulpt(p[1], 2), p[2]), 3); | 
|  | d = p[2]; | 
|  | } | 
|  | else{ | 
|  | c = divpt(addpt(mulpt(p[1], 5), p[2]), 6); | 
|  | d = divpt(addpt(p[1], p[2]), 2); | 
|  | } | 
|  | bpts(l, a, b, c, d); | 
|  | } | 
|  | appendpt(l, d); | 
|  | } | 
|  |  | 
|  | int | 
|  | bezsplinepts(Point *pt, int npt, Point **pp) | 
|  | { | 
|  | Plist l; | 
|  | l.np = 0; | 
|  | l.p = nil; | 
|  | _bezsplinepts(&l, pt, npt); | 
|  | *pp  = l.p; | 
|  | return l.np; | 
|  | } | 
|  |  | 
|  | int | 
|  | bezier(Image *dst, Point p0, Point p1, Point p2, Point p3, int end0, int end1, int radius, Image *src, Point sp) | 
|  | { | 
|  | return bezierop(dst, p0, p1, p2, p3, end0, end1, radius, src, sp, SoverD); | 
|  | } | 
|  |  | 
|  | int | 
|  | bezierop(Image *dst, Point p0, Point p1, Point p2, Point p3, int end0, int end1, int radius, Image *src, Point sp, Drawop op) | 
|  | { | 
|  | Plist l; | 
|  |  | 
|  | l.np = 0; | 
|  | bezierpts(&l, p0, p1, p2, p3); | 
|  | if(l.np == -1) | 
|  | return 0; | 
|  | if(l.np != 0){ | 
|  | polyop(dst, l.p, l.np, end0, end1, radius, src, addpt(subpt(sp, p0), l.p[0]), op); | 
|  | free(l.p); | 
|  | } | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | int | 
|  | bezspline(Image *dst, Point *pt, int npt, int end0, int end1, int radius, Image *src, Point sp) | 
|  | { | 
|  | return bezsplineop(dst, pt, npt, end0, end1, radius, src, sp, SoverD); | 
|  | } | 
|  |  | 
|  | int | 
|  | bezsplineop(Image *dst, Point *pt, int npt, int end0, int end1, int radius, Image *src, Point sp, Drawop op) | 
|  | { | 
|  | Plist l; | 
|  |  | 
|  | l.np = 0; | 
|  | _bezsplinepts(&l, pt, npt); | 
|  | if(l.np==-1) | 
|  | return 0; | 
|  | if(l.np != 0){ | 
|  | polyop(dst, l.p, l.np, end0, end1, radius, src, addpt(subpt(sp, pt[0]), l.p[0]), op); | 
|  | free(l.p); | 
|  | } | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | int | 
|  | fillbezier(Image *dst, Point p0, Point p1, Point p2, Point p3, int w, Image *src, Point sp) | 
|  | { | 
|  | return fillbezierop(dst, p0, p1, p2, p3, w, src, sp, SoverD); | 
|  | } | 
|  |  | 
|  | int | 
|  | fillbezierop(Image *dst, Point p0, Point p1, Point p2, Point p3, int w, Image *src, Point sp, Drawop op) | 
|  | { | 
|  | Plist l; | 
|  |  | 
|  | l.np = 0; | 
|  | bezierpts(&l, p0, p1, p2, p3); | 
|  | if(l.np == -1) | 
|  | return 0; | 
|  | if(l.np != 0){ | 
|  | fillpolyop(dst, l.p, l.np, w, src, addpt(subpt(sp, p0), l.p[0]), op); | 
|  | free(l.p); | 
|  | } | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | int | 
|  | fillbezspline(Image *dst, Point *pt, int npt, int w, Image *src, Point sp) | 
|  | { | 
|  | return fillbezsplineop(dst, pt, npt, w, src, sp, SoverD); | 
|  | } | 
|  |  | 
|  | int | 
|  | fillbezsplineop(Image *dst, Point *pt, int npt, int w, Image *src, Point sp, Drawop op) | 
|  | { | 
|  | Plist l; | 
|  |  | 
|  | l.np = 0; | 
|  | _bezsplinepts(&l, pt, npt); | 
|  | if(l.np == -1) | 
|  | return 0; | 
|  | if(l.np > 0){ | 
|  | fillpolyop(dst, l.p, l.np, w, src, addpt(subpt(sp, pt[0]), l.p[0]), op); | 
|  | free(l.p); | 
|  | } | 
|  | return 1; | 
|  | } |