4f41406421b0cd0def083aa925862bfe89903203
[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 file is distributed under the GPL, see file COPYING for details 
11
12 */
13
14 #define SF_MOVETO       0x01
15 #define SF_FILL0        0x02
16 #define SF_FILL1        0x04
17 #define SF_LINE         0x08
18 #define SF_NEWSTYLE     0x10
19
20 #define FILL_SOLID      0x00
21 #define FILL_LINEAR     0x10  // Gradient
22 #define FILL_RADIAL     0x12
23 #define FILL_TILED      0x40  // Bitmap
24 #define FILL_CLIPPED    0x41
25
26 void swf_ShapeFree(SHAPE * s)
27 { if (s)
28   { if (s->linestyle.data) free(s->linestyle.data);
29     s->linestyle.data = NULL;
30     s->linestyle.n    = 0;
31     if (s->fillstyle.data) free(s->fillstyle.data);
32     s->fillstyle.data = NULL;
33     s->fillstyle.n    = 0;
34     if (s->data) free(s->data);
35     s->data = NULL;
36   }
37   free(s);
38 }
39
40 int swf_ShapeNew(SHAPE * * s)
41 { SHAPE * sh;
42   if (!s) return -1;
43   sh = (SHAPE *)malloc(sizeof(SHAPE)); s[0] = sh;
44   if (sh) memset(sh,0x00,sizeof(SHAPE));
45   return sh?0:-1;
46 }
47
48 int swf_GetSimpleShape(TAG * t,SHAPE * * s) // without Linestyle/Fillstyle Record
49 { SHAPE * sh;
50   int bitl, len;
51   int end;
52   U32 pos;
53   
54   if (FAILED(swf_ShapeNew(s))) return -1;
55   sh = s[0];
56
57   swf_ResetReadBits(t); 
58   sh->bits.fill = (U16)swf_GetBits(t,4);
59   sh->bits.line = (U16)swf_GetBits(t,4);
60   bitl = 0; end = 0; pos = swf_GetTagPos(t);
61
62   while (!end)
63   { int edge = swf_GetBits(t,1); bitl+=1;
64     if (edge)
65     { bitl+=1;
66       if (swf_GetBits(t,1))                 // Line
67       { U16 nbits = swf_GetBits(t,4)+2;
68         bitl+=5;
69
70         if (swf_GetBits(t,1))               // x/y Line
71         { swf_GetBits(t,nbits);
72           swf_GetBits(t,nbits);
73           bitl+=nbits*2;
74         }
75         else                            // hline/vline
76         { swf_GetBits(t,nbits+1);
77           bitl+=nbits+1;
78         }
79       }
80       else                              // Curve
81       { U16 nbits = swf_GetBits(t,4)+2;
82         bitl+=4;
83
84         swf_GetBits(t,nbits);
85         swf_GetBits(t,nbits);
86         swf_GetBits(t,nbits);
87         swf_GetBits(t,nbits);
88
89         bitl+=4*nbits;
90       }
91     }
92     else
93     { U16 flags = swf_GetBits(t,5); bitl+=5;
94       if (flags)
95       {
96         if (flags&SF_MOVETO)
97         { U16 nbits = swf_GetBits(t,5); bitl+=5;
98           swf_GetBits(t,nbits);
99           swf_GetBits(t,nbits);
100           bitl+=2*nbits;
101         }
102         
103         if (flags&SF_FILL0)
104         { swf_GetBits(t,sh->bits.fill);
105           bitl+=sh->bits.fill;
106         }
107         
108         if (flags&SF_FILL1)
109         { swf_GetBits(t,sh->bits.fill);
110           bitl+=sh->bits.fill;
111         }
112
113         if (flags&SF_LINE)
114         { swf_GetBits(t,sh->bits.line);
115           bitl+=sh->bits.line;
116         }
117
118         if (flags&SF_NEWSTYLE)
119         { fprintf(stderr,"RFXSWF: Can't process extended styles in shape.\n");
120         }
121       }
122       else end = 1;
123     }
124   }
125   swf_SetTagPos(t,pos);
126   len = (bitl+7)/8;
127   
128   if (sh->data) free(sh->data);
129   sh->data = (U8*)malloc(len);
130   
131   if (sh->data)
132   { sh->bitlen = bitl;
133     swf_GetBlock(t,sh->data,len);
134   }
135   else return -1;
136   
137   return len;
138 }
139
140 int swf_SetSimpleShape(TAG * t,SHAPE * s) // without Linestyle/Fillstyle Record
141 { int l;
142
143   if (!s) return -1;
144   l = (s->bitlen+7)/8;
145
146   if (t)
147   { swf_ResetWriteBits(t);
148
149     swf_SetBits(t,s->bits.fill,4);
150     swf_SetBits(t,s->bits.line,4);
151     swf_SetBlock(t,s->data,l);
152
153     swf_ResetWriteBits(t);
154   }
155   return l+1;
156 }
157
158 int swf_SetFillStyle(TAG * t,FILLSTYLE * f)
159 { if ((!t)||(!f)) return -1;
160   swf_SetU8(t,f->type);
161   
162   // no gradients yet!
163   
164   switch (f->type)
165   { case FILL_SOLID:
166       if (swf_GetTagID(t)!=ST_DEFINESHAPE3) swf_SetRGB(t,&f->color);
167       else swf_SetRGBA(t,&f->color);
168       break;
169
170     case FILL_TILED:
171     case FILL_CLIPPED:
172       swf_SetU16(t,f->id_bitmap);
173       swf_SetMatrix(t,&f->m);
174       break;
175   }
176   
177   return 0;
178 }
179
180 int swf_SetLineStyle(TAG * t,LINESTYLE * l)
181 { if ((!l)||(!t)) return -1;
182   swf_SetU16(t,l->width);
183
184   if (swf_GetTagID(t)!=ST_DEFINESHAPE3) swf_SetRGB(t,&l->color);
185   else swf_SetRGBA(t,&l->color);
186   
187   return 0;
188 }
189
190 int swf_SetShapeStyleCount(TAG * t,U16 n)
191 { if (n>254)
192   { swf_SetU8(t,0xff);
193     swf_SetU16(t,n);
194     return 3;
195   }
196   else
197   { swf_SetU8(t,n);
198     return 1;
199   }
200 }
201
202 int swf_SetShapeStyles(TAG * t,SHAPE * s)
203 { int i,l;
204   if (!s) return -1;
205
206   l = 0;
207   l += swf_SetShapeStyleCount(t,s->fillstyle.n);
208
209   for (i=0;i<s->fillstyle.n;i++)
210     l+=swf_SetFillStyle(t,&s->fillstyle.data[i]);
211
212   l += swf_SetShapeStyleCount(t,s->linestyle.n);
213
214   for (i=0;i<s->linestyle.n;i++)
215     l+=swf_SetLineStyle(t,&s->linestyle.data[i]);
216
217   return l;
218 }
219
220 int swf_ShapeCountBits(SHAPE * s,U8 * fbits,U8 * lbits)
221 { if (!s) return -1;
222     
223   s->bits.fill = swf_CountBits(s->fillstyle.n,0);
224   s->bits.line = swf_CountBits(s->linestyle.n,0);
225
226   if (fbits) fbits[0] = s->bits.fill;
227   if (lbits) lbits[0] = s->bits.line;
228   
229   return 0;    
230 }
231
232 int swf_SetShapeBits(TAG * t,SHAPE * s)
233 { if ((!t)||(!s)) return -1;
234   swf_ResetWriteBits(t);
235   swf_SetBits(t,s->bits.fill,4);
236   swf_SetBits(t,s->bits.line,4);
237   return 0;
238 }
239
240 int swf_SetShapeHeader(TAG * t,SHAPE * s)
241 { int res;
242   res = swf_SetShapeStyles(t,s);
243   if (res>=0) res = swf_ShapeCountBits(s,NULL,NULL);
244   if (res>=0) res = swf_SetShapeBits(t,s);
245   return res;
246 }
247
248 int swf_ShapeExport(int handle,SHAPE * s)  // without Linestyle/Fillstyle Record
249 { int l;
250   if (!s) return 0;
251
252   l = sizeof(SHAPE);
253
254   if (handle>=0)
255     if (write(handle,s,sizeof(SHAPE))!=sizeof(SHAPE)) return -1;
256
257   // Fillstyle, Linestyle ...
258
259   if (s->data)
260   { int ll = (s->bitlen+7)/8;
261     l+=ll;
262     if (handle>=0)
263       if (write(handle,s->data,ll)!=ll) return -1;
264   }
265
266   return l;
267 }
268
269 int swf_ShapeImport(int handle,SHAPE * * shape)
270 { SHAPE * s;
271
272   if (handle<0) return -1;
273
274   s = (SHAPE *)malloc(sizeof(SHAPE)); shape[0] = s;
275   if (!s) return -1;
276
277   if (read(handle,s,sizeof(SHAPE))!=sizeof(SHAPE))
278   { shape[0] = NULL;
279     free(s);
280     return -1;
281   }
282
283   if (s->data)
284   { int ll = (s->bitlen+7)/8;
285     s->data = (U8*)malloc(ll);
286     if (!s->data)
287     { shape[0] = NULL;
288       free(s);
289       return -1;
290     }
291     if (read(handle,s->data,ll)!=ll)
292     { free(s->data);
293       free(s);
294       shape[0] = NULL;
295       return -1;
296     }
297   }
298
299   return 0;
300 }
301
302 int swf_ShapeAddFillStyle(SHAPE * s,U8 type,MATRIX * m,RGBA * color,U16 id_bitmap)
303 { RGBA def_c;
304   MATRIX def_m;    
305
306   // handle defaults
307   
308   if (!s) return -1;
309   if (!color)
310   { color = &def_c;
311     def_c.a = 0xff;
312     def_c.r = def_c.g = def_c.b = 0;
313   }
314   if (!m)
315   { m = &def_m;
316     swf_GetMatrix(NULL,m);
317   }
318
319   // handle memory
320   
321   if (s->fillstyle.data)
322   { FILLSTYLE * new = (FILLSTYLE *)realloc(s->fillstyle.data,(s->fillstyle.n+1)*sizeof(FILLSTYLE));
323     if (!new) return -1;
324     s->fillstyle.data = new;
325   }
326   else
327   { s->fillstyle.data = (FILLSTYLE *)malloc(sizeof(FILLSTYLE));
328     s->fillstyle.n = 0;
329     if (!s->fillstyle.data) return -1;
330   }
331
332   // set fillstyle  (no gradients yet!)
333   
334   s->fillstyle.data[s->fillstyle.n].type = type; 
335   s->fillstyle.data[s->fillstyle.n].id_bitmap = id_bitmap;
336   memcpy(&s->fillstyle.data[s->fillstyle.n].m,m,sizeof(MATRIX));
337   memcpy(&s->fillstyle.data[s->fillstyle.n].color,color,sizeof(RGBA));
338           
339   return (++s->fillstyle.n);
340 }
341
342 int swf_ShapeAddSolidFillStyle(SHAPE * s,RGBA * color)
343 { return swf_ShapeAddFillStyle(s,FILL_SOLID,NULL,color,0);
344 }
345
346 int swf_ShapeAddBitmapFillStyle(SHAPE * s,MATRIX * m,U16 id_bitmap,int clip)
347 { return swf_ShapeAddFillStyle(s,clip?FILL_CLIPPED:FILL_TILED,m,NULL,id_bitmap);
348 }
349
350 int swf_ShapeAddLineStyle(SHAPE * s,U16 width,RGBA * color)
351 { RGBA def;
352   if (!s) return -1;
353   if (!color)
354   { color = &def;
355     def.a = 0xff;
356     def.r = def.g = def.b = 0; 
357   }
358   if (s->linestyle.data)
359   { LINESTYLE * new = (LINESTYLE *)realloc(s->linestyle.data,(s->linestyle.n+1)*sizeof(LINESTYLE));
360     if (!new) return -1;
361     s->linestyle.data = new;
362   }
363   else
364   { s->linestyle.data = (LINESTYLE *)malloc(sizeof(LINESTYLE));
365     s->linestyle.n = 0;
366     if (!s->linestyle.data) return -1;
367   }
368   
369   s->linestyle.data[s->linestyle.n].width = width;
370   memcpy(&s->linestyle.data[s->linestyle.n].color,color,sizeof(RGBA));
371
372   return (++s->linestyle.n);
373 }
374
375 int swf_ShapeSetMove(TAG * t,SHAPE * s,S32 x,S32 y)
376 { U8 b;
377   if (!t) return -1;
378   swf_SetBits(t,0,1);
379   swf_SetBits(t,SF_MOVETO,5);
380   
381   b = swf_CountBits(x,0);
382   b = swf_CountBits(y,b);
383   
384   swf_SetBits(t,b,5);
385   swf_SetBits(t,x,b);
386   swf_SetBits(t,y,b);
387
388   if (s)
389   { s->px = x;
390     s->py = y;
391   }
392   return 0;
393 }
394
395 int swf_ShapeSetStyle(TAG * t,SHAPE * s,U16 line,U16 fill0,U16 fill1)
396 { if ((!t)||(!s)) return -1;
397     
398   swf_SetBits(t,0,1);
399   swf_SetBits(t,(line?SF_LINE:0)|(fill0?SF_FILL0:0)|(fill1?SF_FILL1:0),5);
400
401   if (fill0) swf_SetBits(t,fill0,s->bits.fill);
402   if (fill1) swf_SetBits(t,fill1,s->bits.fill);
403   if (line)  swf_SetBits(t,line ,s->bits.line);
404   
405   return 0;
406 }
407
408 /* TODO: sometimes we want to set fillstyle 0, as that's the empty fill
409    used for line drawings. At the moment, we can't, as 0 fill be considered
410    nonexistent and therefore not set.
411    these defines are a workaround (they also reduce the maximal number of
412    fill styles to 32768)
413  */
414 #define FILL_RESET 0x8000
415 #define LINE_RESET 0x8000
416
417 int swf_ShapeSetAll(TAG * t,SHAPE * s,S32 x,S32 y,U16 line,U16 fill0,U16 fill1)
418 { U8 b;
419   if ((!t)||(!s)) return -1;
420
421   swf_SetBits(t,0,1);
422   swf_SetBits(t,SF_MOVETO|(line?SF_LINE:0)|(fill0?SF_FILL0:0)|(fill1?SF_FILL1:0),5);
423
424   b = swf_CountBits(x,0);
425   b = swf_CountBits(y,b);
426   swf_SetBits(t,b,5);
427   swf_SetBits(t,x,b);
428   swf_SetBits(t,y,b);
429   s->px = x;
430   s->py = y;
431
432   if (fill0) swf_SetBits(t,fill0,s->bits.fill);
433   if (fill1) swf_SetBits(t,fill1,s->bits.fill);
434   if (line)  swf_SetBits(t,line ,s->bits.line);
435   
436   return 0;
437 }
438
439 int swf_ShapeSetEnd(TAG * t)
440 { if (!t) return -1;
441   swf_SetBits(t,0,6);
442   swf_ResetWriteBits(t);
443   return 0;
444 }
445
446 int swf_ShapeSetLine(TAG * t,SHAPE * s,S32 x,S32 y)
447 { U8 b;
448   if (!t) return -1;
449   swf_SetBits(t,3,2); // Straight Edge
450
451   if ((!s)||((x!=0)&&(y!=0)))
452   { b = swf_CountBits(x,2);
453     b = swf_CountBits(y,b);
454     if (b<2) b=2;
455     swf_SetBits(t, b-2, 4);
456     swf_SetBits(t,1,1);
457     swf_SetBits(t,x,b);
458     swf_SetBits(t,y,b);
459     if (s)
460     { s->px += x;
461       s->py += y;
462     }
463     return 0;
464   }
465
466   if (x==0)
467   { b = swf_CountBits(y,2);
468     if(b<2) 
469         b=2;
470     swf_SetBits(t, b-2, 4);
471     swf_SetBits(t,1,2);
472     swf_SetBits(t,y,b);
473     s->py += y;
474   }
475   else
476   { b = swf_CountBits(x,2);
477     if(b<2) 
478         b=2;
479     swf_SetBits(t, b-2, 4);
480     swf_SetBits(t,0,2);
481     swf_SetBits(t,x,b);
482     s->px += x;
483   }
484   return 0;
485 }
486
487 int swf_ShapeSetCurve(TAG * t,SHAPE * s,S32 x,S32 y,S32 ax,S32 ay)
488 { U8 b;
489   if (!t) return -1;
490
491   swf_SetBits(t,2,2);
492
493   b = swf_CountBits(ax,2);
494   b = swf_CountBits(ay,b);
495   b = swf_CountBits(x,b);
496   b = swf_CountBits(y,b);
497
498   swf_SetBits(t,b-2,4);
499   swf_SetBits(t,x,b);
500   swf_SetBits(t,y,b);
501   swf_SetBits(t,ax,b);
502   swf_SetBits(t,ay,b);
503
504   if (s)
505   { s->px += x+ax;
506     s->py += y+ay;
507   }
508   return 0;
509 }
510
511 int swf_ShapeSetCircle(TAG * t,SHAPE * s,S32 x,S32 y,S32 rx,S32 ry)
512 { double C1 = 0.2930;    
513   double C2 = 0.4140;   
514   double begin = 0.7070; 
515
516   if (!t) return -1;
517   
518   swf_ShapeSetMove(t,s,x+begin*rx,y+begin*ry);
519   swf_ShapeSetCurve(t,s, -C1*rx,  C1*ry, -C2*rx,      0);
520   swf_ShapeSetCurve(t,s, -C2*rx,      0, -C1*rx, -C1*ry);
521   swf_ShapeSetCurve(t,s, -C1*rx, -C1*ry,      0, -C2*ry);
522   swf_ShapeSetCurve(t,s,      0, -C2*ry,  C1*rx, -C1*ry);
523   swf_ShapeSetCurve(t,s,  C1*rx, -C1*ry,  C2*rx,      0);
524   swf_ShapeSetCurve(t,s,  C2*rx,      0,  C1*rx,  C1*ry);
525   swf_ShapeSetCurve(t,s,  C1*rx,  C1*ry,      0,  C2*ry);
526   swf_ShapeSetCurve(t,s,      0,  C2*ry, -C1*rx,  C1*ry);
527   
528   return 0;
529 }
530