several fixes to Huub's patch
[swftools.git] / src / swfc-history.c
1 /* swfc- Compiles swf code (.sc) files into .swf files.
2
3    Part of the swftools package.
4
5    Copyright (c) 2007 Huub Schaeks <huub@h-schaeks.speedlinq.nl>
6    Copyright (c) 2007 Matthias Kramm <kramm@quiss.org>
7  
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
21
22 #include <stdlib.h>
23 #include <memory.h>
24 #include "swfc-history.h"
25
26 change_t* change_new(U16 frame, int function, float value, interpolation_t* inter)
27 {
28         change_t* newChange = (change_t*)malloc(sizeof(change_t));
29         change_init(newChange);
30         newChange->frame = frame;
31         newChange->function = function;
32         newChange->value = value;
33         newChange->interpolation = inter;
34         return newChange;
35 }
36
37 void change_free(change_t *change)
38 {
39         if (change->next)
40                 change_free(change->next);
41         free(change);
42 }
43
44 void change_init(change_t* change)
45 {
46         memset(change, 0, sizeof(change_t));
47 }
48
49 void change_append(change_t* first, change_t* newChange)
50 {
51         while (first->next)
52                 first = first->next;
53         first->next = newChange;
54 }
55
56 float interpolateParameter(float p1, float p2, float fraction, interpolation_t* inter)
57 {
58         if (!inter)
59                 return linear(fraction, p1, p2 - p1);
60         switch (inter->function)
61         {
62                 case IF_LINEAR: return linear(fraction, p1, p2 - p1);
63                 case IF_QUAD_IN: return quadIn(fraction, p1, p2 - p1);
64                 case IF_QUAD_OUT: return quadOut(fraction, p1, p2 - p1);
65                 case IF_QUAD_IN_OUT: return quadInOut(fraction, p1, p2 - p1);
66                 case IF_CUBIC_IN: return cubicIn(fraction, p1, p2 - p1);
67                 case IF_CUBIC_OUT: return cubicOut(fraction, p1, p2 - p1);
68                 case IF_CUBIC_IN_OUT: return cubicInOut(fraction, p1, p2 - p1);
69                 case IF_QUART_IN: return quartIn(fraction, p1, p2 - p1);
70                 case IF_QUART_OUT: return quartOut(fraction, p1, p2 - p1);
71                 case IF_QUART_IN_OUT: return quartInOut(fraction, p1, p2 - p1);
72                 case IF_QUINT_IN: return quintIn(fraction, p1, p2 - p1);
73                 case IF_QUINT_OUT: return quintOut(fraction, p1, p2 - p1);
74                 case IF_QUINT_IN_OUT: return quintInOut(fraction, p1, p2 - p1);
75                 case IF_CIRCLE_IN: return circleIn(fraction, p1, p2 - p1);
76                 case IF_CIRCLE_OUT: return circleOut(fraction, p1, p2 - p1);
77                 case IF_CIRCLE_IN_OUT: return circleInOut(fraction, p1, p2 - p1);
78                 case IF_EXPONENTIAL_IN: return exponentialIn(fraction, p1, p2 - p1);
79                 case IF_EXPONENTIAL_OUT: return exponentialOut(fraction, p1, p2 - p1);
80                 case IF_EXPONENTIAL_IN_OUT: return exponentialInOut(fraction, p1, p2 - p1);
81                 case IF_SINE_IN: return sineIn(fraction, p1, p2 - p1);
82                 case IF_SINE_OUT: return sineOut(fraction, p1, p2 - p1);
83                 case IF_SINE_IN_OUT: return sineInOut(fraction, p1, p2 - p1);
84                 case IF_ELASTIC_IN: return elasticIn(fraction, p1, p2 - p1, inter->amplitude, inter->bounces, inter->damping);
85                 case IF_ELASTIC_OUT: return elasticOut(fraction, p1, p2 - p1, inter->amplitude, inter->bounces, inter->damping);
86                 case IF_ELASTIC_IN_OUT: return elasticInOut(fraction, p1, p2 - p1, inter->amplitude, inter->bounces, inter->damping);
87                 case IF_BACK_IN: return backIn(fraction, p1, p2 - p1, inter->speed);
88                 case IF_BACK_OUT: return backOut(fraction, p1, p2 - p1, inter->speed);
89                 case IF_BACK_IN_OUT: return backInOut(fraction, p1, p2 - p1, inter->speed);
90                 case IF_BOUNCE_IN: return bounceIn(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping);
91                 case IF_BOUNCE_OUT: return bounceOut(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping);
92                 case IF_BOUNCE_IN_OUT: return bounceInOut(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping);
93                 case IF_FAST_BOUNCE_IN: return fastBounceIn(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping);
94                 case IF_FAST_BOUNCE_OUT: return fastBounceOut(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping);
95                 case IF_FAST_BOUNCE_IN_OUT: return fastBounceInOut(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping);
96                 default: return linear(fraction, p1, p2 - p1);
97         }
98 }
99
100 float change_value(change_t* first, U16 frame)
101 {
102         change_t* previous = first;
103         while (first && first->frame < frame)
104         {
105                 previous = first;
106                 first = first->next;
107         }
108         if (!first)
109                 return previous->value;
110         if (first->frame == frame)
111         {
112                 float result;
113                 do 
114                 {
115                         result = first->value;
116                         first = first->next;
117                 }
118                 while (first && first->frame == frame);
119                 return result;
120         }
121         switch (first->function)
122         {
123                 case CF_PUT:
124                         return first->value;
125                 case CF_CHANGE:
126                 {
127                         float fraction = (frame - previous->frame) / (float)(first->frame - previous->frame);
128                         return interpolateParameter(previous->value, first->value, fraction, first->interpolation);
129                 }
130                 case CF_JUMP:
131                         return previous->value;
132                 default:
133                         return 0;
134         }
135 }
136
137 changeFilter_t* changeFilter_new(U16 frame, int function, FILTER* value, interpolation_t* inter)
138 {
139         changeFilter_t* newChange = (changeFilter_t*)malloc(sizeof(changeFilter_t));
140         changeFilter_init(newChange);
141         newChange->frame = frame;
142         newChange->function = function;
143         newChange->value = value;
144         newChange->interpolation = inter;
145         return newChange;
146 }
147
148 void changeFilter_free(changeFilter_t *change)
149 {
150         if (change->next)
151                 changeFilter_free(change->next);
152         free(change);
153 }
154
155 void changeFilter_init(changeFilter_t* change)
156 {
157         memset(change, 0, sizeof(changeFilter_t));
158 }
159
160 void changeFilter_append(changeFilter_t* first, changeFilter_t* newChange)
161 {
162         while (first->next)
163                 first = first->next;
164         first->next = newChange;
165 }
166
167 RGBA interpolateColor(RGBA c1, RGBA c2, float ratio, interpolation_t* inter)
168 {
169     RGBA c;
170     c.r = c1.r * (1-ratio) + c2.r * ratio;
171     c.g = c1.g * (1-ratio) + c2.g * ratio;
172     c.b = c1.b * (1-ratio) + c2.b * ratio;
173     c.a = c1.a * (1-ratio) + c2.a * ratio;
174     return c;
175 }
176
177 FILTER* interpolateFilter(FILTER* filter1,FILTER* filter2, float ratio, interpolation_t* inter)
178 {
179         if(!filter1 && !filter2)
180                 return 0;
181         if(!filter1)
182                 return interpolateFilter(filter2,filter1,1-ratio, inter);
183
184         if(filter2 && filter2->type != filter1->type)
185                 syntaxerror("can't interpolate between %s and %s filters yet", filtername[filter1->type], filtername[filter2->type]);
186    
187         if(filter1->type == FILTERTYPE_BLUR)
188         {
189                 FILTER_BLUR*f1 = (FILTER_BLUR*)filter1;
190                 FILTER_BLUR*f2 = (FILTER_BLUR*)filter2;
191                 if(f2 && f1->blurx == f2->blurx && f1->blury == f2->blury)
192                         return 0;
193                 FILTER_BLUR*f = (FILTER_BLUR*)swf_NewFilter(FILTERTYPE_BLUR);
194                 f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio;
195                 f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio;
196                 f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio;
197                 return (FILTER*)f;
198                 }
199         else
200                 if (filter1->type == FILTERTYPE_DROPSHADOW)
201                 {
202                         FILTER_DROPSHADOW*f1 = (FILTER_DROPSHADOW*)filter1;
203                         FILTER_DROPSHADOW*f2 = (FILTER_DROPSHADOW*)filter2;
204                         if(f2 && !memcmp(&f1->color,&f2->color,sizeof(RGBA)) && f1->strength == f2->strength && 
205                                 f1->blurx == f2->blurx && f1->blury == f2->blury && 
206                                 f1->angle == f2->angle && f1->distance == f2->distance)
207                                 return 0;
208                         FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)swf_NewFilter(FILTERTYPE_DROPSHADOW);
209                         memcpy(f, f1, sizeof(FILTER_DROPSHADOW));
210                         f->color = interpolateColor(f1->color, f2->color, ratio, inter);
211                         f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio;
212                         f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio;
213                         f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio;
214                         f->angle= (f1->angle)*(1-ratio) + (f2?f2->angle:0)*ratio;
215                         f->distance= (f1->distance)*(1-ratio) + (f2?f2->distance:0)*ratio;
216                         f->strength= (f1->strength)*(1-ratio) + (f2?f2->strength:0)*ratio;
217                         return (FILTER*)f;
218                 }
219                 else
220                         if (filter1->type == FILTERTYPE_BEVEL)
221                         {
222                                 FILTER_BEVEL*f1 = (FILTER_BEVEL*)filter1;
223                                 FILTER_BEVEL*f2 = (FILTER_BEVEL*)filter2;
224                                 if(f2 && !memcmp(&f1->shadow,&f2->shadow,sizeof(RGBA)) && 
225                                         !memcmp(&f1->highlight,&f2->highlight,sizeof(RGBA)) && 
226                                         f1->blurx == f2->blurx && f1->blury == f2->blury && f1->angle == f2->angle && f1->strength == f2->strength && f1->distance == f2->distance)
227                                         return 0;
228                                 FILTER_BEVEL*f = (FILTER_BEVEL*)swf_NewFilter(FILTERTYPE_BEVEL);
229                                 memcpy(f, f1, sizeof(FILTER_BEVEL));
230                                 f->shadow = interpolateColor(f1->shadow, f2->shadow, ratio, inter);
231                                 f->highlight = interpolateColor(f1->highlight, f2->highlight, ratio, inter);
232                                 f->blurx= (f1->blurx)*(1-ratio) + (f2?f2->blurx:0)*ratio;
233                                 f->blury= (f1->blury)*(1-ratio) + (f2?f2->blury:0)*ratio;
234                                 f->passes= (f1->passes)*(1-ratio) + (f2?f2->passes:0)*ratio;
235                                 f->angle= (f1->angle)*(1-ratio) + (f2?f2->angle:0)*ratio;
236                                 f->distance= (f1->distance)*(1-ratio) + (f2?f2->distance:0)*ratio;
237                                 f->strength= (f1->strength)*(1-ratio) + (f2?f2->strength:0)*ratio;
238                                 return (FILTER*)f;
239                         } /*else if (filter1->type == FILTERTYPE_GRADIENTGLOW) {
240         FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
241         // can't interpolate gradients
242         memcpy(f, filter1, sizeof(FILTER_GRADIENTGLOW));
243         return (FILTER*)f;
244     }*/ else
245                                 syntaxerror("can't interpolate %s filters yet", filtername[filter1->type]);
246         return 0;
247 }
248
249 FILTER* copyFilter(FILTER* original)
250 {
251         if (!original)
252                 return original;
253         FILTER* copy = swf_NewFilter(original->type);
254         switch (original->type)
255         {
256                 case FILTERTYPE_BLUR:
257                         memcpy(copy, original, sizeof(FILTER_BLUR));
258                         break;
259                 case FILTERTYPE_GRADIENTGLOW:
260                         memcpy(copy, original, sizeof(FILTER_GRADIENTGLOW));
261                         break;
262                 case FILTERTYPE_DROPSHADOW:
263                         memcpy(copy, original, sizeof(FILTER_DROPSHADOW)); 
264                         break;
265                 case FILTERTYPE_BEVEL:
266                         memcpy(copy, original, sizeof(FILTER_BEVEL)); 
267                         break;
268                 default: printf("unsupported filterype");
269         }
270         return copy;
271 }
272
273 FILTER* changeFilter_value(changeFilter_t* first, U16 frame)
274 {
275         changeFilter_t* previous = first;
276         while (first && first->frame < frame)
277         {
278                 previous = first;
279                 first = first->next;
280         }
281         if (!first)
282                 return copyFilter(previous->value);
283         if (first->frame == frame)
284         {
285                 FILTER* result;
286                 do 
287                 {
288                         result = first->value;
289                         first = first->next;
290                 }
291                 while (first && first->frame == frame);
292                 return copyFilter(result);
293         }
294         switch (first->function)
295         {
296                 case CF_PUT:
297                         return copyFilter(first->value);
298                 case CF_CHANGE:
299                 {
300                         float fraction = (frame - previous->frame) / (float)(first->frame - previous->frame);
301                         return interpolateFilter(previous->value, first->value, fraction, first->interpolation);
302                 }
303                 case CF_JUMP:
304                         return copyFilter(previous->value);
305                 default:
306                         return 0;
307         }
308 }
309
310 history_t* history_new()
311 {
312         history_t* newHistory = (history_t*)malloc(sizeof(history_t));
313         history_init(newHistory);
314         return newHistory;
315 }
316
317 void history_free(history_t* past)
318 {
319         change_free(dictionary_lookup(past->changes, "x"));
320         change_free(dictionary_lookup(past->changes, "y"));
321         change_free(dictionary_lookup(past->changes, "scalex"));
322         change_free(dictionary_lookup(past->changes, "scaley"));
323         change_free(dictionary_lookup(past->changes, "cxform.r0"));
324         change_free(dictionary_lookup(past->changes, "cxform.g0"));
325         change_free(dictionary_lookup(past->changes, "cxform.b0"));
326         change_free(dictionary_lookup(past->changes, "cxform.a0"));
327         change_free(dictionary_lookup(past->changes, "cxform.r1"));
328         change_free(dictionary_lookup(past->changes, "cxform.g1"));
329         change_free(dictionary_lookup(past->changes, "cxform.b1"));
330         change_free(dictionary_lookup(past->changes, "cxform.a1"));
331         change_free(dictionary_lookup(past->changes, "rotate"));
332         change_free(dictionary_lookup(past->changes, "shear"));
333         change_free(dictionary_lookup(past->changes, "pivot.x"));
334         change_free(dictionary_lookup(past->changes, "pivot.y"));
335         change_free(dictionary_lookup(past->changes, "pin.x"));
336         change_free(dictionary_lookup(past->changes, "pin.y"));
337         change_free(dictionary_lookup(past->changes, "blendmode"));
338         changeFilter_free(dictionary_lookup(past->changes, "filter"));
339         dictionary_destroy(past->changes);
340         free(past);
341 }
342
343 void history_init(history_t* past)
344 {
345         past->changes = (dictionary_t*)malloc(sizeof(dictionary_t));
346         dictionary_init(past->changes);
347 }
348
349 void history_begin(history_t* past, char* parameter, U16 frame, TAG* tag, float value)
350 {
351         change_t* first = change_new(frame, CF_PUT, value, 0);
352         past->firstTag = tag;
353         past->firstFrame = frame;
354         dictionary_put2(past->changes, parameter, first);
355 }
356
357 void history_beginFilter(history_t* past, U16 frame, TAG* tag, FILTER* value)
358 {
359         changeFilter_t* first = changeFilter_new(frame, CF_PUT, value, 0);
360         past->firstTag = tag;
361         past->firstFrame = frame;
362         dictionary_put2(past->changes, "filter", first);
363 }
364
365 void history_remember(history_t* past, char* parameter, U16 frame, int function, float value, interpolation_t* inter)
366 {
367         change_t* first = dictionary_lookup(past->changes, parameter);
368         if (first) //should always be true
369         {
370                 change_t* next = change_new(frame, function, value, inter);
371                 change_append(first, next);
372         }
373 }
374
375 void history_rememberFilter(history_t* past, U16 frame, int function, FILTER* value, interpolation_t* inter)
376 {
377         changeFilter_t* first = dictionary_lookup(past->changes, "filter");
378         if (first) //should always be true
379         {
380                 changeFilter_t* next = changeFilter_new(frame, function, value, inter);
381                 changeFilter_append(first, next);
382         }
383 }
384
385 float history_value(history_t* past, U16 frame, char* parameter)
386 {
387         change_t* first = dictionary_lookup(past->changes, parameter);
388         if (first)      //should always be true.
389                 return change_value(first, frame);
390         printf("no history found for parameter %s\n", parameter);
391         return 0;
392 }
393
394 FILTER* history_valueFilter(history_t* past, U16 frame)
395 {
396         changeFilter_t* first = dictionary_lookup(past->changes, "filter");
397         if (first)      //should always be true.
398                 return changeFilter_value(first, frame);
399         printf("no history found for parameter filter\n");
400         return 0;
401 }