Huub Schaek's filterlist 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     change_t* previous = 0;
52     change_t* start = first;
53     float p0, p1, m0, m1;
54
55         while (first->next)
56     {
57         previous = first;
58                 first = first->next;
59     }
60         first->next = newChange;
61     if (first->function == CF_QCHANGE)
62     {
63         p0 = previous->value;
64         p1 = first->value;
65         if (previous->function == CF_QCHANGE)
66             m0 = (3 * previous->spline.a + 2 * previous->spline.b + previous->spline.c);
67         else
68             if (previous->function == CF_CHANGE)
69                 m0 = (change_value(start, previous->frame) - change_value(start, previous->frame - 1)) * (first->frame - previous->frame);
70             else
71                 m0 = (first->value - previous->value);
72         if (newChange->function == CF_QCHANGE)
73             m1 = 0.5 * (newChange->value - previous->value);
74         else
75             if (newChange->function == CF_CHANGE)
76                 m1 = (change_value(previous, first->frame + 1) - change_value(previous, first->frame)) * (first->frame - previous->frame);
77             else
78                 m1 = (first->value - previous->value);
79         first->spline.a = 2 * p0 + m0 - 2 * p1 + m1;
80         first->spline.b = -3 * p0 - 2 * m0 + 3 * p1 - m1;
81         first->spline.c = m0;
82         first->spline.d = p0;
83     }
84     if (newChange->function == CF_QCHANGE)
85     {
86         p0 = first->value;
87         p1 = newChange->value;
88         if (first->function == CF_QCHANGE)
89             m0 = m1;
90         else
91             if (first->function == CF_CHANGE)
92                 m0 = (change_value(start, first->frame) - change_value(start, first->frame - 1)) * (first->frame - previous->frame);
93             else
94                 m0 = (newChange->value - first->value);
95         m1 = (newChange->value - first->value);
96         newChange->spline.a = 2 * p0 + m0 - 2 * p1 + m1;
97         newChange->spline.b = -3 * p0 - 2 * m0 + 3 * p1 - m1;
98         newChange->spline.c = m0;
99         newChange->spline.d = p0;
100     }
101 }
102
103 float calculateSpline(change_t* modification, float fraction)
104 {
105     spline_t s = modification->spline;
106     return (((s.a * fraction) + s.b) * fraction + s.c) * fraction + s.d;
107 }
108
109 float interpolateScalar(float p1, float p2, float fraction, interpolation_t* inter)
110 {
111         if (!inter)
112                 return linear(fraction, p1, p2 - p1);
113         switch (inter->function)
114         {
115                 case IF_LINEAR: return linear(fraction, p1, p2 - p1);
116                 case IF_QUAD_IN: return quadIn(fraction, p1, p2 - p1);
117                 case IF_QUAD_OUT: return quadOut(fraction, p1, p2 - p1);
118                 case IF_QUAD_IN_OUT: return quadInOut(fraction, p1, p2 - p1);
119                 case IF_CUBIC_IN: return cubicIn(fraction, p1, p2 - p1);
120                 case IF_CUBIC_OUT: return cubicOut(fraction, p1, p2 - p1);
121                 case IF_CUBIC_IN_OUT: return cubicInOut(fraction, p1, p2 - p1);
122                 case IF_QUART_IN: return quartIn(fraction, p1, p2 - p1);
123                 case IF_QUART_OUT: return quartOut(fraction, p1, p2 - p1);
124                 case IF_QUART_IN_OUT: return quartInOut(fraction, p1, p2 - p1);
125                 case IF_QUINT_IN: return quintIn(fraction, p1, p2 - p1);
126                 case IF_QUINT_OUT: return quintOut(fraction, p1, p2 - p1);
127                 case IF_QUINT_IN_OUT: return quintInOut(fraction, p1, p2 - p1);
128                 case IF_CIRCLE_IN: return circleIn(fraction, p1, p2 - p1);
129                 case IF_CIRCLE_OUT: return circleOut(fraction, p1, p2 - p1);
130                 case IF_CIRCLE_IN_OUT: return circleInOut(fraction, p1, p2 - p1);
131                 case IF_EXPONENTIAL_IN: return exponentialIn(fraction, p1, p2 - p1);
132                 case IF_EXPONENTIAL_OUT: return exponentialOut(fraction, p1, p2 - p1);
133                 case IF_EXPONENTIAL_IN_OUT: return exponentialInOut(fraction, p1, p2 - p1);
134                 case IF_SINE_IN: return sineIn(fraction, p1, p2 - p1);
135                 case IF_SINE_OUT: return sineOut(fraction, p1, p2 - p1);
136                 case IF_SINE_IN_OUT: return sineInOut(fraction, p1, p2 - p1);
137                 case IF_ELASTIC_IN: return elasticIn(fraction, p1, p2 - p1, inter->amplitude, inter->bounces, inter->damping);
138                 case IF_ELASTIC_OUT: return elasticOut(fraction, p1, p2 - p1, inter->amplitude, inter->bounces, inter->damping);
139                 case IF_ELASTIC_IN_OUT: return elasticInOut(fraction, p1, p2 - p1, inter->amplitude, inter->bounces, inter->damping);
140                 case IF_BACK_IN: return backIn(fraction, p1, p2 - p1, inter->speed);
141                 case IF_BACK_OUT: return backOut(fraction, p1, p2 - p1, inter->speed);
142                 case IF_BACK_IN_OUT: return backInOut(fraction, p1, p2 - p1, inter->speed);
143                 case IF_BOUNCE_IN: return bounceIn(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping);
144                 case IF_BOUNCE_OUT: return bounceOut(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping);
145                 case IF_BOUNCE_IN_OUT: return bounceInOut(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping);
146                 case IF_FAST_BOUNCE_IN: return fastBounceIn(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping);
147                 case IF_FAST_BOUNCE_OUT: return fastBounceOut(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping);
148                 case IF_FAST_BOUNCE_IN_OUT: return fastBounceInOut(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping);
149                 default: return linear(fraction, p1, p2 - p1);
150         }
151 }
152
153 int change_differs(change_t* modification, U16 frame)
154 {
155     change_t* previous = modification;
156     while (modification && modification->frame < frame)
157         {
158         previous = modification;
159         modification = modification->next;
160     }
161     if (!modification)
162         return 0;
163     if (modification->frame == frame)
164         return 1;
165     return (modification->function != CF_JUMP);
166         }
167
168 float change_value(change_t* modification, U16 frame)
169 {
170     change_t* previous = modification;
171     while (modification && modification->frame < frame)
172     {
173         previous = modification;
174         modification = modification->next;
175     }
176     if (!modification)
177                 return previous->value;
178     if (modification->frame == frame)
179         {
180                 do 
181                 {
182             previous = modification;
183             modification = modification->next;
184                 }
185         while (modification && modification->frame == frame);
186         return previous->value;
187         }
188     switch (modification->function)
189         {
190                 case CF_PUT:
191             return modification->value;
192                 case CF_CHANGE:
193                 {
194             float fraction = (frame - previous->frame) / (float)(modification->frame - previous->frame);
195             return interpolateScalar(previous->value, modification->value, fraction, modification->interpolation);
196         }
197         case CF_QCHANGE:
198         {
199             float fraction = (frame - previous->frame) / (float)(modification->frame - previous->frame);
200             return calculateSpline(modification, fraction);
201                 }
202                 case CF_JUMP:
203                         return previous->value;
204                 default:
205                         return 0;
206         }
207 }
208
209 changeFilter_t* changeFilter_new(U16 frame, int function, FILTERLIST* value, interpolation_t* inter)
210 {
211         changeFilter_t* newChange = (changeFilter_t*)malloc(sizeof(changeFilter_t));
212         changeFilter_init(newChange);
213         newChange->frame = frame;
214         newChange->function = function;
215         newChange->value = value;
216         newChange->interpolation = inter;
217         return newChange;
218 }
219
220 void changeFilter_free(changeFilter_t *change)
221 {
222         if (change->next)
223                 changeFilter_free(change->next);
224     free(change->value);
225         free(change);
226 }
227
228 void changeFilter_init(changeFilter_t* change)
229 {
230         memset(change, 0, sizeof(changeFilter_t));
231 }
232
233 void changeFilter_append(changeFilter_t* first, changeFilter_t* newChange)
234 {
235         while (first->next)
236                 first = first->next;
237     if (!first->value || !newChange->value)
238         first->next = newChange;
239     else
240     {
241         int i, mergedCount = 0;
242         int common = first->value->num < newChange->value->num ? first->value->num : newChange->value->num;
243         for (i = 0; i < common; i++)
244         {
245             mergedCount++;
246             if (newChange->value->filter[i]->type != first->value->filter[i]->type)
247                 mergedCount++;
248         }
249         mergedCount = mergedCount + first->value->num - common + newChange->value->num - common;
250         if (mergedCount > 8)
251         {
252             char* list1;
253             char* list2;
254             char* newList;
255             list1 = (char*)malloc(1);
256             *list1 = '\0';
257             for (i = 0; i < first->value->num; i++)
258             {
259                 newList = (char*)malloc(strlen(list1) + strlen(filtername[first->value->filter[i]->type]) + 2);
260                 newList = strcat(strcat(list1, "+"), filtername[first->value->filter[i]->type]);
261                 free(list1);
262                 list1 = newList;
263             }
264             list2 = (char*)malloc(1);
265             *list2 = '\0';
266             for (i = 0; i < newChange->value->num; i++)
267             {
268                 newList = (char*)malloc(strlen(list1) + strlen(filtername[newChange->value->filter[i]->type]) + 2);
269                 newList = strcat(strcat(list2, "+"), filtername[newChange->value->filter[i]->type]);
270                 free(list2);
271                 list2 = newList;
272             }
273             syntaxerror("filterlists %s and %s cannot be interpolated.", list1, list2);
274         }
275         first->next = newChange;
276     }
277 }
278
279 RGBA interpolateColor(RGBA c1, RGBA c2, float ratio, interpolation_t* inter)
280 {
281     RGBA c;
282     c.r = interpolateScalar(c1.r, c2.r, ratio, inter);
283     c.g = interpolateScalar(c1.g, c2.g, ratio, inter);
284     c.b = interpolateScalar(c1.b, c2.b, ratio, inter);
285     c.a = interpolateScalar(c1.a, c2.a, ratio, inter);
286     return c;
287 }
288
289 GRADIENT* interpolateNodes(GRADIENT* g1, GRADIENT* g2, float fraction, interpolation_t* inter)
290 {
291     if (g1->num != g2->num)
292         syntaxerror("Internal error: gradients are not equal in size");
293
294     int i;
295     GRADIENT* g = (GRADIENT*) malloc(sizeof(GRADIENT));
296     g->ratios = rfx_calloc(16*sizeof(U8));
297     g->rgba = rfx_calloc(16*sizeof(RGBA));
298     g->num = g1->num;
299     for (i = 0; i < g->num; i++)
300     {
301         g->ratios[i] = interpolateScalar(g1->ratios[i], g2->ratios[i], fraction, inter);
302         g->rgba[i] = interpolateColor(g1->rgba[i], g2->rgba[i], fraction, inter);
303     }
304     return g;
305 }
306
307 void copyGradient(GRADIENT* dest, GRADIENT* source)
308 {
309     dest->num = source->num;
310     memcpy(dest->ratios, source->ratios, source->num * sizeof(U8));
311     memcpy(dest->rgba, source->rgba, source->num * sizeof(RGBA));
312 }
313
314 void insertNode(GRADIENT* g, int pos)
315 {
316     memmove(&g->ratios[pos + 1], &g->ratios[pos], (g->num - pos) * sizeof(U8));
317     memmove(&g->rgba[pos + 1], &g->rgba[pos], (g->num - pos) * sizeof(RGBA));
318     if (pos == 0)
319     {
320         g->ratios[0] = g->ratios[1] / 2;
321         g->rgba[0] = g->rgba[1];
322     }
323     else
324         if (pos == g->num)
325         {
326             g->ratios[pos] = (255 + g->ratios[g->num - 1]) / 2;
327             g->rgba[pos] = g->rgba[pos - 1];
328         }
329         else
330         {
331             g->ratios[pos] = (g->ratios[pos - 1] + g->ratios[pos + 1]) / 2;
332             g->rgba[pos] = interpolateColor(g->rgba[pos - 1], g->rgba[pos + 1], 0.5, 0);
333         }
334     g->num++;
335 }
336
337 void insertOptimalNode(GRADIENT* g)
338 {
339     int i, next_gap;
340     int pos = 0;
341     int gap = g->ratios[0];
342     for (i = 0; i < g->num - 1; i++)
343     {
344         next_gap = g->ratios[i + 1] - g->ratios[i];
345         if (next_gap > gap)
346         {
347             gap = next_gap;
348             pos = i + 1;
349         }
350     }
351     next_gap = 255 - g->ratios[g->num -1];
352     if (next_gap > gap)
353         pos = g->num;
354     insertNode(g, pos);
355 }
356    
357 void growGradient(GRADIENT* start, int size)
358 {
359     while (start->num < size)
360         insertOptimalNode(start);
361 }
362
363 GRADIENT* interpolateGradient(GRADIENT* g1, GRADIENT* g2, float fraction, interpolation_t* inter)
364 {
365     int i;
366     GRADIENT g;
367     g.ratios = rfx_calloc(16*sizeof(U8));
368     g.rgba = rfx_calloc(16*sizeof(RGBA));
369
370     if (g1->num > g2->num)
371     {
372         copyGradient(&g, g2);
373         growGradient(&g, g1->num);
374         GRADIENT* result = interpolateNodes(g1, &g, fraction, inter);
375         rfx_free(g.rgba);
376         rfx_free(g.ratios);
377         return result;
378     }
379     else
380         if (g1->num < g2->num)
381         {
382             copyGradient(&g, g1);
383             growGradient(&g, g2->num);
384             GRADIENT* result = interpolateNodes(&g, g2, fraction, inter);
385             rfx_free(g.rgba);
386             rfx_free(g.ratios);
387             return result;
388         }
389         else
390             return interpolateNodes(g1, g2, fraction, inter);
391 }
392
393 FILTER* copyFilter(FILTER* original)
394 {
395     if (!original)
396         return original;
397     FILTER* copy = swf_NewFilter(original->type);
398     switch (original->type)
399     {
400         case FILTERTYPE_BLUR:
401             memcpy(copy, original, sizeof(FILTER_BLUR));
402             break;
403         case FILTERTYPE_GRADIENTGLOW:
404         {
405             memcpy(copy, original, sizeof(FILTER_GRADIENTGLOW));
406             FILTER_GRADIENTGLOW* ggcopy = (FILTER_GRADIENTGLOW*)copy;
407             ggcopy->gradient = (GRADIENT*)malloc(sizeof(GRADIENT));
408             ggcopy->gradient->ratios = (U8*)malloc(16 * sizeof(U8));
409             ggcopy->gradient->rgba = (RGBA*)malloc(16 * sizeof(RGBA));
410             copyGradient(ggcopy->gradient, ((FILTER_GRADIENTGLOW*)original)->gradient);
411         }
412             break;
413         case FILTERTYPE_DROPSHADOW:
414             memcpy(copy, original, sizeof(FILTER_DROPSHADOW));
415             break;
416         case FILTERTYPE_BEVEL:
417             memcpy(copy, original, sizeof(FILTER_BEVEL));
418             break;
419         default: syntaxerror("Internal error: unsupported filterype, cannot copy");
420     }
421     return copy;
422 }
423
424 FILTER* interpolateBlur(FILTER* filter1, FILTER* filter2, float ratio, interpolation_t* inter)
425         {
426                 FILTER_BLUR*f1 = (FILTER_BLUR*)filter1;
427                 FILTER_BLUR*f2 = (FILTER_BLUR*)filter2;
428     if (!f1)
429         f1 = noBlur;
430     if (!f2)
431         f2 = noBlur;
432     if(f1->blurx == f2->blurx && f1->blury == f2->blury)
433         return copyFilter(filter1);
434                 FILTER_BLUR*f = (FILTER_BLUR*)swf_NewFilter(FILTERTYPE_BLUR);
435     f->blurx= interpolateScalar(f1->blurx, (f2->blurx), ratio, inter);
436     f->blury= interpolateScalar(f1->blury, (f2->blury), ratio, inter);
437     f->passes= interpolateScalar(f1->passes, (f2->passes), ratio, inter);
438                 return (FILTER*)f;
439                 }
440
441 void matchDropshadowFlags(FILTER_DROPSHADOW* unset, FILTER_DROPSHADOW* target)
442 {
443     unset->innershadow = target->innershadow;
444     unset->knockout = target->knockout;
445     unset->composite = target->composite;
446 }
447
448 FILTER* interpolateDropshadow(FILTER* filter1,FILTER* filter2, float ratio, interpolation_t* inter)
449                 {
450                         FILTER_DROPSHADOW*f1 = (FILTER_DROPSHADOW*)filter1;
451                         FILTER_DROPSHADOW*f2 = (FILTER_DROPSHADOW*)filter2;
452     if (!f1)
453         f1 = noDropshadow;
454     if (!f2)
455         f2 = noDropshadow;
456     if(!memcmp(&f1->color,&f2->color,sizeof(RGBA)) && f1->strength == f2->strength &&
457                                 f1->blurx == f2->blurx && f1->blury == f2->blury && 
458                                 f1->angle == f2->angle && f1->distance == f2->distance)
459                 return copyFilter(filter1);
460                         FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)swf_NewFilter(FILTERTYPE_DROPSHADOW);
461                         memcpy(f, f1, sizeof(FILTER_DROPSHADOW));
462                         f->color = interpolateColor(f1->color, f2->color, ratio, inter);
463     f->blurx= interpolateScalar(f1->blurx, (f2->blurx), ratio, inter);
464     f->blury= interpolateScalar(f1->blury, (f2->blury), ratio, inter);
465     f->passes= interpolateScalar(f1->passes, (f2->passes), ratio, inter);
466     f->angle= interpolateScalar(f1->angle, (f2->angle), ratio, inter);
467     f->distance= interpolateScalar(f1->distance, (f2->distance), ratio, inter);
468     f->strength= interpolateScalar(f1->strength, (f2->strength), ratio, inter);
469     if (f1 == noDropshadow)
470     {
471         if (f2 != noDropshadow)
472             matchDropshadowFlags(f, f2);
473                 }
474                 else
475         if (f2 == noDropshadow)
476             matchDropshadowFlags(f, f1);
477         else
478             if (ratio > 0.5)
479                 matchDropshadowFlags(f, f2);
480             else
481                 matchDropshadowFlags(f, f1);
482     return (FILTER*)f;
483 }
484
485 void matchBevelFlags(FILTER_BEVEL* unset, FILTER_BEVEL* target)
486 {
487     unset->innershadow = target->innershadow;
488     unset->knockout = target->knockout;
489     unset->composite = target->composite;
490     unset->ontop = target->ontop;
491 }
492
493 FILTER* interpolateBevel(FILTER* filter1,FILTER* filter2, float ratio, interpolation_t* inter)
494                         {
495                                 FILTER_BEVEL*f1 = (FILTER_BEVEL*)filter1;
496                                 FILTER_BEVEL*f2 = (FILTER_BEVEL*)filter2;
497     if (!f1)
498         f1 = noBevel;
499     if (!f2)
500         f2 = noBevel;
501     if(!memcmp(&f1->shadow,&f2->shadow,sizeof(RGBA)) &&
502                                         !memcmp(&f1->highlight,&f2->highlight,sizeof(RGBA)) && 
503                                         f1->blurx == f2->blurx && f1->blury == f2->blury && f1->angle == f2->angle && f1->strength == f2->strength && f1->distance == f2->distance)
504                 return copyFilter(filter1);
505                                 FILTER_BEVEL*f = (FILTER_BEVEL*)swf_NewFilter(FILTERTYPE_BEVEL);
506                                 memcpy(f, f1, sizeof(FILTER_BEVEL));
507                                 f->shadow = interpolateColor(f1->shadow, f2->shadow, ratio, inter);
508                                 f->highlight = interpolateColor(f1->highlight, f2->highlight, ratio, inter);
509     f->blurx= interpolateScalar(f1->blurx, (f2->blurx), ratio, inter);
510     f->blury= interpolateScalar(f1->blury, (f2->blury), ratio, inter);
511     f->passes= interpolateScalar(f1->passes, (f2->passes), ratio, inter);
512     f->angle= interpolateScalar(f1->angle, (f2->angle), ratio, inter);
513     f->distance= interpolateScalar(f1->distance, (f2->distance), ratio, inter);
514     f->strength= interpolateScalar(f1->strength, (f2->strength), ratio, inter);
515     if (f1 == noBevel)
516     {
517         if (f2 != noBevel)
518             matchBevelFlags(f, f2);
519     }
520     else
521         if (f2 == noBevel)
522             matchBevelFlags(f, f1);
523         else
524             if (ratio > 0.5)
525                 matchBevelFlags(f, f2);
526             else
527                 matchBevelFlags(f, f1);
528                                 return (FILTER*)f;
529 }
530
531 void matchGradientGlowFlags(FILTER_GRADIENTGLOW* unset, FILTER_GRADIENTGLOW* target)
532 {
533     unset->innershadow = target->innershadow;
534     unset->knockout = target->knockout;
535     unset->composite = target->composite;
536     unset->ontop = target->ontop;
537 }
538
539 FILTER* interpolateGradientGlow(FILTER* filter1,FILTER* filter2, float ratio, interpolation_t* inter)
540 {
541     FILTER_GRADIENTGLOW*f1 = (FILTER_GRADIENTGLOW*)filter1;
542     FILTER_GRADIENTGLOW*f2 = (FILTER_GRADIENTGLOW*)filter2;
543     if (!f1)
544         f1 = noGradientGlow;
545     if (!f2)
546         f2 = noGradientGlow;
547     if(f1->gradient->num == f2->gradient->num &&
548                 !memcmp(&f1->gradient->ratios,&f2->gradient->ratios,f1->gradient->num * sizeof(U8)) &&
549                 !memcmp(&f1->gradient->rgba,&f2->gradient->rgba,f1->gradient->num * sizeof(RGBA)) &&
550                 f1->blurx == f2->blurx && f1->blury == f2->blury && f1->angle == f2->angle && f1->strength == f2->strength && f1->distance == f2->distance)
551                 return copyFilter(filter1);
552         FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
553     memcpy(f, f1, sizeof(FILTER_GRADIENTGLOW));
554     f->blurx= interpolateScalar(f1->blurx, (f2->blurx), ratio, inter);
555     f->blury= interpolateScalar(f1->blury, (f2->blury), ratio, inter);
556     f->passes= interpolateScalar(f1->passes, (f2->passes), ratio, inter);
557     f->angle= interpolateScalar(f1->angle, (f2->angle), ratio, inter);
558     f->distance= interpolateScalar(f1->distance, (f2->distance), ratio, inter);
559     f->strength= interpolateScalar(f1->strength, (f2->strength), ratio, inter);
560     f->gradient= interpolateGradient(f1->gradient, f2->gradient, ratio, inter);
561     if (f1 == noGradientGlow)
562     {
563         if (f2 != noGradientGlow)
564             matchGradientGlowFlags(f, f2);
565     }
566     else
567         if (f2 == noGradientGlow)
568             matchGradientGlowFlags(f, f1);
569         else
570             if (ratio > 0.5)
571                 matchGradientGlowFlags(f, f2);
572             else
573                 matchGradientGlowFlags(f, f1);
574         return (FILTER*)f;
575 }
576
577 FILTER* interpolateFilter(FILTER* filter1,FILTER* filter2, float ratio, interpolation_t* inter)
578 {
579     if(!filter1 && !filter2)
580         return 0;
581
582     int filter_type;
583     if (!filter1)
584         filter_type = filter2->type;
585     else
586         if (!filter2)
587             filter_type = filter1->type;
588         else
589             if(filter2->type != filter1->type)
590                 syntaxerror("can't interpolate between %s and %s filters yet", filtername[filter1->type], filtername[filter2->type]);
591             else
592                 filter_type = filter1->type;
593
594     switch (filter_type)
595     {
596         case FILTERTYPE_BLUR:
597             return interpolateBlur(filter1, filter2, ratio, inter);
598         case FILTERTYPE_BEVEL:
599             return interpolateBevel(filter1, filter2, ratio, inter);
600         case FILTERTYPE_DROPSHADOW:
601             return interpolateDropshadow(filter1, filter2, ratio, inter);
602         case FILTERTYPE_GRADIENTGLOW:
603             return interpolateGradientGlow(filter1, filter2, ratio, inter);
604         default:
605             syntaxerror("Filtertype %s not supported yet.\n", filtername[filter1->type]);
606     }
607         return 0;
608 }
609
610 FILTERLIST* copyFilterList(FILTERLIST* original)
611 {
612         if (!original)
613                 return original;
614     int i;
615     FILTERLIST* copy = (FILTERLIST*)malloc(sizeof(FILTERLIST));
616     copy->num = original->num;
617     for (i = 0; i < copy->num; i++)
618         copy->filter[i] = copyFilter(original->filter[i]);
619     return copy;
620 }
621
622 FILTER* noFilter(int type)
623 {
624     switch (type)
625         {
626                 case FILTERTYPE_BLUR:
627             return (FILTER*)noBlur;
628                         break;
629         case FILTERTYPE_BEVEL:
630             return (FILTER*)noBevel;
631                         break;
632                 case FILTERTYPE_DROPSHADOW:
633             return (FILTER*)noDropshadow;
634                         break;
635         case FILTERTYPE_GRADIENTGLOW:
636             return (FILTER*)noGradientGlow;
637                         break;
638         default:
639             syntaxerror("Internal error: unsupported filtertype, cannot match filterlists");
640         }
641     return 0;
642 }
643
644 FILTERLIST* interpolateFilterList(FILTERLIST* list1, FILTERLIST* list2, float ratio, interpolation_t* inter)
645 {
646     if (!list1 && !list2)
647         return list1;
648     FILTERLIST start, target, dummy;
649     dummy.num = 0;
650     if (!list1)
651         list1 = &dummy;
652     if (!list2)
653         list2 = &dummy;
654     int i, j = 0;
655     int common = list1->num < list2->num ? list1->num : list2->num;
656         for (i = 0; i < common; i++)
657     {
658         start.filter[j] = list1->filter[i];
659         if (list2->filter[i]->type == list1->filter[i]->type)
660         {
661             target.filter[j] = list2->filter[i];
662             j++;
663         }
664         else
665         {
666             target.filter[j] = noFilter(list1->filter[i]->type);
667             j++;
668             start.filter[j] = noFilter(list2->filter[i]->type);
669             target.filter[j] = list2->filter[i];
670             j++;
671         }
672     }
673     if (list1->num > common)
674         for (i = common; i < list1->num; i++)
675         {
676             start.filter[j] = list1->filter[i];
677             target.filter[j] = noFilter(list1->filter[i]->type);
678             j++;
679         }
680     if (list2->num > common)
681         for (i = common; i < list2->num; i++)
682         {
683             start.filter[j] = noFilter(list2->filter[i]->type);
684             target.filter[j] = list2->filter[i];
685             j++;
686         }
687     start.num = j;
688     target.num = j;
689     FILTERLIST* mixedList = (FILTERLIST*)malloc(sizeof(FILTERLIST));
690     mixedList->num = j;
691     for (i = 0; i < j; i++)
692         mixedList->filter[i] = interpolateFilter(start.filter[i], target.filter[i], ratio, inter);
693     return mixedList;
694 }
695
696 int changeFilter_differs(changeFilter_t* modification, U16 frame)
697 {
698     changeFilter_t* previous = modification;
699     while (modification && modification->frame < frame)
700         {
701         previous = modification;
702         modification = modification->next;
703         }
704     if (!modification)
705         return 0;
706     if (modification->frame == frame)
707         return 1;
708     return (modification->function != CF_JUMP);
709 }
710
711 FILTERLIST* changeFilter_value(changeFilter_t* modification, U16 frame)
712 {
713     changeFilter_t* previous = modification;
714     while (modification && modification->frame < frame)
715     {
716         previous = modification;
717         modification = modification->next;
718     }
719     if (!modification)
720         return copyFilterList(previous->value);
721     if (modification->frame == frame)
722         {
723                 do 
724                 {
725             previous = modification;
726             modification = modification->next;
727                 }
728         while (modification && modification->frame == frame);
729         return copyFilterList(previous->value);
730         }
731     switch (modification->function)
732         {
733                 case CF_PUT:
734             return copyFilterList(modification->value);
735                 case CF_CHANGE:
736                 {
737             float fraction = (frame - previous->frame) / (float)(modification->frame - previous->frame);
738             return interpolateFilterList(previous->value, modification->value, fraction, modification->interpolation);
739                 }
740                 case CF_JUMP:
741             return copyFilterList(previous->value);
742                 default:
743                         return 0;
744         }
745 }
746
747 history_t* history_new()
748 {
749         history_t* newHistory = (history_t*)malloc(sizeof(history_t));
750         history_init(newHistory);
751         return newHistory;
752 }
753
754 void history_free(history_t* past)
755 {
756         change_free(dictionary_lookup(past->changes, "x"));
757         change_free(dictionary_lookup(past->changes, "y"));
758         change_free(dictionary_lookup(past->changes, "scalex"));
759         change_free(dictionary_lookup(past->changes, "scaley"));
760         change_free(dictionary_lookup(past->changes, "cxform.r0"));
761         change_free(dictionary_lookup(past->changes, "cxform.g0"));
762         change_free(dictionary_lookup(past->changes, "cxform.b0"));
763         change_free(dictionary_lookup(past->changes, "cxform.a0"));
764         change_free(dictionary_lookup(past->changes, "cxform.r1"));
765         change_free(dictionary_lookup(past->changes, "cxform.g1"));
766         change_free(dictionary_lookup(past->changes, "cxform.b1"));
767         change_free(dictionary_lookup(past->changes, "cxform.a1"));
768         change_free(dictionary_lookup(past->changes, "rotate"));
769         change_free(dictionary_lookup(past->changes, "shear"));
770         change_free(dictionary_lookup(past->changes, "pivot.x"));
771         change_free(dictionary_lookup(past->changes, "pivot.y"));
772         change_free(dictionary_lookup(past->changes, "pin.x"));
773         change_free(dictionary_lookup(past->changes, "pin.y"));
774         change_free(dictionary_lookup(past->changes, "blendmode"));
775         changeFilter_free(dictionary_lookup(past->changes, "filter"));
776         dictionary_destroy(past->changes);
777         free(past);
778 }
779
780 void history_init(history_t* past)
781 {
782         past->changes = (dictionary_t*)malloc(sizeof(dictionary_t));
783         dictionary_init(past->changes);
784 }
785
786 void history_begin(history_t* past, char* parameter, U16 frame, TAG* tag, float value)
787 {
788         change_t* first = change_new(frame, CF_PUT, value, 0);
789         past->firstTag = tag;
790         past->firstFrame = frame;
791         dictionary_put2(past->changes, parameter, first);
792 }
793
794 void history_beginFilter(history_t* past, U16 frame, TAG* tag, FILTERLIST* value)
795 {
796         changeFilter_t* first = changeFilter_new(frame, CF_PUT, value, 0);
797         past->firstTag = tag;
798         past->firstFrame = frame;
799         dictionary_put2(past->changes, "filter", first);
800 }
801
802 void history_remember(history_t* past, char* parameter, U16 frame, int function, float value, interpolation_t* inter)
803 {
804         change_t* first = dictionary_lookup(past->changes, parameter);
805         if (first) //should always be true
806         {
807                 change_t* next = change_new(frame, function, value, inter);
808                 change_append(first, next);
809         }
810 }
811
812 void history_rememberFilter(history_t* past, U16 frame, int function, FILTERLIST* value, interpolation_t* inter)
813 {
814         changeFilter_t* first = dictionary_lookup(past->changes, "filter");
815         if (first) //should always be true
816         {
817                 changeFilter_t* next = changeFilter_new(frame, function, value, inter);
818                 changeFilter_append(first, next);
819         }
820 }
821
822 int history_change(history_t* past, U16 frame, char* parameter)
823 {
824     change_t* first = dictionary_lookup(past->changes, parameter);
825     if (first)  //should always be true.
826         return change_differs(first, frame);
827     printf("no history found for parameter %s\n", parameter);
828     return 0;
829 }
830
831 float history_value(history_t* past, U16 frame, char* parameter)
832 {
833         change_t* first = dictionary_lookup(past->changes, parameter);
834         if (first)      //should always be true.
835                 return change_value(first, frame);
836         printf("no history found for parameter %s\n", parameter);
837         return 0;
838 }
839
840 int history_changeFilter(history_t* past, U16 frame)
841 {
842     changeFilter_t* first = dictionary_lookup(past->changes, "filter");
843     if (first)  //should always be true.
844         return changeFilter_differs(first, frame);
845     printf("no history found for parameter filter\n");
846     return 0;
847 }
848
849 FILTERLIST* history_valueFilter(history_t* past, U16 frame)
850 {
851         changeFilter_t* first = dictionary_lookup(past->changes, "filter");
852         if (first)      //should always be true.
853                 return changeFilter_value(first, frame);
854         printf("no history found for parameter filter\n");
855         return 0;
856 }