lines which are too long are now split.
[swftools.git] / lib / modules / swfshape.c
1 /* swfshape.c
2
3    shape functions
4       
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2001 Rainer Böhme <rfxswf@reflex-studio.de>
9  
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
23
24 #define SF_MOVETO       0x01
25 #define SF_FILL0        0x02
26 #define SF_FILL1        0x04
27 #define SF_LINE         0x08
28 #define SF_NEWSTYLE     0x10
29
30 #define FILL_SOLID      0x00
31 #define FILL_LINEAR     0x10  // Gradient
32 #define FILL_RADIAL     0x12
33 #define FILL_TILED      0x40  // Bitmap
34 #define FILL_CLIPPED    0x41
35
36 void swf_ShapeFree(SHAPE * s)
37 { if (s)
38   { if (s->linestyle.data) free(s->linestyle.data);
39     s->linestyle.data = NULL;
40     s->linestyle.n    = 0;
41     if (s->fillstyle.data) free(s->fillstyle.data);
42     s->fillstyle.data = NULL;
43     s->fillstyle.n    = 0;
44     if (s->data) free(s->data);
45     s->data = NULL;
46   }
47   free(s);
48 }
49
50 int swf_ShapeNew(SHAPE * * s)
51 { SHAPE * sh;
52   if (!s) return -1;
53   sh = (SHAPE *)malloc(sizeof(SHAPE)); s[0] = sh;
54   if (sh) memset(sh,0x00,sizeof(SHAPE));
55   return sh?0:-1;
56 }
57
58 int swf_GetSimpleShape(TAG * t,SHAPE * * s) // without Linestyle/Fillstyle Record
59 { SHAPE * sh;
60   int bitl, len;
61   int end;
62   U32 pos;
63   
64   if (FAILED(swf_ShapeNew(s))) return -1;
65   sh = s[0];
66
67   swf_ResetReadBits(t); 
68   sh->bits.fill = (U16)swf_GetBits(t,4);
69   sh->bits.line = (U16)swf_GetBits(t,4);
70   bitl = 0; end = 0; pos = swf_GetTagPos(t);
71
72   while (!end)
73   { int edge = swf_GetBits(t,1); bitl+=1;
74     if (edge)
75     { bitl+=1;
76       if (swf_GetBits(t,1))                 // Line
77       { U16 nbits = swf_GetBits(t,4)+2;
78         bitl+=5;
79
80         if (swf_GetBits(t,1))               // x/y Line
81         { swf_GetBits(t,nbits);
82           swf_GetBits(t,nbits);
83           bitl+=nbits*2;
84         }
85         else                            // hline/vline
86         { swf_GetBits(t,nbits+1);
87           bitl+=nbits+1;
88         }
89       }
90       else                              // Curve
91       { U16 nbits = swf_GetBits(t,4)+2;
92         bitl+=4;
93
94         swf_GetBits(t,nbits);
95         swf_GetBits(t,nbits);
96         swf_GetBits(t,nbits);
97         swf_GetBits(t,nbits);
98
99         bitl+=4*nbits;
100       }
101     }
102     else
103     { U16 flags = swf_GetBits(t,5); bitl+=5;
104       if (flags)
105       {
106         if (flags&SF_MOVETO)
107         { U16 nbits = swf_GetBits(t,5); bitl+=5;
108           swf_GetBits(t,nbits);
109           swf_GetBits(t,nbits);
110           bitl+=2*nbits;
111         }
112         
113         if (flags&SF_FILL0)
114         { swf_GetBits(t,sh->bits.fill);
115           bitl+=sh->bits.fill;
116         }
117         
118         if (flags&SF_FILL1)
119         { swf_GetBits(t,sh->bits.fill);
120           bitl+=sh->bits.fill;
121         }
122
123         if (flags&SF_LINE)
124         { swf_GetBits(t,sh->bits.line);
125           bitl+=sh->bits.line;
126         }
127
128         if (flags&SF_NEWSTYLE)
129         { fprintf(stderr,"RFXSWF: Can't process extended styles in shape.\n");
130         }
131       }
132       else end = 1;
133     }
134   }
135   swf_SetTagPos(t,pos);
136   len = (bitl+7)/8;
137   
138   if (sh->data) free(sh->data);
139   sh->data = (U8*)malloc(len);
140   
141   if (sh->data)
142   { sh->bitlen = bitl;
143     swf_GetBlock(t,sh->data,len);
144   }
145   else return -1;
146   
147   return len;
148 }
149
150 int swf_SetSimpleShape(TAG * t,SHAPE * s) // without Linestyle/Fillstyle Record
151 { int l;
152
153   if (!s) return -1;
154   l = (s->bitlen+7)/8;
155
156   if (t)
157   { swf_ResetWriteBits(t);
158
159     swf_SetBits(t,s->bits.fill,4);
160     swf_SetBits(t,s->bits.line,4);
161     swf_SetBlock(t,s->data,l);
162
163     swf_ResetWriteBits(t);
164   }
165   return l+1;
166 }
167
168 int swf_SetFillStyle(TAG * t,FILLSTYLE * f)
169 { if ((!t)||(!f)) return -1;
170   swf_SetU8(t,f->type);
171   
172   // no gradients yet!
173   
174   switch (f->type)
175   { case FILL_SOLID:
176       if (swf_GetTagID(t)!=ST_DEFINESHAPE3) swf_SetRGB(t,&f->color);
177       else swf_SetRGBA(t,&f->color);
178       break;
179
180     case FILL_TILED:
181     case FILL_CLIPPED:
182       swf_SetU16(t,f->id_bitmap);
183       swf_SetMatrix(t,&f->m);
184       break;
185     case FILL_LINEAR:
186     case FILL_RADIAL:
187       swf_SetMatrix(t,&f->m);
188       swf_SetGradient(t,&f->gradient,/*alpha?*/t->id==ST_DEFINESHAPE3?1:0);
189       break;
190   }
191   
192   return 0;
193 }
194
195 int swf_SetLineStyle(TAG * t,LINESTYLE * l)
196 { if ((!l)||(!t)) return -1;
197   swf_SetU16(t,l->width);
198
199   if (swf_GetTagID(t)!=ST_DEFINESHAPE3) swf_SetRGB(t,&l->color);
200   else swf_SetRGBA(t,&l->color);
201   
202   return 0;
203 }
204
205 int swf_SetShapeStyleCount(TAG * t,U16 n)
206 { if (n>254)
207   { swf_SetU8(t,0xff);
208     swf_SetU16(t,n);
209     return 3;
210   }
211   else
212   { swf_SetU8(t,n);
213     return 1;
214   }
215 }
216
217 int swf_SetShapeStyles(TAG * t,SHAPE * s)
218 { int i,l;
219   if (!s) return -1;
220
221   l = 0;
222   l += swf_SetShapeStyleCount(t,s->fillstyle.n);
223
224   for (i=0;i<s->fillstyle.n;i++)
225     l+=swf_SetFillStyle(t,&s->fillstyle.data[i]);
226
227   l += swf_SetShapeStyleCount(t,s->linestyle.n);
228
229   for (i=0;i<s->linestyle.n;i++)
230     l+=swf_SetLineStyle(t,&s->linestyle.data[i]);
231
232   return l;
233 }
234
235 int swf_ShapeCountBits(SHAPE * s,U8 * fbits,U8 * lbits)
236 { if (!s) return -1;
237   s->bits.fill = swf_CountUBits(s->fillstyle.n, 0);
238   s->bits.line = swf_CountUBits(s->linestyle.n, 0);
239   if (fbits) fbits[0] = s->bits.fill;
240   if (lbits) lbits[0] = s->bits.line;
241   return 0;    
242 }
243
244 int swf_SetShapeBits(TAG * t,SHAPE * s)
245 { if ((!t)||(!s)) return -1;
246   swf_ResetWriteBits(t);
247   swf_SetBits(t,s->bits.fill,4);
248   swf_SetBits(t,s->bits.line,4);
249   return 0;
250 }
251
252 int swf_SetShapeHeader(TAG * t,SHAPE * s)
253 { int res;
254   res = swf_SetShapeStyles(t,s);
255   if (res>=0) res = swf_ShapeCountBits(s,NULL,NULL);
256   if (res>=0) res = swf_SetShapeBits(t,s);
257   return res;
258 }
259
260 int swf_ShapeAddFillStyle(SHAPE * s,U8 type,MATRIX * m,RGBA * color,U16 id_bitmap, GRADIENT*gradient)
261 { RGBA def_c;
262   MATRIX def_m;    
263   GRADIENT def_g;
264
265   // handle defaults
266   
267   if (!s) return -1;
268   if (!color)
269   { color = &def_c;
270     def_c.a = 0xff;
271     def_c.r = def_c.g = def_c.b = 0;
272   }
273   if (!m)
274   { m = &def_m;
275     swf_GetMatrix(NULL,m);
276   }
277   if(!gradient)
278   {
279     gradient = &def_g;
280     swf_GetGradient(NULL, gradient, 1);
281   }
282
283   // handle memory
284   
285   if (s->fillstyle.data)
286   { FILLSTYLE * new = (FILLSTYLE *)realloc(s->fillstyle.data,(s->fillstyle.n+1)*sizeof(FILLSTYLE));
287     if (!new) return -1;
288     s->fillstyle.data = new;
289   }
290   else
291   { s->fillstyle.data = (FILLSTYLE *)malloc(sizeof(FILLSTYLE));
292     s->fillstyle.n = 0;
293     if (!s->fillstyle.data) return -1;
294   }
295
296   // set fillstyle
297   
298   s->fillstyle.data[s->fillstyle.n].type = type; 
299   s->fillstyle.data[s->fillstyle.n].id_bitmap = id_bitmap;
300   memcpy(&s->fillstyle.data[s->fillstyle.n].m,m,sizeof(MATRIX));
301   memcpy(&s->fillstyle.data[s->fillstyle.n].color,color,sizeof(RGBA));
302   memcpy(&s->fillstyle.data[s->fillstyle.n].gradient,gradient,sizeof(GRADIENT));
303           
304   return (++s->fillstyle.n);
305 }
306
307 int swf_ShapeAddSolidFillStyle(SHAPE * s,RGBA * color)
308 { return swf_ShapeAddFillStyle(s,FILL_SOLID,NULL,color,0,0);
309 }
310
311 int swf_ShapeAddBitmapFillStyle(SHAPE * s,MATRIX * m,U16 id_bitmap,int clip)
312 { return swf_ShapeAddFillStyle(s,clip?FILL_CLIPPED:FILL_TILED,m,NULL,id_bitmap,0);
313 }
314
315 int swf_ShapeAddGradientFillStyle(SHAPE * s,MATRIX * m,GRADIENT* gradient,int radial)
316 { return swf_ShapeAddFillStyle(s,radial?FILL_RADIAL:FILL_LINEAR,m,NULL,0,gradient);
317 }
318
319 int swf_ShapeAddLineStyle(SHAPE * s,U16 width,RGBA * color)
320 { RGBA def;
321   if (!s) return -1;
322   if (!color)
323   { color = &def;
324     def.a = 0xff;
325     def.r = def.g = def.b = 0; 
326   }
327   if (s->linestyle.data)
328   { LINESTYLE * new = (LINESTYLE *)realloc(s->linestyle.data,(s->linestyle.n+1)*sizeof(LINESTYLE));
329     if (!new) return -1;
330     s->linestyle.data = new;
331   }
332   else
333   { s->linestyle.data = (LINESTYLE *)malloc(sizeof(LINESTYLE));
334     s->linestyle.n = 0;
335     if (!s->linestyle.data) return -1;
336   }
337   
338   s->linestyle.data[s->linestyle.n].width = width;
339   memcpy(&s->linestyle.data[s->linestyle.n].color,color,sizeof(RGBA));
340
341   return (++s->linestyle.n);
342 }
343
344 int swf_ShapeSetMove(TAG * t,SHAPE * s,S32 x,S32 y)
345 { U8 b;
346   if (!t) return -1;
347   swf_SetBits(t,0,1);
348   swf_SetBits(t,SF_MOVETO,5);
349   
350   b = swf_CountBits(x,0);
351   b = swf_CountBits(y,b);
352   
353   swf_SetBits(t,b,5);
354   swf_SetBits(t,x,b);
355   swf_SetBits(t,y,b);
356
357   return 0;
358 }
359
360 int swf_ShapeSetStyle(TAG * t,SHAPE * s,int line,int fill0,int fill1)
361 { if ((!t)||(!s)) return -1;
362     
363   swf_SetBits(t,0,1);
364   swf_SetBits(t,(line?SF_LINE:0)|(fill0?SF_FILL0:0)|(fill1?SF_FILL1:0),5);
365
366   if (fill0) swf_SetBits(t,fill0,s->bits.fill);
367   if (fill1) swf_SetBits(t,fill1,s->bits.fill);
368   if (line)  swf_SetBits(t,line ,s->bits.line);
369   
370   return 0;
371 }
372
373 /* TODO: sometimes we want to set fillstyle 0, as that's the empty fill
374    used for line drawings. At the moment, we can't, as 0 fill be considered
375    nonexistent and therefore not set.
376    these defines are a workaround (they also reduce the maximal number of
377    fill styles to 32768)
378  */
379 #define UNDEFINED_COORD 0x7fffffff
380
381 int swf_ShapeSetAll(TAG * t,SHAPE * s,S32 x,S32 y,int line,int fill0,int fill1)
382 { U8 b;
383   U8 hasmove = 0;
384   if ((!t)||(!s)) return -1;
385
386   if(x!=UNDEFINED_COORD || y!=UNDEFINED_COORD)
387       hasmove=1;
388
389   swf_SetBits(t,0,1);
390   swf_SetBits(t,(hasmove?SF_MOVETO:0)|(line?SF_LINE:0)|(fill0?SF_FILL0:0)|(fill1?SF_FILL1:0),5);
391
392   if(hasmove) {
393     b = swf_CountBits(x,0);
394     b = swf_CountBits(y,b);
395     swf_SetBits(t,b,5);
396     swf_SetBits(t,x,b);
397     swf_SetBits(t,y,b);
398   }
399
400   if (fill0) swf_SetBits(t,fill0,s->bits.fill);
401   if (fill1) swf_SetBits(t,fill1,s->bits.fill);
402   if (line)  swf_SetBits(t,line ,s->bits.line);
403   
404   return 0;
405 }
406
407 int swf_ShapeSetEnd(TAG * t)
408 { if (!t) return -1;
409   swf_SetBits(t,0,6);
410   swf_ResetWriteBits(t);
411   return 0;
412 }
413
414 int swf_ShapeSetLine(TAG * t,SHAPE * s,S32 x,S32 y)
415
416     U8 b;
417     if (!t) return -1;
418    
419     b = swf_CountBits(x,2);
420     b = swf_CountBits(y,b);
421     if (b<2) b=2;
422     if(b >= 18) {
423         if(b >= 18 + 4) {
424             /* do not split into more than 16 segments. If the line is *that* long, something's broken */
425             fprintf(stderr, "Warning: Line to %.2f,%.2f is too long", (double)x,(double)y);
426             return -1;
427         } else {
428             /* split line */
429             int x1,y1,x2,y2;
430             if(x>=0) { x1 = x/2;x2 = (x+1)/2;} 
431             else     { x1 = x/2;x2 = (x-1)/2;}
432             if(y>=0) { y1 = y/2;y2 = (y+1)/2;} 
433             else     { y1 = y/2;y2 = (y-1)/2;}
434             swf_ShapeSetLine(t, s, x1,y1);
435             swf_ShapeSetLine(t, s, x2,y2);
436             return 0;
437         }
438     }
439
440     if(x!=0 && y!=0) { //(!s)||((x!=0)&&(y!=0)))
441         swf_SetBits(t,3,2); // Straight Edge
442         swf_SetBits(t, b-2, 4); //Number of Bits in x/y
443         swf_SetBits(t,1,1); // Diagonal
444         swf_SetBits(t,x,b);
445         swf_SetBits(t,y,b);
446     } else if (x==0) {
447         swf_SetBits(t,3,2); // Straight Edge
448         swf_SetBits(t, b-2, 4); //Number of Bits in y
449         swf_SetBits(t,1,2); // Vertical
450         swf_SetBits(t,y,b);
451     } else {
452         swf_SetBits(t,3,2); // Straight Edge
453         swf_SetBits(t, b-2, 4); //Number of Bits in x
454         swf_SetBits(t,0,2); // Horizontal
455         swf_SetBits(t,x,b);
456     }
457     return 0;
458 }
459
460 int swf_ShapeSetCurve(TAG * t,SHAPE * s,S32 x,S32 y,S32 ax,S32 ay)
461
462     U8 b;
463     if (!t) return -1;
464
465     b = swf_CountBits(ax,2);
466     b = swf_CountBits(ay,b);
467     b = swf_CountBits(x,b);
468     b = swf_CountBits(y,b);
469
470     if(b >= 18) {
471           fprintf(stderr, "Bit overflow in swf_ShapeSetCurve- %d (%d,%d,%d,%d)\n", b, ax,ay,x,y);
472           b = 17;
473     }
474
475     swf_SetBits(t,2,2);
476     swf_SetBits(t,b-2,4);
477     swf_SetBits(t,x,b);
478     swf_SetBits(t,y,b);
479     swf_SetBits(t,ax,b);
480     swf_SetBits(t,ay,b);
481     return 0;
482 }
483
484 int swf_ShapeSetCircle(TAG * t,SHAPE * s,S32 x,S32 y,S32 rx,S32 ry)
485 { double C1 = 0.2930;    
486   double C2 = 0.4140;   
487   double begin = 0.7070; 
488
489   if (!t) return -1;
490   
491   swf_ShapeSetMove(t,s,x+begin*rx,y+begin*ry);
492   swf_ShapeSetCurve(t,s, -C1*rx,  C1*ry, -C2*rx,      0);
493   swf_ShapeSetCurve(t,s, -C2*rx,      0, -C1*rx, -C1*ry);
494   swf_ShapeSetCurve(t,s, -C1*rx, -C1*ry,      0, -C2*ry);
495   swf_ShapeSetCurve(t,s,      0, -C2*ry,  C1*rx, -C1*ry);
496   swf_ShapeSetCurve(t,s,  C1*rx, -C1*ry,  C2*rx,      0);
497   swf_ShapeSetCurve(t,s,  C2*rx,      0,  C1*rx,  C1*ry);
498   swf_ShapeSetCurve(t,s,  C1*rx,  C1*ry,      0,  C2*ry);
499   swf_ShapeSetCurve(t,s,      0,  C2*ry, -C1*rx,  C1*ry);
500   
501   return 0;
502 }
503
504 /* todo: merge this with swf_GetSimpleShape */
505 SHAPELINE* swf_ParseShapeData(U8*data, int bits, int fillbits, int linebits)
506 {
507     SHAPELINE _lines;
508     SHAPELINE*lines = &_lines;
509
510     TAG _tag;
511     TAG* tag = &_tag;
512     int fill0 = 0;
513     int fill1 = 0;
514     int line = 0;
515     int x=0,y=0;
516     
517     memset(tag, 0, sizeof(TAG));
518     tag->data = data;
519     tag->len = tag->memsize = (bits+7)/8;
520     tag->pos = 0;
521
522     lines->next = 0;
523     while(1) {
524         int flags;
525         flags = swf_GetBits(tag, 1);
526         if(!flags) { //style change
527             flags = swf_GetBits(tag, 5);
528             if(!flags)
529                 break;
530             if(flags&1) { //move
531                 int n = swf_GetBits(tag, 5); 
532                 x = swf_GetSBits(tag, n); //x
533                 y = swf_GetSBits(tag, n); //y
534             }
535             if(flags&2)
536                 fill0 = swf_GetBits(tag, fillbits); 
537             if(flags&4)
538                 fill1 = swf_GetBits(tag, fillbits); 
539             if(flags&8)
540                 line = swf_GetBits(tag, linebits); 
541             if(flags&16) {
542                 fprintf(stderr, "Additional file styles style change not yet supported\n");
543                 exit(1);
544                 //enumerateUsedIDs_styles(tag, callback, callback_data, num);
545                 fillbits = swf_GetBits(tag, 4);
546                 linebits = swf_GetBits(tag, 4);
547             }
548             if(flags&1) { //move
549                 lines->next = (SHAPELINE*)malloc(sizeof(SHAPELINE));
550                 lines = lines->next;
551                 lines->type = moveTo;
552                 lines->x = x; 
553                 lines->y = y; 
554                 lines->sx = lines->sy = 0;
555                 lines->fillstyle0 = fill0;
556                 lines->fillstyle1 = fill1;
557                 lines->linestyle = line;
558                 lines->next = 0;
559             }
560         } else {
561             flags = swf_GetBits(tag, 1);
562             if(flags) { //straight edge
563                 int n = swf_GetBits(tag, 4) + 2;
564                 if(swf_GetBits(tag, 1)) { //line flag
565                     x += swf_GetSBits(tag, n); //delta x
566                     y += swf_GetSBits(tag, n); //delta y
567                 } else {
568                     int v=swf_GetBits(tag, 1);
569                     int d;
570                     d = swf_GetSBits(tag, n); //vert/horz
571                     if(v) y += d;
572                     else  x += d;
573                 }
574                 lines->next = (SHAPELINE*)malloc(sizeof(SHAPELINE));
575                 lines = lines->next;
576                 lines->type = lineTo;
577                 lines->x = x; 
578                 lines->y = y; 
579                 lines->sx = lines->sy = 0;
580                 lines->fillstyle0 = fill0;
581                 lines->fillstyle1 = fill1;
582                 lines->linestyle = line;
583                 lines->next = 0;
584             } else { //curved edge
585                 int n = swf_GetBits(tag, 4) + 2;
586                 int x1,y1;
587                 x += swf_GetSBits(tag, n);
588                 y += swf_GetSBits(tag, n);
589                 x1 = x;
590                 y1 = y;
591                 x += swf_GetSBits(tag, n);
592                 y += swf_GetSBits(tag, n);
593
594                 lines->next = (SHAPELINE*)malloc(sizeof(SHAPELINE));
595                 lines = lines->next;
596                 lines->type = splineTo;
597                 lines->sx = x1; 
598                 lines->sy = y1; 
599                 lines->x = x; 
600                 lines->y = y; 
601                 lines->fillstyle0 = fill0;
602                 lines->fillstyle1 = fill1;
603                 lines->linestyle = line;
604                 lines->next = 0;
605             }
606         }
607     }
608     return _lines.next;
609 }
610
611 SRECT swf_GetShapeBoundingBox(SHAPE2*shape2)
612 {
613     SRECT r;
614     SHAPELINE*l = shape2->lines;
615     int lastx=0,lasty=0;
616     int valid = 0;
617     r.xmin = r.ymin = SCOORD_MAX;
618     r.xmax = r.ymax = SCOORD_MIN;
619
620     while(l) {
621         int t1;
622         if(l->linestyle>0) {
623             t1 = shape2->linestyles[l->linestyle - 1].width*3/2;
624         } else {
625             t1 = 0;
626         }
627
628         if(l->type == lineTo || l->type == splineTo)
629         {
630             valid = 1;
631             if(lastx - t1 < r.xmin) r.xmin = lastx - t1;
632             if(lasty - t1 < r.ymin) r.ymin = lasty - t1;
633             if(lastx + t1 > r.xmax) r.xmax = lastx + t1;
634             if(lasty + t1 > r.ymax) r.ymax = lasty + t1;
635             if(l->x - t1 < r.xmin) r.xmin = l->x - t1;
636             if(l->y - t1 < r.ymin) r.ymin = l->y - t1;
637             if(l->x + t1 > r.xmax) r.xmax = l->x + t1;
638             if(l->y + t1 > r.ymax) r.ymax = l->y + t1;
639             if(l->type == splineTo) {
640                 if(l->sx - t1 < r.xmin) r.xmin = l->sx - t1;
641                 if(l->sy - t1 < r.ymin) r.ymin = l->sy - t1;
642                 if(l->sx + t1 > r.xmax) r.xmax = l->sx + t1;
643                 if(l->sy + t1 > r.ymax) r.ymax = l->sy + t1;
644             }
645         }
646         lastx = l->x;
647         lasty = l->y;
648         l = l->next;
649     }
650     if(!valid) memset(&r, 0, sizeof(SRECT));
651     return r;
652 }
653
654 void swf_Shape2Free(SHAPE2 * s)
655 {
656     SHAPELINE*line = s->lines;
657     while(line) {
658         SHAPELINE*next = line->next;
659         free(line);
660         line = next;
661     }
662     if(s->linestyles)
663         free(s->linestyles);
664     if(s->fillstyles)
665         free(s->fillstyles);
666     if(s->bbox)
667         free(s->bbox);
668 }
669
670 SHAPE2* swf_ShapeToShape2(SHAPE*shape) {
671
672     SHAPE2*shape2 = (SHAPE2*)malloc(sizeof(SHAPE2));
673     
674     shape2->numlinestyles = shape->linestyle.n;
675     shape2->linestyles = (LINESTYLE*)malloc(sizeof(LINESTYLE)*shape->linestyle.n);
676     memcpy(shape2->linestyles, shape->linestyle.data, sizeof(LINESTYLE)*shape->linestyle.n);
677     
678     shape2->numfillstyles = shape->fillstyle.n;
679     shape2->fillstyles = (FILLSTYLE*)malloc(sizeof(FILLSTYLE)*shape->fillstyle.n);
680     memcpy(shape2->fillstyles, shape->fillstyle.data, sizeof(FILLSTYLE)*shape->fillstyle.n);
681
682     shape2->lines = swf_ParseShapeData(shape->data, shape->bitlen, shape->bits.fill, shape->bits.line);
683     shape2->bbox = 0;
684     return shape2;
685 };
686
687 void swf_ShapeSetBitmapRect(TAG*tag, U16 gfxid, int width, int height)
688 {
689     SHAPE*shape;
690     MATRIX m;
691     RGBA rgb;
692     SRECT r;
693     int lines = 0;
694     int ls=0,fs;
695     swf_ShapeNew(&shape);
696     rgb.b = rgb.g = rgb.r = 0xff;
697     if(lines)
698         ls = swf_ShapeAddLineStyle(shape,20,&rgb);  
699     swf_GetMatrix(NULL,&m);
700     m.sx = 20*65536;
701     m.sy = 20*65536;
702
703     fs = swf_ShapeAddBitmapFillStyle(shape,&m,gfxid,0);
704     r.xmin = 0;
705     r.ymin = 0;
706     r.xmax = width*20;
707     r.ymax = height*20;
708     swf_SetRect(tag,&r);
709
710     swf_SetShapeStyles(tag,shape);
711     swf_ShapeCountBits(shape,NULL,NULL);
712     swf_SetShapeBits(tag,shape);
713
714     swf_ShapeSetAll(tag,shape,0,0,lines?ls:0,fs,0);
715
716     swf_ShapeSetLine(tag,shape,width*20,0);
717     swf_ShapeSetLine(tag,shape,0,height*20);
718     swf_ShapeSetLine(tag,shape,-width*20,0);
719     swf_ShapeSetLine(tag,shape,0,-height*20);
720     swf_ShapeSetEnd(tag);
721     swf_ShapeFree(shape);
722 }
723
724 void swf_Shape2ToShape(SHAPE2*shape2, SHAPE*shape)
725 {
726     TAG*tag = swf_InsertTag(0,0);
727     SHAPELINE*l,*next;
728     int newx=0,newy=0,lastx=0,lasty=0,oldls=0,oldfs0=0,oldfs1=0;
729
730     memset(shape, 0, sizeof(SHAPE));
731
732     shape->linestyle.n = shape2->numlinestyles;
733     shape->linestyle.data = (LINESTYLE*)malloc(sizeof(LINESTYLE)*shape->linestyle.n);
734     memcpy(shape->linestyle.data, shape2->linestyles, sizeof(LINESTYLE)*shape->linestyle.n);
735     
736     shape->fillstyle.n =  shape2->numfillstyles;
737     shape->fillstyle.data = (FILLSTYLE*)malloc(sizeof(FILLSTYLE)*shape->fillstyle.n);
738     memcpy(shape->fillstyle.data, shape2->fillstyles, sizeof(FILLSTYLE)*shape->fillstyle.n);
739
740     swf_ShapeCountBits(shape,NULL,NULL);
741
742     l = shape2->lines;
743
744     while(l) {
745         int ls=0,fs0=0,fs1=0;
746
747         if(l->type != moveTo) {
748             if(oldls != l->linestyle) {oldls = ls = l->linestyle;if(!ls) ls=0x8000;}
749             if(oldfs0 != l->fillstyle0) {oldfs0 = fs0 = l->fillstyle0;if(!fs0) fs0=0x8000;}
750             if(oldfs1 != l->fillstyle1) {oldfs1 = fs1 = l->fillstyle1;if(!fs1) fs1=0x8000;}
751
752             if(ls || fs0 || fs1 || newx!=0x7fffffff || newy!=0x7fffffff) {
753                 swf_ShapeSetAll(tag,shape,newx,newy,ls,fs0,fs1);
754                 newx = 0x7fffffff;
755                 newy = 0x7fffffff;
756             }
757         }
758
759         if(l->type == lineTo) {
760             swf_ShapeSetLine(tag,shape,l->x-lastx,l->y-lasty);
761         } else if(l->type == splineTo) {
762             swf_ShapeSetCurve(tag,shape, l->sx-lastx,l->sy-lasty, l->x-l->sx,l->y-l->sy);
763         }
764         if(l->type == moveTo) {
765             newx = l->x;
766             newy = l->y;
767         }
768
769         lastx = l->x;
770         lasty = l->y;
771         l = l->next;
772     }
773     swf_ShapeSetEnd(tag);
774     shape->data = tag->data;
775     shape->bitlen = tag->len*8;
776 }
777
778 void swf_SetShape2(TAG*tag, SHAPE2*shape2)
779 {
780     SHAPE shape;
781     swf_Shape2ToShape(shape2, &shape);
782
783     swf_SetRect(tag,shape2->bbox);
784     swf_SetShapeStyles(tag, &shape);
785     swf_ShapeCountBits(&shape,NULL,NULL);
786     swf_SetShapeBits(tag,&shape);
787
788     swf_SetBlock(tag, shape.data, (shape.bitlen+7)/8);
789 }
790
791 static void parseFillStyleArray(TAG*tag, SHAPE2*shape)
792 {
793     U16 count;
794     int t;
795     int num=0;
796     if(tag->id == ST_DEFINESHAPE)
797         num = 1;
798     else if(tag->id == ST_DEFINESHAPE2)
799         num = 2;
800     else if(tag->id == ST_DEFINESHAPE3)
801         num = 3;
802
803     count = swf_GetU8(tag);
804     if(count == 0xff && num>1) // defineshape2,3 only
805         count = swf_GetU16(tag);
806
807     shape->numfillstyles = count;
808     shape->fillstyles = malloc(sizeof(FILLSTYLE)*count);
809
810     for(t=0;t<count;t++)
811     {
812         int type;
813         U8*pos;
814         FILLSTYLE*dest = &shape->fillstyles[t];
815         type = swf_GetU8(tag); //type
816         shape->fillstyles[t].type = type;
817         if(type == 0) {
818             /* plain color */
819             if(num == 3)
820                 swf_GetRGBA(tag, &dest->color);
821             else 
822                 swf_GetRGB(tag, &dest->color);
823         }
824         else if(type == 0x10 || type == 0x12)
825         {
826             /* linear/radial gradient fill */
827             swf_ResetReadBits(tag);
828             swf_GetMatrix(tag, &dest->m);
829             swf_ResetReadBits(tag);
830             swf_GetGradient(tag, &dest->gradient, num>=3?1:0);
831         }
832         else if(type == 0x40 || type == 0x41)
833         {
834             /* bitmap fill */
835             swf_ResetReadBits(tag);
836             dest->id_bitmap = swf_GetU16(tag); //id
837             swf_ResetReadBits(tag); //?
838             swf_GetMatrix(tag, &dest->m);
839         }
840         else {
841             fprintf(stderr, "rfxswf:swftools.c Unknown fillstyle:0x%02x\n",type);
842         }
843     }
844     swf_ResetReadBits(tag);
845     count = swf_GetU8(tag); // line style array
846     if(count == 0xff)
847         count = swf_GetU16(tag);
848
849     //if(verbose) printf("lnum: %d\n", count);
850
851     shape->numlinestyles = count;
852     shape->linestyles = malloc(sizeof(LINESTYLE)*count);
853     /* TODO: should we start with 1 and insert a correct definition of the
854        "built in" linestyle 0? */
855     for(t=0;t<count;t++) 
856     {
857         shape->linestyles[t].width = swf_GetU16(tag);
858         if(num == 3)
859             swf_GetRGBA(tag, &shape->linestyles[t].color);
860         else
861             swf_GetRGB(tag, &shape->linestyles[t].color);
862     }
863     return;
864 }
865
866 void swf_ParseDefineShape(TAG*tag, SHAPE2*shape)
867 {
868     int num = 0, id;
869     U16 fill,line;
870     SRECT r;
871     SRECT r2;
872     SHAPELINE*l;
873     if(tag->id == ST_DEFINESHAPE)
874         num = 1;
875     else if(tag->id == ST_DEFINESHAPE2)
876         num = 2;
877     else if(tag->id == ST_DEFINESHAPE3)
878         num = 3;
879     else {
880         fprintf(stderr, "parseDefineShape must be called with a shape tag");
881     }
882
883     id = swf_GetU16(tag); //id
884     memset(shape, 0, sizeof(SHAPE2));
885     shape->bbox = malloc(sizeof(SRECT));
886     swf_GetRect(tag, &r);
887
888     memcpy(shape->bbox, &r, sizeof(SRECT));
889     parseFillStyleArray(tag, shape);
890
891     swf_ResetReadBits(tag); 
892     fill = (U16)swf_GetBits(tag,4);
893     line = (U16)swf_GetBits(tag,4);
894
895     shape->lines = swf_ParseShapeData(&tag->data[tag->pos], (tag->len - tag->pos)*8, fill, line);
896
897     l = shape->lines;
898 }
899