X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fgfxtools.c;h=cd08a42a5a1d825b01687cd37cfd0106b60ae87d;hb=d320fe6202257cc281bbd0f3e45895b3bc4f2ef9;hp=6fdc4985547c17cfd3cdaae9c4e69848c2e35ef6;hpb=50edd3bb0093193fc1a861acbd8ccc055fc120c0;p=swftools.git diff --git a/lib/gfxtools.c b/lib/gfxtools.c index 6fdc498..cd08a42 100644 --- a/lib/gfxtools.c +++ b/lib/gfxtools.c @@ -20,6 +20,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include #include @@ -36,6 +37,12 @@ static void linedraw_moveTo(gfxdrawer_t*d, gfxcoord_t x, gfxcoord_t y) linedraw_internal_t*i = (linedraw_internal_t*)d->internal; gfxline_t*l = rfx_alloc(sizeof(gfxline_t)); l->type = gfx_moveTo; + if((int)((d->x * 5120) == (int)(x * 5120)) && + (int)((d->y * 5120) == (int)(y * 5120))) { + /* never mind- we're already there */ + return; + + } d->x = l->x = x; d->y = l->y = y; l->next = 0; @@ -140,106 +147,165 @@ static void spline_get_controlpoint(qspline_abc_t*q, double t1, double t2, doubl static double get_spline_len(qspline_abc_t*s) { - //int parts = (int)(sqrt(abs(l2->x-2*l2->sx+x) + abs(l2->y-2*l2->sy+y)/3)); + int parts = (int)(sqrt(fabs(s->ax) + fabs(s->ay))*3); int i; double len = 0; - for(i=0;i<128;i++) + double r; + double r2; + if(parts < 3) parts = 3; + r = 1.0/parts; + r2 = 1.0/(parts*parts); + for(i=0;iax*t + s->bx; - double dy = 2*s->ay*t + s->by; + double dx = s->ax*(2*i+1)*r2 + s->bx*r; + double dy = s->ay*(2*i+1)*r2 + s->by*r; len += sqrt(dx*dx+dy*dy); } - return len / 128; + /*printf("Spline from %f,%f to %f,%f has len %f (%f)\n", s->cx, s->cy, + s->cx + s->bx + s->ax, + s->cy + s->by + s->ay, len, + sqrt((s->bx + s->ax)*(s->bx + s->ax) + (s->by + s->ay)*(s->by + s->ay)) + ); + assert(len+0.5 >= sqrt((s->bx + s->ax)*(s->bx + s->ax) + (s->by + s->ay)*(s->by + s->ay))); + */ + return len; } -void gfxtool_draw_dashed_line(gfxdrawer_t*d, gfxline_t*line, float*r) +void gfxtool_draw_dashed_line(gfxdrawer_t*d, gfxline_t*line, float*r, float phase) { double x=0,y=0; - int apos = 0; - double linepos = 0; - double nextpos = 0; - char on = 1; + double linepos,nextpos; + char on; + int apos; + + if(line && line->type != gfx_moveTo) { + fprintf(stderr, "gfxtool: outline doesn't start with a moveTo"); + return; + } + if(!r || r[0]<0 || phase<0) { + fprintf(stderr, "gfxtool: invalid dashes"); + return; + } + for(;line;line=line->next) { if(line->type == gfx_moveTo) { d->moveTo(d, line->x, line->y); - apos = 0; nextpos = 0; on = 1; linepos = 0; + on = 1; nextpos = r[0]; apos = 0; linepos = 0; x = line->x; y = line->y; + while(linepos < phase) { + //printf("[+] linepos: %f, phase: %f, on:%d, apos:%d nextpos:%f\n", linepos, phase, on, apos, nextpos); + linepos += r[apos]; + if(linepos < phase) { + on ^= 1; + if(r[++apos]<0) + apos = 0; + nextpos += r[apos]; + } + } + linepos = phase; + //printf("[k] linepos: %f, phase: %f, on:%d, apos:%d nextpos:%f \n", linepos, phase, on, apos, nextpos); } else if(line->type == gfx_lineTo) { double dx = line->x - x; double dy = line->y - y; double len = sqrt(dx*dx+dy*dy); + double vx; + double vy; + double lineend = linepos+len; if(len==0) continue; - double vx = dx/len; - double vy = dy/len; - double lineend = linepos+len; + vx = dx/len; + vy = dy/len; assert(nextpos>=linepos); - //printf("nextpos: %f, line end: %f\n", nextpos, linepos+len); + //printf("(line) on:%d apos: %d nextpos: %f, line pos: %f, line end: %f\n", on, apos, nextpos, linepos, linepos+len); while(nextposlineTo(d, nx,ny); - else d->moveTo(d, nx,ny); + if(on) {d->lineTo(d, nx,ny);/*printf("lineTo %f\n", nextpos);*/} + else {d->moveTo(d, nx,ny);/*printf("moveTo %f\n", nextpos);*/} on^=1; + if(r[++apos]<0) + apos = 0; nextpos+=r[apos]; - apos++; - if(r[apos]==0) - apos = 1; } linepos = lineend; if(on) { + //printf("lineTo %f\n", 1.0); d->lineTo(d, line->x,line->y); } x = line->x; y = line->y; } else if(line->type == gfx_splineTo) { qspline_abc_t q; + double len, lineend,lastt; mkspline(&q, x, y, line); - double len = get_spline_len(&q); + len = get_spline_len(&q); //printf("%f %f -> %f %f, len: %f\n", x, y, line->x, line->y, len); if(len==0) continue; - double lineend = linepos+len; - double lastt = 0; + lineend = linepos+len; + lastt = 0; if(nextpos=linepos); + //printf("(spline) on:%d apos: %d nextpos: %f, line pos: %f, line end: %f\n", on, apos, nextpos, linepos, linepos+len); while(nextpossplineTo(d, sx, sy, nx,ny); + //printf("splineTo %f\n", nextpos); } else { d->moveTo(d, nx,ny); + //printf("moveTo %f\n", nextpos); } lastt = t; on^=1; + if(r[++apos]<0) + apos = 0; nextpos+=r[apos]; - apos++; - if(r[apos]==0) - apos = 1; } linepos = lineend; if(on) { double sx,sy; spline_get_controlpoint(&q, lastt, 1, &sx, &sy); d->splineTo(d, sx, sy, line->x,line->y); + //printf("splineTo %f\n", 1.0); } x = line->x; y = line->y; } } } -gfxline_t* gfxtool_dash_line(gfxline_t*line, float*dashes) +gfxline_t * gfxline_clone(gfxline_t*line) +{ + gfxline_t*dest = 0; + gfxline_t*pos = 0; + while(line) { + gfxline_t*n = rfx_calloc(sizeof(gfxline_t)); + *n = *line; + n->next = 0; + if(!pos) { + dest = pos = n; + } else { + pos->next = n; + pos = n; + } + line = line->next; + } + return dest; +} + +gfxline_t* gfxtool_dash_line(gfxline_t*line, float*dashes, float phase) { gfxdrawer_t d; + gfxline_t*result; gfxdrawer_target_gfxline(&d); - gfxtool_draw_dashed_line(&d, line, dashes); - gfxline_t*result= (gfxline_t*)d.result(&d); + gfxtool_draw_dashed_line(&d, line, dashes, phase); + result= (gfxline_t*)d.result(&d); return result; } @@ -265,7 +331,7 @@ void gfxline_free(gfxline_t*l) while(l) { next = l->next; l->next = 0; - free(l); + rfx_free(l); l = next; } } @@ -345,7 +411,7 @@ static int approximate3(const cspline_t*s, qspline_t*q, int size, double quality test.control.y += test.end.y; } -#define PROBES +//#define PROBES #ifdef PROBES /* measure the spline's accurancy, by taking a number of probes */ for(t=0;tend.x - s->control2.x*3 + s->control1.x*3 - s->start.x; dy= s->end.y - s->control2.y*3 + s->control1.y*3 - s->start.y; + /* we need to do this for the subspline between [start,end], not [0,1] + as a transformation of t->a*t+b does nothing to highest coefficient + of the spline except multiply it with a^3, we just need to modify + d here. */ + {double m = end-start; + dx*=m*m*m; + dy*=m*m*m; + } + /* use the integral over (f(x)-g(x))^2 between 0 and 1 to measure the approximation quality. - (it boils down to const*d^2) - */ + (it boils down to const*d^2) */ recurse = (dx*dx + dy*dy > quality2); #endif @@ -407,11 +478,21 @@ static int approximate3(const cspline_t*s, qspline_t*q, int size, double quality return num; } -void gfxdraw_cubicTo(gfxdrawer_t*draw, double c1x, double c1y, double c2x, double c2y, double x, double y) +void gfxdraw_conicTo(gfxdrawer_t*draw, double cx, double cy, double tox, double toy, double quality) +{ + double c1x = (draw->x + 2 * cx) / 3; + double c1y = (draw->y + 2 * cy) / 3; + double c2x = (2 * cx + tox) / 3; + double c2y = (2 * cy + toy) / 3; + gfxdraw_cubicTo(draw, c1x, c1y, c2x, c2y, tox, toy, quality); +} + + +void gfxdraw_cubicTo(gfxdrawer_t*draw, double c1x, double c1y, double c2x, double c2y, double x, double y, double quality) { qspline_t q[128]; cspline_t c; - double maxerror = 0.04; + double maxerror = quality>0 ? quality : 1.0; int t,num; c.start.x = draw->x; @@ -423,11 +504,11 @@ void gfxdraw_cubicTo(gfxdrawer_t*draw, double c1x, double c1y, double c2x, doubl c.end.x = x; c.end.y = y; - num = approximate3(&c, q, 128, maxerror*maxerror); + num = approximate3(&c, q, 128, maxerror); for(t=0;tx; - y = line->x; + y = line->y; line = line->next; } return bbox; } +void gfxline_dump(gfxline_t*line, FILE*fi, char*prefix) +{ + while(line) { + if(line->type == gfx_moveTo) { + fprintf(fi, "%smoveTo %.2f %.2f\n", prefix, line->x, line->y); + } else if(line->type == gfx_lineTo) { + fprintf(fi, "%slineTo %.2f %.2f\n", prefix, line->x, line->y); + } else if(line->type == gfx_splineTo) { + fprintf(fi, "%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix, line->sx, line->sy, line->x, line->y); + } + line = line->next; + } +} + +gfxline_t* gfxline_append(gfxline_t*line1, gfxline_t*line2) +{ + gfxline_t*l = line1;; + if(!l) + return line2; + while(l->next) { + l = l->next; + } + l->next = line2; + return line1; +} + +void gfxline_transform(gfxline_t*line, gfxmatrix_t*matrix) +{ + while(line) { + double x = matrix->m00*line->x + matrix->m10*line->y + matrix->tx; + double y = matrix->m01*line->x + matrix->m11*line->y + matrix->ty; + line->x = x; + line->y = y; + if(line->type == gfx_splineTo) { + double sx = matrix->m00*line->sx + matrix->m10*line->sy + matrix->tx; + double sy = matrix->m01*line->sx + matrix->m11*line->sy + matrix->ty; + line->sx = sx; + line->sy = sy; + } + line = line->next; + } +} + +void gfxmatrix_dump(gfxmatrix_t*m, FILE*fi, char*prefix) +{ + fprintf(fi, "%f %f | %f\n", m->m00, m->m10, m->tx); + fprintf(fi, "%f %f | %f\n", m->m01, m->m11, m->ty); +}