small speed improvements
[swftools.git] / lib / gfxpoly / convert.c
1 #include <stdlib.h>
2 #include <math.h>
3 #include <string.h>
4 #include "../gfxdevice.h"
5 #include "../mem.h"
6 #include "poly.h"
7
8 /* factor that determines into how many line fragments a spline is converted */
9 #define SUBFRACTION (2.4)
10
11 static edge_t*edge_new(int x1, int y1, int x2, int y2)
12 {
13     edge_t*s = rfx_calloc(sizeof(edge_t));
14     s->a.x = x1;
15     s->a.y = y1;
16     s->b.x = x2;
17     s->b.y = y2;
18     return s;
19 }
20
21 static inline void gfxpoly_add_edge(gfxpoly_t*poly, double _x1, double _y1, double _x2, double _y2)
22 {
23     int x1 = ceil(_x1);
24     int y1 = ceil(_y1);
25     int x2 = ceil(_x2);
26     int y2 = ceil(_y2);
27
28     if(x1!=x2 || y1!=y2) {
29         edge_t*s = edge_new(x1, y1, x2, y2);
30         s->next = poly->edges;
31         poly->edges = s;
32     }
33 }
34
35 gfxpoly_t* gfxpoly_from_gfxline(gfxline_t*line, double gridsize)
36 {
37     gfxpoly_t*p = gfxpoly_new(gridsize);
38
39     double z = 1.0 / gridsize;
40
41     double lastx=0, lasty=0;
42     assert(!line || line[0].type == gfx_moveTo);
43     while(line) {
44         double x = line->x*z;
45         double y = line->y*z;
46         if(line->type == gfx_moveTo) {
47         } else if(line->type == gfx_lineTo) {
48             gfxpoly_add_edge(p, lastx, lasty, x, y);
49         } else if(line->type == gfx_splineTo) {
50             int parts = (int)(sqrt(fabs(line->x-2*line->sx+lastx) + 
51                                    fabs(line->y-2*line->sy+lasty))*SUBFRACTION);
52             if(!parts) parts = 1;
53             double stepsize = 1.0/parts;
54             int i;
55             for(i=0;i<parts;i++) {
56                 double t = (double)i*stepsize;
57                 double sx = (line->x*t*t + 2*line->sx*t*(1-t) + x*(1-t)*(1-t))*z;
58                 double sy = (line->y*t*t + 2*line->sy*t*(1-t) + y*(1-t)*(1-t))*z;
59                 gfxpoly_add_edge(p, lastx, lasty, sx, sy);
60                 lastx = sx;
61                 lasty = sy;
62             }
63             gfxpoly_add_edge(p, lastx, lasty, x, y);
64         }
65         lastx = x;
66         lasty = y;
67         line = line->next;
68     }
69     
70     gfxline_free(line);
71     return p;
72 }
73
74 typedef struct _gfxstroke {
75     segment_dir_t dir;
76     point_t*stroke;
77     fillstyle_t*fs;
78     int num_points;
79 } gfxstroke_t;
80 typedef struct _gfxcompactpoly {
81     double gridsize;
82     int num_strokes;
83     gfxstroke_t strokes[0];
84 } gfxcompactpoly_t;
85
86 static char* readline(FILE*fi)
87 {
88     char c;
89     while(1) {
90         int l = fread(&c, 1, 1, fi);
91         if(!l)
92             return 0;
93         if(c!=10 || c!=13)
94             break;
95     }
96     char line[256];
97     int pos = 0;
98     while(1) {
99         line[pos++] = c;
100         line[pos] = 0;
101         int l = fread(&c, 1, 1, fi);
102         if(!l || c==10 || c==13) {
103             return strdup(line);
104         }
105     }
106 }
107
108 gfxpoly_t* gfxpoly_from_file(const char*filename, double gridsize)
109 {
110     gfxpoly_t*p = gfxpoly_new(gridsize);
111
112     double z = 1.0 / gridsize;
113
114     FILE*fi = fopen(filename, "rb");
115     if(!fi) {
116         perror(filename);
117         return 0;
118     }
119     int count = 0;
120     double g = 0;
121     double lastx=0,lasty=0;
122     while(1) {
123         char*line = readline(fi);
124         if(!line)
125             break;
126         double x,y;
127         char s[256];
128         if(sscanf(line, "%lf %lf %s", &x, &y, &s) == 3) {
129             x*=z;
130             y*=z;
131             if(s && !strcmp(s,"moveto")) {
132                 count++;
133             } else if(s && !strcmp(s,"lineto")) {
134                 gfxpoly_add_edge(p, lastx, lasty, x, y);
135                 count++;
136             } else {
137                 printf("invalid command: %s\n", s);
138             }
139             lastx = x;
140             lasty = y;
141         } else if(sscanf(line, "%% gridsize %lf", &g) == 1) {
142             p->gridsize = g;
143         }
144         free(line);
145     }
146     fclose(fi);
147     if(g) {
148         printf("loaded %d points from %s (gridsize %f)\n", count, filename, g);
149     } else {
150         printf("loaded %d points from %s\n", count, filename);
151     }
152     return p;
153 }