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