X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fgfxtools.c;h=56007761c6c31efcc7688d8b984dfb1e91447340;hb=6c3ab5574d31504d24710c2756899d49275c1a37;hp=e0750595bc52921c71cf813c931ceec06b349ba4;hpb=9d1556507170bc827fca8ebbaa27862c978c6c33;p=swftools.git diff --git a/lib/gfxtools.c b/lib/gfxtools.c index e075059..5600776 100644 --- a/lib/gfxtools.c +++ b/lib/gfxtools.c @@ -21,10 +21,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include +#include #include #include +#include #include #include "gfxtools.h" +#include "gfxfont.h" typedef struct _linedraw_internal { @@ -35,8 +38,15 @@ typedef struct _linedraw_internal 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)); + gfxline_t*l = (gfxline_t*)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; + + } + l->sx = l->sy = 0; d->x = l->x = x; d->y = l->y = y; l->next = 0; @@ -49,10 +59,18 @@ static void linedraw_moveTo(gfxdrawer_t*d, gfxcoord_t x, gfxcoord_t y) static void linedraw_lineTo(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)); + gfxline_t*l = (gfxline_t*)rfx_alloc(sizeof(gfxline_t)); + + if(!i->start) { + /* starts with a line, not with a moveto. That needs we first + need an explicit moveto to (0,0) */ + linedraw_moveTo(d, 0, 0); + } + l->type = gfx_lineTo; d->x = l->x = x; d->y = l->y = y; + l->next = 0; if(i->next) i->next->next = l; @@ -63,7 +81,14 @@ static void linedraw_lineTo(gfxdrawer_t*d, gfxcoord_t x, gfxcoord_t y) static void linedraw_splineTo(gfxdrawer_t*d, gfxcoord_t sx, gfxcoord_t sy, gfxcoord_t x, gfxcoord_t y) { linedraw_internal_t*i = (linedraw_internal_t*)d->internal; - gfxline_t*l = rfx_alloc(sizeof(gfxline_t)); + gfxline_t*l = (gfxline_t*)rfx_alloc(sizeof(gfxline_t)); + + if(!i->start) { + /* starts with a line, not with a moveto. That needs we first + need an explicit moveto to (0,0) */ + linedraw_moveTo(d, 0, 0); + } + l->type = gfx_splineTo; d->x = l->x = x; d->y = l->y = y; @@ -88,6 +113,8 @@ static void* linedraw_result(gfxdrawer_t*d) void gfxdrawer_target_gfxline(gfxdrawer_t*d) { linedraw_internal_t*i = (linedraw_internal_t*)rfx_calloc(sizeof(linedraw_internal_t)); + d->x = 0x7fffffff; + d->y = 0x7fffffff; d->internal = i; d->moveTo = linedraw_moveTo; d->lineTo = linedraw_lineTo; @@ -274,6 +301,76 @@ void gfxtool_draw_dashed_line(gfxdrawer_t*d, gfxline_t*line, float*r, float phas } } +gfxline_t * gfxline_clone(gfxline_t*line) +{ + gfxline_t*dest = 0; + gfxline_t*pos = 0; + while(line) { + gfxline_t*n = (gfxline_t*)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; +} +void gfxline_optimize(gfxline_t*line) +{ + gfxline_t*l = line; + /* step 1: convert splines to lines, where possible */ + double x=0,y=0; + while(l) { + if(l->type == gfx_splineTo) { + double dx = l->x-x; + double dy = l->y-y; + double sx = l->sx-x; + double sy = l->sy-y; + if(fabs(dx*sy - dy*sx) < 0.000001 && (dx*sx + dy*sy) >= 0) { + l->type = gfx_lineTo; + } + } + x = l->x; + y = l->y; + l = l->next; + } + /* step 2: combine adjacent lines and splines, where possible */ + l = line; + while(l && l->next) { + gfxline_t*next = l->next; + char combine = 0; + double sx=0,sy=0; + if(l->type == gfx_lineTo && next->type == gfx_lineTo) { + double dx = l->x-x; + double dy = l->y-y; + double nx = next->x-l->x; + double ny = next->y-l->y; + if(fabs(dx*ny - dy*nx) < 0.000001 && (dx*nx + dy*ny) >= 0) { + combine = 1; + } + } else if(l->type == gfx_splineTo && next->type == gfx_splineTo) { + /* TODO */ + } + if(combine) { + l->next = next->next; + next->next = 0; + l->x = next->x; + l->y = next->y; + l->sx = sx; + l->sy = sy; + rfx_free(next); + } else { + x = l->x; + y = l->y; + l = l->next; + } + } +} + gfxline_t* gfxtool_dash_line(gfxline_t*line, float*dashes, float phase) { gfxdrawer_t d; @@ -287,13 +384,13 @@ gfxline_t* gfxtool_dash_line(gfxline_t*line, float*dashes, float phase) void gfxline_show(gfxline_t*l, FILE*fi) { while(l) { - if(l->type == moveTo) { + if(l->type == gfx_moveTo) { fprintf(fi, "moveTo %.2f,%.2f\n", l->x, l->y); } - if(l->type == lineTo) { + if(l->type == gfx_lineTo) { fprintf(fi, "lineTo %.2f,%.2f\n", l->x, l->y); } - if(l->type == splineTo) { + if(l->type == gfx_splineTo) { fprintf(fi, "splineTo %.2f,%.2f %.2f,%.2f\n", l->sx, l->sy, l->x, l->y); } l = l->next; @@ -302,12 +399,17 @@ void gfxline_show(gfxline_t*l, FILE*fi) void gfxline_free(gfxline_t*l) { - gfxline_t*next; - while(l) { - next = l->next; - l->next = 0; + if(l && (l+1) == l->next) { + /* flattened */ rfx_free(l); - l = next; + } else { + gfxline_t*next; + while(l) { + next = l->next; + l->next = 0; + rfx_free(l); + l = next; + } } } @@ -386,7 +488,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 @@ -448,11 +555,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; @@ -464,11 +581,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) +void gfxline_dump(gfxline_t*line, FILE*fi, char*prefix) { while(line) { if(line->type == gfx_moveTo) { - fprintf(fi, "moveTo %.2f %.2f\n", line->x, line->y); + fprintf(fi, "%smoveTo %.2f %.2f\n", prefix, line->x, line->y); } else if(line->type == gfx_lineTo) { - fprintf(fi, "lineTo %.2f %.2f\n", line->x, line->y); + fprintf(fi, "%slineTo %.2f %.2f\n", prefix, line->x, line->y); } else if(line->type == gfx_splineTo) { - fprintf(fi, "splineTo (%.2f %.2f) %.2f %.2f\n", line->sx, line->sy, line->x, line->y); + 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); +} + +void gfxmatrix_transform(gfxmatrix_t*m, double* v, double*dest) +{ + dest[0] = m->m00*v[0] + m->m10*v[1] + m->tx; + dest[1] = m->m01*v[0] + m->m11*v[1] + m->ty; +} +void gfxmatrix_invert(gfxmatrix_t*m, gfxmatrix_t*dest) +{ + double det = m->m00 * m->m11 - m->m10 * m->m01; + if(!det) { + memset(dest, 0, sizeof(gfxmatrix_t)); + return; + } + det = 1/det; + dest->m00 = m->m11 * det; + dest->m01 = -m->m01 * det; + dest->m10 = -m->m10 * det; + dest->m11 = m->m00 * det; + dest->tx = -(dest->m00 * m->tx + dest->m10 * m->ty); + dest->ty = -(dest->m01 * m->tx + dest->m11 * m->ty); +} +void gfxmatrix_unit(gfxmatrix_t*m) +{ + memset(m, 0, sizeof(gfxmatrix_t)); + m->m00 = 1.0; + m->m11 = 1.0; +} +void gfxmatrix_multiply(gfxmatrix_t*m1, gfxmatrix_t*m2, gfxmatrix_t*dest) +{ + dest->m00 = m1->m00*m2->m00 + m1->m10*m2->m01; + dest->m01 = m1->m01*m2->m00 + m1->m11*m2->m01; + dest->m10 = m1->m00*m2->m10 + m1->m10*m2->m11; + dest->m11 = m1->m01*m2->m10 + m1->m11*m2->m11; + dest->tx = m1->m00*m2->tx + m1->m10*m2->ty + m1->tx; + dest->ty = m1->m01*m2->tx + m1->m11*m2->ty + m1->ty; +} + +gfxfontlist_t* gfxfontlist_create() +{ + /* Initial list ist empty */ + return 0; +} + +gfxfont_t*gfxfontlist_findfont(gfxfontlist_t*list, char*id) +{ + gfxfontlist_t*l = list; + while(l) { + if(!strcmp((char*)l->font->id, id)) { + return l->font; + } + l = l->next; + } + return 0; +} +char gfxfontlist_hasfont(gfxfontlist_t*list, gfxfont_t*font) +{ + gfxfontlist_t*l = list; + while(l) { + if(!strcmp((char*)l->font->id, font->id)) { + return 1; + } + l = l->next; + } + return 0; +} +gfxfontlist_t*gfxfontlist_addfont(gfxfontlist_t*list, gfxfont_t*font) +{ + gfxfontlist_t*last=0,*l = list; + while(l) { + last = l; + if(!strcmp((char*)l->font->id, font->id)) { + return list; // we already know this font + } + l = l->next; + } + if(!font) { + fprintf(stderr, "Tried to add zero font\n"); + } + l = (gfxfontlist_t*)rfx_calloc(sizeof(gfxfontlist_t)); + l->font = font; + l->next = 0; + if(last) { + last->next = l; + return list; + } else { + return l; + } +} +void gfxfontlist_free(gfxfontlist_t*list, char deletefonts) +{ + gfxfontlist_t*l = list; + while(l) { + gfxfontlist_t*next = l->next; + if(l->font) { + gfxfont_free(l->font);l->font; + } + l->next = 0; + free(l); + l = next; + } +} + +gfxline_t*gfxline_makerectangle(int x1,int y1,int x2, int y2) +{ + gfxline_t* line = (gfxline_t*)rfx_calloc(sizeof(gfxline_t)*5); + line[0].x = x1;line[0].y = y1;line[0].type = gfx_moveTo;line[0].next = &line[1]; + line[1].x = x2;line[1].y = y1;line[1].type = gfx_lineTo;line[1].next = &line[2]; + line[2].x = x2;line[2].y = y2;line[2].type = gfx_lineTo;line[2].next = &line[3]; + line[3].x = x1;line[3].y = y2;line[3].type = gfx_lineTo;line[3].next = &line[4]; + line[4].x = x1;line[4].y = y1;line[4].type = gfx_lineTo; + return line; +} + +void gfximage_transform(gfximage_t*img, gfxcxform_t*cxform) +{ + int t; + int size = img->width*img->height; + + int rr,rg,rb,ra, tr; + int gr,gg,gb,ga, tg; + int br,bg,bb,ba, tb; + int ar,ag,ab,aa, ta; + rr = (int)(cxform->rr*256);gr = (int)(cxform->gr*256); + rg = (int)(cxform->rg*256);gg = (int)(cxform->gg*256); + rb = (int)(cxform->rb*256);gb = (int)(cxform->gb*256); + ra = (int)(cxform->ra*256);ga = (int)(cxform->ga*256); + br = (int)(cxform->br*256);ar = (int)(cxform->ar*256);tr = (int)(cxform->tr*256); + bg = (int)(cxform->bg*256);ag = (int)(cxform->ag*256);tg = (int)(cxform->tg*256); + bb = (int)(cxform->bb*256);ab = (int)(cxform->ab*256);tb = (int)(cxform->tb*256); + ba = (int)(cxform->ba*256);aa = (int)(cxform->aa*256);ta = (int)(cxform->ta*256); + + for(t=0;tdata[t]; + unsigned char r = (pixel->r * rr + pixel->g * rg + pixel->b * rb + pixel->a * ra + tr) / 256; + unsigned char g = (pixel->r * gr + pixel->g * gg + pixel->b * gb + pixel->a * ga + tg) / 256; + unsigned char b = (pixel->r * br + pixel->g * bg + pixel->b * bb + pixel->a * ba + tb) / 256; + unsigned char a = (pixel->r * ar + pixel->g * ag + pixel->b * ab + pixel->a * aa + ta) / 256; + pixel->r = r; + pixel->g = g; + pixel->b = b; + pixel->a = a; + } +}