c0abe756cbed62958f5ba8e0e2d764006edbca71
[swftools.git] / lib / modules / swfobject.c
1 /* swfobject.c
2
3    Object place and move routines
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 PF_MOVE         0x01
25 #define PF_CHAR         0x02
26 #define PF_MATRIX       0x04
27 #define PF_CXFORM       0x08
28 #define PF_RATIO        0x10
29 #define PF_NAME         0x20
30 #define PF_CLIPDEPTH    0x40
31 #define PF_ACTIONEVENT  0x80
32
33 #define PF2_FILTERS      0x01
34 #define PF2_BLENDMODE    0x02
35 #define PF2_ASBITMAP     0x04
36 //...
37
38 char*blendModeNames[] = {"normal","normal2","layer","multiply",
39                        "screen","lighten", "darken","add",
40                        "substract","difference","invert","alpha",
41                        "erase","overlay","hardlight",0};
42
43 int isUnitMatrix(MATRIX* m)
44 {
45     /* a matrix with all zeros is also considered
46        "unit matrix", as a zeroed out MATRIX structure
47        usually means that the caller doesn't want to
48        set the matrix */
49     if((   (m->sx == 0x10000 && m->sy == 0x10000) 
50         || (m->sx == 0 && m->sy == 0))
51                 && ((m->r0|m->r1|m->tx|m->ty) == 0)
52       )
53         return 1;
54     return 0;
55 }
56
57 int isUnitCXForm(CXFORM* cx)
58 {
59     if((cx->a0==256 && cx->r0==256 && cx->g0==256 && cx->b0==256) &&
60        (cx->a1==0 && cx->r1==0 && cx->g1==0 && cx->b1==0))
61         return 1;
62     /* A CXForm of all zeros is, unfortunately, not as unlikely
63        as a matrix of all zeros. However, we still treat it
64        as non-existent/uniform transform */
65     if((cx->a0==0 && cx->r0==0 && cx->g0==0 && cx->b0==0) &&
66        (cx->a1==0 && cx->r1==0 && cx->g1==0 && cx->b1==0))
67         return 1;
68     return 0;
69 }
70
71 static int objectplace(TAG * t,U16 id,U16 depth,MATRIX * m,CXFORM * cx,U8 * name, U16 clipaction, U8 blendmode, FILTERLIST*filters)
72 { U8 flags,flags2;
73   if (!t) return -1;
74
75   if(cx && id && cx->r1==0 && cx->g1==0 && cx->b1==0 && cx->a1==0
76               && cx->r0==256 && cx->g0==256 && cx->b0==256 && cx->a0==256)
77       cx = 0;
78
79   if(m && id && isUnitMatrix(m)) 
80       m = 0;
81
82   flags = (id?PF_CHAR:0)|(m?PF_MATRIX:0)|(cx?PF_CXFORM:0)|(name?PF_NAME:0)|((m||cx)&&(!id)?PF_MOVE:0)|(clipaction?PF_CLIPDEPTH:0);
83   flags2 = (0?PF2_ASBITMAP:0)|(blendmode?PF2_BLENDMODE:0)|(filters?PF2_FILTERS:0);
84
85   swf_SetU8(t,flags);
86   if(t->id == ST_PLACEOBJECT3)
87       swf_SetU8(t, flags2);
88   swf_SetU16(t,depth);
89   if (flags&PF_CHAR) swf_SetU16(t,id);
90   if (flags&PF_MATRIX) swf_SetMatrix(t,m);
91   if (flags&PF_CXFORM) swf_SetCXForm(t,cx,1);
92   if (flags&PF_RATIO) swf_SetU16(t,0);
93   /* ??? The spec states that name comes first? */
94   if (flags&PF_CLIPDEPTH) swf_SetU16(t, clipaction);
95   if (flags&PF_NAME) swf_SetString(t,name);
96         
97   if (flags2&PF2_BLENDMODE)
98     swf_SetU8(t,blendmode);
99   return 0; 
100 }
101 int swf_ObjectPlace(TAG * t,U16 id,U16 depth,MATRIX * m,CXFORM * cx,U8 * name)
102 {
103     return objectplace(t,id,depth,m,cx,name,0,0,0);
104 }
105 int swf_ObjectPlaceClip(TAG * t,U16 id,U16 depth,MATRIX * m,CXFORM * cx,U8 * name, U16 clipaction)
106
107     return objectplace(t,id,depth,m,cx,name,clipaction,0,0);
108 }
109 int swf_ObjectPlaceBlend(TAG * t,U16 id,U16 depth,MATRIX * m,CXFORM * cx,U8 * name, U8 blend)
110
111     if(t->id != ST_PLACEOBJECT3)
112         fprintf(stderr, "wrong tag- ignoring blend mode\n");
113     return objectplace(t,id,depth,m,cx,name,0,blend,0);
114 }
115 int swf_ObjectMove(TAG * t,U16 depth,MATRIX * m,CXFORM * cx)
116 {
117     return objectplace(t,0,depth,m,cx,0,0,0,0);
118 }
119
120 void swf_SetPlaceObject(TAG * t,SWFPLACEOBJECT* obj)
121
122     if (!t) return ;
123     if(t->id == ST_PLACEOBJECT) {
124         swf_SetU16(t, obj->id);
125         swf_SetU16(t, obj->depth);      
126         swf_SetMatrix(t, &obj->matrix);
127         swf_SetCXForm(t, &obj->cxform, 0);
128     } else {
129         U8 flags,flags2;
130         int m = !isUnitMatrix(&obj->matrix);
131         int cx = !isUnitCXForm(&obj->cxform);
132
133         flags = (obj->id?PF_CHAR:0)|(m?PF_MATRIX:0)|(cx?PF_CXFORM:0)|(obj->ratio?PF_RATIO:0)|
134                 (obj->name?PF_NAME:0)|(obj->move?PF_MOVE:0)|
135                 (obj->clipdepth?PF_CLIPDEPTH:0);
136         flags2 = (0?PF2_ASBITMAP:0)|(obj->blendmode?PF2_BLENDMODE:0)|(obj->filters?PF2_FILTERS:0);
137
138         swf_SetU8(t,flags);
139         if(t->id == ST_PLACEOBJECT3) 
140             swf_SetU8(t,flags2);
141         swf_SetU16(t,obj->depth);
142         if (flags&PF_CHAR) swf_SetU16(t,obj->id);
143         if (flags&PF_MATRIX) swf_SetMatrix(t,&obj->matrix);
144         if (flags&PF_CXFORM) swf_SetCXForm(t,&obj->cxform,1);
145         if (flags&PF_RATIO) swf_SetU16(t,obj->ratio);
146   
147         /* ??? The spec states that name comes first? */
148         if (flags&PF_CLIPDEPTH) swf_SetU16(t,obj->clipdepth);
149         if (flags&PF_NAME) swf_SetString(t,obj->name);
150
151         if (flags2&PF2_FILTERS) {
152             swf_SetU8(t,obj->filters->num);
153             int s;
154             for(s=0;s<obj->filters->num;s++)
155                 swf_SetFilter(t,obj->filters->filter[s]);
156         }
157         if (flags2&PF2_BLENDMODE)
158             swf_SetU8(t,obj->blendmode);
159         if (flags&PF_ACTIONEVENT) {
160             // ...
161         }
162     }
163 }
164
165 void swf_GetPlaceObject(TAG * tag,SWFPLACEOBJECT* obj)
166 {
167     if(!tag) {
168         memset(obj, 0, sizeof(SWFPLACEOBJECT));
169         swf_GetMatrix(0, &obj->matrix);
170         swf_GetCXForm(0, &obj->cxform, 1);
171         //obj->internal = PF_CHAR|PF_MATRIX|PF_CXFORM;
172         return;
173     }
174     swf_SetTagPos(tag, 0);
175     
176     if(tag->id == ST_PLACEOBJECT) {
177         obj->id = swf_GetU16(tag);
178         obj->depth = swf_GetU16(tag);
179         swf_GetMatrix(tag, &obj->matrix);
180         swf_GetCXForm(tag, &obj->cxform, 0);
181         //obj->internal = PF_CHAR|PF_MATRIX|PF_CXFORM;
182     } else if(tag->id == ST_PLACEOBJECT2 || tag->id == ST_PLACEOBJECT3) {
183         U8 flags,flags2=0;
184         flags = swf_GetU8(tag);
185         if(tag->id == ST_PLACEOBJECT3)
186             flags2 = swf_GetU8(tag);
187         memset(obj,0,sizeof(SWFPLACEOBJECT));
188             
189         swf_GetMatrix(0,&obj->matrix);
190         swf_GetCXForm(0,&obj->cxform,1);
191
192         obj->depth = swf_GetU16(tag);
193         //obj->internal = flags;
194         if(flags&PF_MOVE) obj->move = 1;
195         if(flags&PF_CHAR) obj->id = swf_GetU16(tag);
196         if(flags&PF_MATRIX) swf_GetMatrix(tag, &obj->matrix);
197         if(flags&PF_CXFORM) swf_GetCXForm(tag, &obj->cxform,1);
198         if(flags&PF_RATIO) obj->ratio = swf_GetU16(tag);
199         /* if you modify the order of these operations, also
200            modify it in ../src/swfcombine.c */
201         if(flags&PF_CLIPDEPTH) 
202             obj->clipdepth = swf_GetU16(tag); //clip
203         if(flags&PF_NAME) {
204             int l,t;
205             U8*data;
206             swf_ResetReadBits(tag);
207             l = strlen(&tag->data[tag->pos]);
208             t = 0;
209             data = rfx_alloc(l+1);
210             obj->name = data;
211             while((data[t++] = swf_GetU8(tag))); 
212         }
213         if(flags2&PF2_BLENDMODE) {
214             obj->blendmode = swf_GetU8(tag);
215         }
216
217         /* Actionscript ignored (for now) */
218         obj->actions = 0;
219     } else {
220         fprintf(stderr, "rfxswf: Bad Tag: %d not a placeobject\n", tag->id);
221     }
222 }
223
224 void swf_PlaceObjectFree(SWFPLACEOBJECT* obj)
225 {
226     if(obj->name)
227         rfx_free(obj->name);
228 }
229