minor fixes: swf_SetBits(), cleanup shape struct, fixed dumpfont
[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   return 0;
389 }
390
391 int swf_ShapeSetStyle(TAG * t,SHAPE * s,U16 line,U16 fill0,U16 fill1)
392 { if ((!t)||(!s)) return -1;
393     
394   swf_SetBits(t,0,1);
395   swf_SetBits(t,(line?SF_LINE:0)|(fill0?SF_FILL0:0)|(fill1?SF_FILL1:0),5);
396
397   if (fill0) swf_SetBits(t,fill0,s->bits.fill);
398   if (fill1) swf_SetBits(t,fill1,s->bits.fill);
399   if (line)  swf_SetBits(t,line ,s->bits.line);
400   
401   return 0;
402 }
403
404 /* TODO: sometimes we want to set fillstyle 0, as that's the empty fill
405    used for line drawings. At the moment, we can't, as 0 fill be considered
406    nonexistent and therefore not set.
407    these defines are a workaround (they also reduce the maximal number of
408    fill styles to 32768)
409  */
410 #define FILL_RESET 0x8000
411 #define LINE_RESET 0x8000
412
413 int swf_ShapeSetAll(TAG * t,SHAPE * s,S32 x,S32 y,U16 line,U16 fill0,U16 fill1)
414 { U8 b;
415   if ((!t)||(!s)) return -1;
416
417   swf_SetBits(t,0,1);
418   swf_SetBits(t,SF_MOVETO|(line?SF_LINE:0)|(fill0?SF_FILL0:0)|(fill1?SF_FILL1:0),5);
419
420   b = swf_CountBits(x,0);
421   b = swf_CountBits(y,b);
422   swf_SetBits(t,b,5);
423   swf_SetBits(t,x,b);
424   swf_SetBits(t,y,b);
425
426   if (fill0) swf_SetBits(t,fill0,s->bits.fill);
427   if (fill1) swf_SetBits(t,fill1,s->bits.fill);
428   if (line)  swf_SetBits(t,line ,s->bits.line);
429   
430   return 0;
431 }
432
433 int swf_ShapeSetEnd(TAG * t)
434 { if (!t) return -1;
435   swf_SetBits(t,0,6);
436   swf_ResetWriteBits(t);
437   return 0;
438 }
439
440 int swf_ShapeSetLine(TAG * t,SHAPE * s,S32 x,S32 y)
441 { U8 b;
442   if (!t) return -1;
443   swf_SetBits(t,3,2); // Straight Edge
444
445   if ((!s)||((x!=0)&&(y!=0)))
446   { b = swf_CountBits(x,2);
447     b = swf_CountBits(y,b);
448     if (b<2) b=2;
449     swf_SetBits(t, b-2, 4);
450     swf_SetBits(t,1,1);
451     swf_SetBits(t,x,b);
452     swf_SetBits(t,y,b);
453     return 0;
454   }
455
456   if (x==0)
457   { b = swf_CountBits(y,2);
458     if(b<2) 
459         b=2;
460     swf_SetBits(t, b-2, 4);
461     swf_SetBits(t,1,2);
462     swf_SetBits(t,y,b);
463   } 
464   else
465   { b = swf_CountBits(x,2);
466     if(b<2) 
467         b=2;
468     swf_SetBits(t, b-2, 4);
469     swf_SetBits(t,0,2);
470     swf_SetBits(t,x,b);
471   }
472   return 0;
473 }
474
475 int swf_ShapeSetCurve(TAG * t,SHAPE * s,S32 x,S32 y,S32 ax,S32 ay)
476 { U8 b;
477   if (!t) return -1;
478
479   swf_SetBits(t,2,2);
480
481   b = swf_CountBits(ax,2);
482   b = swf_CountBits(ay,b);
483   b = swf_CountBits(x,b);
484   b = swf_CountBits(y,b);
485
486   swf_SetBits(t,b-2,4);
487   swf_SetBits(t,x,b);
488   swf_SetBits(t,y,b);
489   swf_SetBits(t,ax,b);
490   swf_SetBits(t,ay,b);
491
492   return 0;
493 }
494
495 int swf_ShapeSetCircle(TAG * t,SHAPE * s,S32 x,S32 y,S32 rx,S32 ry)
496 { double C1 = 0.2930;    
497   double C2 = 0.4140;   
498   double begin = 0.7070; 
499
500   if (!t) return -1;
501   
502   swf_ShapeSetMove(t,s,x+begin*rx,y+begin*ry);
503   swf_ShapeSetCurve(t,s, -C1*rx,  C1*ry, -C2*rx,      0);
504   swf_ShapeSetCurve(t,s, -C2*rx,      0, -C1*rx, -C1*ry);
505   swf_ShapeSetCurve(t,s, -C1*rx, -C1*ry,      0, -C2*ry);
506   swf_ShapeSetCurve(t,s,      0, -C2*ry,  C1*rx, -C1*ry);
507   swf_ShapeSetCurve(t,s,  C1*rx, -C1*ry,  C2*rx,      0);
508   swf_ShapeSetCurve(t,s,  C2*rx,      0,  C1*rx,  C1*ry);
509   swf_ShapeSetCurve(t,s,  C1*rx,  C1*ry,      0,  C2*ry);
510   swf_ShapeSetCurve(t,s,      0,  C2*ry, -C1*rx,  C1*ry);
511   
512   return 0;
513 }
514