Huub Schaek's interpolation 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, FILTER* 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);
225 }
226
227 void changeFilter_init(changeFilter_t* change)
228 {
229         memset(change, 0, sizeof(changeFilter_t));
230 }
231
232 void changeFilter_append(changeFilter_t* first, changeFilter_t* newChange)
233 {
234         while (first->next)
235                 first = first->next;
236         first->next = newChange;
237 }
238
239 RGBA interpolateColor(RGBA c1, RGBA c2, float ratio, interpolation_t* inter)
240 {
241     RGBA c;
242     c.r = interpolateScalar(c1.r, c2.r, ratio, inter);
243     c.g = interpolateScalar(c1.g, c2.g, ratio, inter);
244     c.b = interpolateScalar(c1.b, c2.b, ratio, inter);
245     c.a = interpolateScalar(c1.a, c2.a, ratio, inter);
246     return c;
247 }
248
249 GRADIENT* interpolateNodes(GRADIENT* g1, GRADIENT* g2, float fraction, interpolation_t* inter)
250 {
251     if (g1->num != g2->num)
252         syntaxerror("Internal error: gradients are not equal in size");
253
254     int i;
255     GRADIENT* g = (GRADIENT*) malloc(sizeof(GRADIENT));
256     g->ratios = rfx_calloc(16*sizeof(U8));
257     g->rgba = rfx_calloc(16*sizeof(RGBA));
258     g->num = g1->num;
259     for (i = 0; i < g->num; i++)
260     {
261         g->ratios[i] = interpolateScalar(g1->ratios[i], g2->ratios[i], fraction, inter);
262         g->rgba[i] = interpolateColor(g1->rgba[i], g2->rgba[i], fraction, inter);
263     }
264     return g;
265 }
266
267 void copyGradient(GRADIENT* dest, GRADIENT* source)
268 {
269     dest->num = source->num;
270     memcpy(dest->ratios, source->ratios, source->num * sizeof(U8));
271     memcpy(dest->rgba, source->rgba, source->num * sizeof(RGBA));
272 }
273
274 void insertNode(GRADIENT* g, int pos)
275 {
276     memmove(&g->ratios[pos + 1], &g->ratios[pos], (g->num - pos) * sizeof(U8));
277     memmove(&g->rgba[pos + 1], &g->rgba[pos], (g->num - pos) * sizeof(RGBA));
278     if (pos == 0)
279     {
280         g->ratios[0] = g->ratios[1] / 2;
281         g->rgba[0] = g->rgba[1];
282     }
283     else
284         if (pos == g->num)
285         {
286             g->ratios[pos] = (255 + g->ratios[g->num - 1]) / 2;
287             g->rgba[pos] = g->rgba[pos - 1];
288         }
289         else
290         {
291             g->ratios[pos] = (g->ratios[pos - 1] + g->ratios[pos + 1]) / 2;
292             g->rgba[pos] = interpolateColor(g->rgba[pos - 1], g->rgba[pos + 1], 0.5, 0);
293         }
294     g->num++;
295 }
296
297 void insertOptimalNode(GRADIENT* g)
298 {
299     int i, next_gap;
300     int pos = 0;
301     int gap = g->ratios[0];
302     for (i = 0; i < g->num - 1; i++)
303     {
304         next_gap = g->ratios[i + 1] - g->ratios[i];
305         if (next_gap > gap)
306         {
307             gap = next_gap;
308             pos = i + 1;
309         }
310     }
311     next_gap = 255 - g->ratios[g->num -1];
312     if (next_gap > gap)
313         pos = g->num;
314     insertNode(g, pos);
315 }
316    
317 void growGradient(GRADIENT* start, int size)
318 {
319     while (start->num < size)
320         insertOptimalNode(start);
321 }
322
323 GRADIENT* interpolateGradient(GRADIENT* g1, GRADIENT* g2, float fraction, interpolation_t* inter)
324 {
325     int i;
326     GRADIENT g;
327     g.ratios = rfx_calloc(16*sizeof(U8));
328     g.rgba = rfx_calloc(16*sizeof(RGBA));
329
330     if (g1->num > g2->num)
331     {
332         copyGradient(&g, g2);
333         growGradient(&g, g1->num);
334         GRADIENT* result = interpolateNodes(g1, &g, fraction, inter);
335         rfx_free(g.rgba);
336         rfx_free(g.ratios);
337         return result;
338     }
339     else
340         if (g1->num < g2->num)
341         {
342             copyGradient(&g, g1);
343             growGradient(&g, g2->num);
344             GRADIENT* result = interpolateNodes(&g, g2, fraction, inter);
345             rfx_free(g.rgba);
346             rfx_free(g.ratios);
347             return result;
348         }
349         else
350             return interpolateNodes(g1, g2, fraction, inter);
351 }
352
353 FILTER* interpolateBlur(FILTER* filter1, FILTER* filter2, float ratio, interpolation_t* inter)
354         {
355                 FILTER_BLUR*f1 = (FILTER_BLUR*)filter1;
356                 FILTER_BLUR*f2 = (FILTER_BLUR*)filter2;
357     if (!f1)
358         f1 = noBlur;
359     if (!f2)
360         f2 = noBlur;
361     if(f1->blurx == f2->blurx && f1->blury == f2->blury)
362                         return 0;
363                 FILTER_BLUR*f = (FILTER_BLUR*)swf_NewFilter(FILTERTYPE_BLUR);
364     f->blurx= interpolateScalar(f1->blurx, (f2->blurx), ratio, inter);
365     f->blury= interpolateScalar(f1->blury, (f2->blury), ratio, inter);
366     f->passes= interpolateScalar(f1->passes, (f2->passes), ratio, inter);
367                 return (FILTER*)f;
368                 }
369
370 void matchDropshadowFlags(FILTER_DROPSHADOW* unset, FILTER_DROPSHADOW* target)
371 {
372     unset->innershadow = target->innershadow;
373     unset->knockout = target->knockout;
374     unset->composite = target->composite;
375 }
376
377 FILTER* interpolateDropshadow(FILTER* filter1,FILTER* filter2, float ratio, interpolation_t* inter)
378                 {
379                         FILTER_DROPSHADOW*f1 = (FILTER_DROPSHADOW*)filter1;
380                         FILTER_DROPSHADOW*f2 = (FILTER_DROPSHADOW*)filter2;
381     if (!f1)
382         f1 = noDropshadow;
383     if (!f2)
384         f2 = noDropshadow;
385     if(!memcmp(&f1->color,&f2->color,sizeof(RGBA)) && f1->strength == f2->strength &&
386                                 f1->blurx == f2->blurx && f1->blury == f2->blury && 
387                                 f1->angle == f2->angle && f1->distance == f2->distance)
388                                 return 0;
389                         FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)swf_NewFilter(FILTERTYPE_DROPSHADOW);
390                         memcpy(f, f1, sizeof(FILTER_DROPSHADOW));
391                         f->color = interpolateColor(f1->color, f2->color, ratio, inter);
392     f->blurx= interpolateScalar(f1->blurx, (f2->blurx), ratio, inter);
393     f->blury= interpolateScalar(f1->blury, (f2->blury), ratio, inter);
394     f->passes= interpolateScalar(f1->passes, (f2->passes), ratio, inter);
395     f->angle= interpolateScalar(f1->angle, (f2->angle), ratio, inter);
396     f->distance= interpolateScalar(f1->distance, (f2->distance), ratio, inter);
397     f->strength= interpolateScalar(f1->strength, (f2->strength), ratio, inter);
398     if (f1 == noDropshadow)
399     {
400         if (f2 != noDropshadow)
401             matchDropshadowFlags(f, f2);
402                 }
403                 else
404         if (f2 == noDropshadow)
405             matchDropshadowFlags(f, f1);
406         else
407             if (ratio > 0.5)
408                 matchDropshadowFlags(f, f2);
409             else
410                 matchDropshadowFlags(f, f1);
411     return (FILTER*)f;
412 }
413
414 void matchBevelFlags(FILTER_BEVEL* unset, FILTER_BEVEL* target)
415 {
416     unset->innershadow = target->innershadow;
417     unset->knockout = target->knockout;
418     unset->composite = target->composite;
419     unset->ontop = target->ontop;
420 }
421
422 FILTER* interpolateBevel(FILTER* filter1,FILTER* filter2, float ratio, interpolation_t* inter)
423                         {
424                                 FILTER_BEVEL*f1 = (FILTER_BEVEL*)filter1;
425                                 FILTER_BEVEL*f2 = (FILTER_BEVEL*)filter2;
426     if (!f1)
427         f1 = noBevel;
428     if (!f2)
429         f2 = noBevel;
430     if(!memcmp(&f1->shadow,&f2->shadow,sizeof(RGBA)) &&
431                                         !memcmp(&f1->highlight,&f2->highlight,sizeof(RGBA)) && 
432                                         f1->blurx == f2->blurx && f1->blury == f2->blury && f1->angle == f2->angle && f1->strength == f2->strength && f1->distance == f2->distance)
433                                         return 0;
434                                 FILTER_BEVEL*f = (FILTER_BEVEL*)swf_NewFilter(FILTERTYPE_BEVEL);
435                                 memcpy(f, f1, sizeof(FILTER_BEVEL));
436                                 f->shadow = interpolateColor(f1->shadow, f2->shadow, ratio, inter);
437                                 f->highlight = interpolateColor(f1->highlight, f2->highlight, ratio, inter);
438     f->blurx= interpolateScalar(f1->blurx, (f2->blurx), ratio, inter);
439     f->blury= interpolateScalar(f1->blury, (f2->blury), ratio, inter);
440     f->passes= interpolateScalar(f1->passes, (f2->passes), ratio, inter);
441     f->angle= interpolateScalar(f1->angle, (f2->angle), ratio, inter);
442     f->distance= interpolateScalar(f1->distance, (f2->distance), ratio, inter);
443     f->strength= interpolateScalar(f1->strength, (f2->strength), ratio, inter);
444     if (f1 == noBevel)
445     {
446         if (f2 != noBevel)
447             matchBevelFlags(f, f2);
448     }
449     else
450         if (f2 == noBevel)
451             matchBevelFlags(f, f1);
452         else
453             if (ratio > 0.5)
454                 matchBevelFlags(f, f2);
455             else
456                 matchBevelFlags(f, f1);
457                                 return (FILTER*)f;
458 }
459
460 void matchGradientGlowFlags(FILTER_GRADIENTGLOW* unset, FILTER_GRADIENTGLOW* target)
461 {
462     unset->innershadow = target->innershadow;
463     unset->knockout = target->knockout;
464     unset->composite = target->composite;
465     unset->ontop = target->ontop;
466 }
467
468 FILTER* interpolateGradientGlow(FILTER* filter1,FILTER* filter2, float ratio, interpolation_t* inter)
469 {
470     FILTER_GRADIENTGLOW*f1 = (FILTER_GRADIENTGLOW*)filter1;
471     FILTER_GRADIENTGLOW*f2 = (FILTER_GRADIENTGLOW*)filter2;
472     if (!f1)
473         f1 = noGradientGlow;
474     if (!f2)
475         f2 = noGradientGlow;
476     if(f1->gradient->num == f2->gradient->num &&
477                 !memcmp(&f1->gradient->ratios,&f2->gradient->ratios,f1->gradient->num * sizeof(U8)) &&
478                 !memcmp(&f1->gradient->rgba,&f2->gradient->rgba,f1->gradient->num * sizeof(RGBA)) &&
479                 f1->blurx == f2->blurx && f1->blury == f2->blury && f1->angle == f2->angle && f1->strength == f2->strength && f1->distance == f2->distance)
480                 return 0;
481         FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
482     memcpy(f, f1, sizeof(FILTER_GRADIENTGLOW));
483     f->blurx= interpolateScalar(f1->blurx, (f2->blurx), ratio, inter);
484     f->blury= interpolateScalar(f1->blury, (f2->blury), ratio, inter);
485     f->passes= interpolateScalar(f1->passes, (f2->passes), ratio, inter);
486     f->angle= interpolateScalar(f1->angle, (f2->angle), ratio, inter);
487     f->distance= interpolateScalar(f1->distance, (f2->distance), ratio, inter);
488     double d = f->distance;
489     double fr;
490     if (d < 0)
491         fr = ((int)d - d)*65536;
492     else
493         fr = (d - (int)d)*65536;
494         printf("%.3f <> %.3f : %.3f = %.3f [%.3f . %.3f] - %.5u.%.5u\n", f1->distance, f2->distance, ratio, f->distance, d, fr/65536, (U16)d, (U16)fr);
495     f->strength= interpolateScalar(f1->strength, (f2->strength), ratio, inter);
496     f->gradient= interpolateGradient(f1->gradient, f2->gradient, ratio, inter);
497     if (f1 == noGradientGlow)
498     {
499         if (f2 != noGradientGlow)
500             matchGradientGlowFlags(f, f2);
501     }
502     else
503         if (f2 == noGradientGlow)
504             matchGradientGlowFlags(f, f1);
505         else
506             if (ratio > 0.5)
507                 matchGradientGlowFlags(f, f2);
508             else
509                 matchGradientGlowFlags(f, f1);
510         return (FILTER*)f;
511 }
512
513 FILTER* interpolateFilter(FILTER* filter1,FILTER* filter2, float ratio, interpolation_t* inter)
514 {
515     if(!filter1 && !filter2)
516         return 0;
517
518
519     int filter_type;
520     if (!filter1)
521         filter_type = filter2->type;
522     else
523         if (!filter2)
524             filter_type = filter1->type;
525         else
526             if(filter2->type != filter1->type)
527                 syntaxerror("can't interpolate between %s and %s filters yet", filtername[filter1->type], filtername[filter2->type]);
528             else
529                 filter_type = filter1->type;
530
531
532     switch (filter_type)
533     {
534         case FILTERTYPE_BLUR:
535             return interpolateBlur(filter1, filter2, ratio, inter);
536         case FILTERTYPE_BEVEL:
537             return interpolateBevel(filter1, filter2, ratio, inter);
538         case FILTERTYPE_DROPSHADOW:
539             return interpolateDropshadow(filter1, filter2, ratio, inter);
540         case FILTERTYPE_GRADIENTGLOW:
541             return interpolateGradientGlow(filter1, filter2, ratio, inter);
542         default:
543             syntaxerror("Filtertype %s not supported yet.\n", filtername[filter1->type]);
544     }
545         return 0;
546 }
547
548 FILTER* copyFilter(FILTER* original)
549 {
550         if (!original)
551                 return original;
552         FILTER* copy = swf_NewFilter(original->type);
553         switch (original->type)
554         {
555                 case FILTERTYPE_BLUR:
556                         memcpy(copy, original, sizeof(FILTER_BLUR));
557                         break;
558                 case FILTERTYPE_GRADIENTGLOW:
559         {
560                         memcpy(copy, original, sizeof(FILTER_GRADIENTGLOW));
561             FILTER_GRADIENTGLOW* ggcopy = (FILTER_GRADIENTGLOW*)copy;
562             ggcopy->gradient = (GRADIENT*)malloc(sizeof(GRADIENT));
563             ggcopy->gradient->ratios = (U8*)malloc(16 * sizeof(U8));
564             ggcopy->gradient->rgba = (RGBA*)malloc(16 * sizeof(RGBA));
565             copyGradient(ggcopy->gradient, ((FILTER_GRADIENTGLOW*)original)->gradient);
566         }
567                         break;
568                 case FILTERTYPE_DROPSHADOW:
569                         memcpy(copy, original, sizeof(FILTER_DROPSHADOW)); 
570                         break;
571                 case FILTERTYPE_BEVEL:
572                         memcpy(copy, original, sizeof(FILTER_BEVEL)); 
573                         break;
574         default: syntaxerror("Internal error: unsupported filterype");
575         }
576         return copy;
577 }
578
579 int changeFilter_differs(changeFilter_t* modification, U16 frame)
580 {
581     changeFilter_t* previous = modification;
582     while (modification && modification->frame < frame)
583         {
584         previous = modification;
585         modification = modification->next;
586         }
587     if (!modification)
588         return 0;
589     if (modification->frame == frame)
590         return 1;
591     return (modification->function != CF_JUMP);
592 }
593
594 FILTER* changeFilter_value(changeFilter_t* modification, U16 frame)
595 {
596     changeFilter_t* previous = modification;
597     while (modification && modification->frame < frame)
598     {
599         previous = modification;
600         modification = modification->next;
601     }
602     if (!modification)
603                 return copyFilter(previous->value);
604     if (modification->frame == frame)
605         {
606                 do 
607                 {
608             previous = modification;
609             modification = modification->next;
610                 }
611         while (modification && modification->frame == frame);
612         return copyFilter(previous->value);
613         }
614     switch (modification->function)
615         {
616                 case CF_PUT:
617             return copyFilter(modification->value);
618                 case CF_CHANGE:
619                 {
620             float fraction = (frame - previous->frame) / (float)(modification->frame - previous->frame);
621             return interpolateFilter(previous->value, modification->value, fraction, modification->interpolation);
622                 }
623                 case CF_JUMP:
624                         return copyFilter(previous->value);
625                 default:
626                         return 0;
627         }
628 }
629
630 history_t* history_new()
631 {
632         history_t* newHistory = (history_t*)malloc(sizeof(history_t));
633         history_init(newHistory);
634         return newHistory;
635 }
636
637 void history_free(history_t* past)
638 {
639         change_free(dictionary_lookup(past->changes, "x"));
640         change_free(dictionary_lookup(past->changes, "y"));
641         change_free(dictionary_lookup(past->changes, "scalex"));
642         change_free(dictionary_lookup(past->changes, "scaley"));
643         change_free(dictionary_lookup(past->changes, "cxform.r0"));
644         change_free(dictionary_lookup(past->changes, "cxform.g0"));
645         change_free(dictionary_lookup(past->changes, "cxform.b0"));
646         change_free(dictionary_lookup(past->changes, "cxform.a0"));
647         change_free(dictionary_lookup(past->changes, "cxform.r1"));
648         change_free(dictionary_lookup(past->changes, "cxform.g1"));
649         change_free(dictionary_lookup(past->changes, "cxform.b1"));
650         change_free(dictionary_lookup(past->changes, "cxform.a1"));
651         change_free(dictionary_lookup(past->changes, "rotate"));
652         change_free(dictionary_lookup(past->changes, "shear"));
653         change_free(dictionary_lookup(past->changes, "pivot.x"));
654         change_free(dictionary_lookup(past->changes, "pivot.y"));
655         change_free(dictionary_lookup(past->changes, "pin.x"));
656         change_free(dictionary_lookup(past->changes, "pin.y"));
657         change_free(dictionary_lookup(past->changes, "blendmode"));
658         changeFilter_free(dictionary_lookup(past->changes, "filter"));
659         dictionary_destroy(past->changes);
660         free(past);
661 }
662
663 void history_init(history_t* past)
664 {
665         past->changes = (dictionary_t*)malloc(sizeof(dictionary_t));
666         dictionary_init(past->changes);
667 }
668
669 void history_begin(history_t* past, char* parameter, U16 frame, TAG* tag, float value)
670 {
671         change_t* first = change_new(frame, CF_PUT, value, 0);
672         past->firstTag = tag;
673         past->firstFrame = frame;
674         dictionary_put2(past->changes, parameter, first);
675 }
676
677 void history_beginFilter(history_t* past, U16 frame, TAG* tag, FILTER* value)
678 {
679         changeFilter_t* first = changeFilter_new(frame, CF_PUT, value, 0);
680         past->firstTag = tag;
681         past->firstFrame = frame;
682         dictionary_put2(past->changes, "filter", first);
683 }
684
685 void history_remember(history_t* past, char* parameter, U16 frame, int function, float value, interpolation_t* inter)
686 {
687         change_t* first = dictionary_lookup(past->changes, parameter);
688         if (first) //should always be true
689         {
690                 change_t* next = change_new(frame, function, value, inter);
691                 change_append(first, next);
692         }
693 }
694
695 void history_rememberFilter(history_t* past, U16 frame, int function, FILTER* value, interpolation_t* inter)
696 {
697         changeFilter_t* first = dictionary_lookup(past->changes, "filter");
698         if (first) //should always be true
699         {
700                 changeFilter_t* next = changeFilter_new(frame, function, value, inter);
701                 changeFilter_append(first, next);
702         }
703 }
704
705 int history_change(history_t* past, U16 frame, char* parameter)
706 {
707     change_t* first = dictionary_lookup(past->changes, parameter);
708     if (first)  //should always be true.
709         return change_differs(first, frame);
710     printf("no history found for parameter %s\n", parameter);
711     return 0;
712 }
713
714 float history_value(history_t* past, U16 frame, char* parameter)
715 {
716         change_t* first = dictionary_lookup(past->changes, parameter);
717         if (first)      //should always be true.
718                 return change_value(first, frame);
719         printf("no history found for parameter %s\n", parameter);
720         return 0;
721 }
722
723 int history_changeFilter(history_t* past, U16 frame)
724 {
725     changeFilter_t* first = dictionary_lookup(past->changes, "filter");
726     if (first)  //should always be true.
727         return changeFilter_differs(first, frame);
728     printf("no history found for parameter filter\n");
729     return 0;
730 }
731
732 FILTER* history_valueFilter(history_t* past, U16 frame)
733 {
734         changeFilter_t* first = dictionary_lookup(past->changes, "filter");
735         if (first)      //should always be true.
736                 return changeFilter_value(first, frame);
737         printf("no history found for parameter filter\n");
738         return 0;
739 }