40aa255a786bd76efa19aab900b886899cf49c8e
[swftools.git] / lib / modules / swfdraw.c
1 // swfdraw.c
2
3 typedef struct _SWFSHAPEDRAWER
4 {
5     SHAPE*shape;
6     TAG*tag;
7     int tagfree;
8     SCOORD firstx;
9     SCOORD firsty;
10     SCOORD lastx;
11     SCOORD lasty;
12     SRECT bbox;
13     char isfinished;
14 } SWFSHAPEDRAWER;
15
16 static void swf_ShapeDrawerSetLineStyle(drawer_t*draw, void*style);
17 static void swf_ShapeDrawerSetFillStyle(drawer_t*draw, void*style);
18 static void swf_ShapeDrawerMoveTo(drawer_t*draw, FPOINT * to);
19 static void swf_ShapeDrawerLineTo(drawer_t*draw, FPOINT * to);
20 static void swf_ShapeDrawerSplineTo(drawer_t*draw, FPOINT * c1, FPOINT*  to);
21 static void swf_ShapeDrawerFinish(drawer_t*draw);
22 static void swf_ShapeDrawerClear(drawer_t*draw);
23
24 static void swf_ShapeDrawerInit(drawer_t*draw, TAG*tag, int fillstylebits, int linestylebits)
25 {
26     SWFSHAPEDRAWER*sdraw = rfx_calloc(sizeof(SWFSHAPEDRAWER));
27     draw->internal = sdraw;
28
29     draw->setLineStyle = swf_ShapeDrawerSetLineStyle;
30     draw->setFillStyle = swf_ShapeDrawerSetFillStyle;
31     draw->moveTo = swf_ShapeDrawerMoveTo;
32     draw->lineTo = swf_ShapeDrawerLineTo;
33     draw->splineTo = swf_ShapeDrawerSplineTo;
34     draw->finish = swf_ShapeDrawerFinish;
35     draw->dealloc = swf_ShapeDrawerClear;
36     
37     sdraw->tagfree = 0;
38     if(tag == 0) {
39         tag = swf_InsertTag(0, ST_DEFINESHAPE);
40         sdraw->tagfree = 1;
41     }
42     sdraw->tag = tag;
43     swf_ShapeNew(&sdraw->shape);
44     draw->pos.x = 0;
45     draw->pos.y = 0;
46
47     swf_SetU8(sdraw->tag,0);
48     sdraw->shape->bits.fill = fillstylebits;
49     sdraw->shape->bits.line = linestylebits;
50     
51     sdraw->bbox.xmin = sdraw->bbox.ymin = SCOORD_MAX;
52     sdraw->bbox.xmax = sdraw->bbox.ymax = SCOORD_MIN;
53
54     sdraw->isfinished = 0;
55
56     swf_ShapeSetStyle(sdraw->tag,sdraw->shape,linestylebits?1:0,fillstylebits?1:0,0/*?*/);
57 }
58
59 void swf_Shape10DrawerInit(drawer_t*draw, TAG*tag)
60 {
61     swf_ShapeDrawerInit(draw, tag, 0, 1);
62 }
63
64 void swf_Shape01DrawerInit(drawer_t*draw, TAG*tag)
65 {
66     swf_ShapeDrawerInit(draw, tag, 1, 0);
67 }
68
69 void swf_Shape11DrawerInit(drawer_t*draw, TAG*tag)
70 {
71     swf_ShapeDrawerInit(draw, tag, 1, 1);
72 }
73
74 static void swf_ShapeDrawerSetLineStyle(drawer_t*draw, void*style)
75 {
76     SWFSHAPEDRAWER*sdraw = (SWFSHAPEDRAWER*)draw->internal;
77 }
78 static void swf_ShapeDrawerSetFillStyle(drawer_t*draw, void*style)
79 {
80     SWFSHAPEDRAWER*sdraw = (SWFSHAPEDRAWER*)draw->internal;
81 }
82 static void fixEndPoint(drawer_t*draw)
83 {
84     SWFSHAPEDRAWER*sdraw = (SWFSHAPEDRAWER*)draw->internal;
85     if(   sdraw->firstx != sdraw->lastx 
86        || sdraw->firsty != sdraw->lasty) {
87         /* fix non-closing shapes */
88         FPOINT to;
89         to.x = sdraw->firstx/20.0;
90         to.y = sdraw->firsty/20.0;
91         if(sdraw->shape->bits.fill) // do this only if the shape is filled
92             draw->lineTo(draw, &to);
93     }
94 }
95 static void swf_ShapeDrawerMoveTo(drawer_t*draw, FPOINT * to)
96 {
97     SWFSHAPEDRAWER*sdraw = (SWFSHAPEDRAWER*)draw->internal;
98     int x = to->x*20+0.001;
99     int y = to->y*20+0.001;
100
101     /* we need to write moveto always- it
102        might be that it signals the end of a polygon, otherwise
103        we would end up connecting two polygons which should
104        be seperate 
105         TODO: check if the last operation was a moveTo- if
106               yes we *can* skip it.
107      */
108
109     //if(sdraw->lastx != x || sdraw->lasty != y) {
110         fixEndPoint(draw);
111         swf_ShapeSetMove(sdraw->tag,sdraw->shape,x,y);
112         sdraw->firstx = sdraw->lastx = x;
113         sdraw->firsty = sdraw->lasty = y;
114         draw->pos = *to;
115     //}
116 }
117 static void swf_ShapeDrawerLineTo(drawer_t*draw, FPOINT * to)
118 {
119     SWFSHAPEDRAWER*sdraw = (SWFSHAPEDRAWER*)draw->internal;
120     int x = to->x*20+0.001;
121     int y = to->y*20+0.001;
122     if(sdraw->lastx < sdraw->bbox.xmin) sdraw->bbox.xmin = sdraw->lastx;
123     if(sdraw->lasty < sdraw->bbox.ymin) sdraw->bbox.ymin = sdraw->lasty;
124     if(sdraw->lastx > sdraw->bbox.xmax) sdraw->bbox.xmax = sdraw->lastx;
125     if(sdraw->lasty > sdraw->bbox.ymax) sdraw->bbox.ymax = sdraw->lasty;
126     if(x < sdraw->bbox.xmin) sdraw->bbox.xmin = x;
127     if(y < sdraw->bbox.ymin) sdraw->bbox.ymin = y;
128     if(x > sdraw->bbox.xmax) sdraw->bbox.xmax = x;
129     if(y > sdraw->bbox.ymax) sdraw->bbox.ymax = y;
130     swf_ShapeSetLine(sdraw->tag,sdraw->shape,x-sdraw->lastx,y-sdraw->lasty);
131     sdraw->lastx = x;
132     sdraw->lasty = y;
133     draw->pos = *to;
134 }
135 static void swf_ShapeDrawerSplineTo(drawer_t*draw, FPOINT * c1, FPOINT*  to)
136 {
137     SWFSHAPEDRAWER*sdraw = (SWFSHAPEDRAWER*)draw->internal;
138     int tx = c1->x*20+0.001;
139     int ty = c1->y*20+0.001;
140     int x = to->x*20+0.001;
141     int y = to->y*20+0.001;
142     if(sdraw->lastx < sdraw->bbox.xmin) sdraw->bbox.xmin = sdraw->lastx;
143     if(sdraw->lasty < sdraw->bbox.ymin) sdraw->bbox.ymin = sdraw->lasty;
144     if(sdraw->lastx > sdraw->bbox.xmax) sdraw->bbox.xmax = sdraw->lastx;
145     if(sdraw->lasty > sdraw->bbox.ymax) sdraw->bbox.ymax = sdraw->lasty;
146     if(x < sdraw->bbox.xmin) sdraw->bbox.xmin = x;
147     if(y < sdraw->bbox.ymin) sdraw->bbox.ymin = y;
148     if(x > sdraw->bbox.xmax) sdraw->bbox.xmax = x;
149     if(y > sdraw->bbox.ymax) sdraw->bbox.ymax = y;
150     if(tx < sdraw->bbox.xmin) sdraw->bbox.xmin = tx;
151     if(ty < sdraw->bbox.ymin) sdraw->bbox.ymin = ty;
152     if(tx > sdraw->bbox.xmax) sdraw->bbox.xmax = tx;
153     if(ty > sdraw->bbox.ymax) sdraw->bbox.ymax = ty;
154     swf_ShapeSetCurve(sdraw->tag,sdraw->shape, tx-sdraw->lastx,ty-sdraw->lasty, x-tx,y-ty);
155     sdraw->lastx = x;
156     sdraw->lasty = y;
157     draw->pos = *to;
158 }
159 static void swf_ShapeDrawerFinish(drawer_t*draw)
160 {
161     SWFSHAPEDRAWER*sdraw = (SWFSHAPEDRAWER*)draw->internal;
162     if(sdraw->isfinished)
163         return;
164         
165     fixEndPoint(draw);
166
167     if(sdraw->bbox.xmin == SCOORD_MAX) {
168         /* no points at all -> empty bounding box */
169         sdraw->bbox.xmin = sdraw->bbox.ymin = 
170         sdraw->bbox.xmax = sdraw->bbox.ymax = 0;
171     }
172     sdraw->isfinished = 1;
173     swf_ShapeSetEnd(sdraw->tag);
174 }
175
176 static void swf_ShapeDrawerClear(drawer_t*draw)
177 {
178     SWFSHAPEDRAWER*sdraw = (SWFSHAPEDRAWER*)draw->internal;
179     if(sdraw->tagfree) {
180         swf_DeleteTag(sdraw->tag);
181         sdraw->tag = 0;
182     }
183     swf_ShapeFree(sdraw->shape);
184     sdraw->shape = 0;
185
186     rfx_free(draw->internal);
187     draw->internal = 0;
188 }
189
190 SRECT swf_ShapeDrawerGetBBox(drawer_t*draw)
191 {
192     SWFSHAPEDRAWER*sdraw = (SWFSHAPEDRAWER*)draw->internal;
193     return sdraw->bbox;
194 }
195
196 SHAPE* swf_ShapeDrawerToShape(drawer_t*draw)
197 {
198     SWFSHAPEDRAWER*sdraw = (SWFSHAPEDRAWER*)draw->internal;
199     SHAPE* shape = rfx_alloc(sizeof(SHAPE));
200     if(!sdraw->isfinished) {
201         fprintf(stderr, "Warning: you should Finish() your drawer before calling DrawerToShape");
202         swf_ShapeDrawerFinish(draw);
203     }
204     memcpy(shape, sdraw->shape, sizeof(SHAPE));
205     shape->bitlen = (sdraw->tag->len-1)*8;
206     shape->data = (U8*)rfx_alloc(sdraw->tag->len-1);
207     memcpy(shape->data, &sdraw->tag->data[1], sdraw->tag->len-1);
208     return shape;
209 }