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