first half of Huub Schaek's sweep 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 enum
27 {
28     T_BEFORE = 0,
29     T_AFTER = 1,
30     T_SYMMETRIC = 2
31 };
32
33 state_t* state_new(U16 frame, int function, float value, interpolation_t* inter)
34 {
35     state_t* newState = (state_t*)malloc(sizeof(state_t));
36     state_init(newState);
37     newState->frame = frame;
38     newState->function = function;
39     newState->value = value;
40     newState->interpolation = inter;
41     return newState;
42 }
43
44 void state_free(state_t* state)
45 {
46     if (state->next)
47         state_free(state->next);
48     free(state);
49 }
50
51 void state_init(state_t* state)
52 {
53     memset(state, 0, sizeof(state_t));
54 }
55
56 state_t* state_at(state_t* state, U16 frame)
57 {
58     while (state->next && state->next->frame < frame)
59         state = state->next;
60     return state;
61 }
62
63 void state_append(state_t* state, state_t* newState)
64 {
65     state_t* previous = 0;
66     state_t* start = state;
67     float p0, p1, m0, m1;
68
69     while (state->next)
70     {
71         previous = state;
72         state = state->next;
73     }
74     state->next = newState;
75     if (state->function == CF_SCHANGE)
76     {
77         p0 = previous->value;
78         p1 = state->value;
79         if (previous->function == CF_SCHANGE)
80             m0 = (3 * previous->spline.a + 2 * previous->spline.b + previous->spline.c);
81         else
82             if (previous->function == CF_CHANGE || previous->function == CF_SWEEP)
83                 m0 = state_tangent(start, previous->frame, T_BEFORE) * (state->frame - previous->frame);
84             else
85                 m0 = (state->value - previous->value);
86         if (newState->function == CF_SCHANGE)
87             m1 = 0.5 * (newState->value - previous->value)/* * (state->frame - previous->frame) / (newState->frame - state->frame)*/;
88         else
89             if (newState->function == CF_CHANGE || newState->function == CF_SWEEP)
90                 m1 = state_tangent(previous, state->frame, T_AFTER) * (state->frame - previous->frame);
91             else
92                 m1 = (newState->value - state->value);
93         state->spline.a = 2 * p0 + m0 - 2 * p1 + m1;
94         state->spline.b = -3 * p0 - 2 * m0 + 3 * p1 - m1;
95         state->spline.c = m0;
96         state->spline.d = p0;
97 //      printf("p0: %f, p1: %f, m0: %f, m1: %f.\n", p0, p1, m0, m1);
98 //      printf("a: %f, b: %f, c: %f, d: %f.\n", state->spline.a, state->spline.b, state->spline.c, state->spline.d);
99     }
100     if (newState->function == CF_SCHANGE)
101     {
102         p0 = state->value;
103         p1 = newState->value;
104         if (state->function == CF_SCHANGE)
105             m0 = m1;
106         else
107             if (state->function == CF_CHANGE || state->function == CF_SWEEP)
108                 m0 = state_tangent(start, state->frame, T_BEFORE) * (state->frame - previous->frame);
109             else
110                 m0 = (newState->value - state->value);
111         m1 = (newState->value - state->value);
112         newState->spline.a = 2 * p0 + m0 - 2 * p1 + m1;
113         newState->spline.b = -3 * p0 - 2 * m0 + 3 * p1 - m1;
114         newState->spline.c = m0;
115         newState->spline.d = p0;
116     }
117     }
118
119 void state_insert(state_t* state, state_t* newState)
120 {
121     while (state->next && state->next->frame < newState->frame)
122         state = state->next;
123     newState->next = state->next;
124     state->next = newState;
125     // if this is going to be used to insert CF_SCHANGE states it will have to be extended
126     // as in state_append above. I know this is not necessary right now, so I'll be lazy.
127 }
128
129 float calculateSpline(state_t* modification, float fraction)
130 {
131     spline_t s = modification->spline;
132     return (((s.a * fraction) + s.b) * fraction + s.c) * fraction + s.d;
133 }
134
135 float interpolateScalar(float p1, float p2, float fraction, interpolation_t* inter)
136 {
137         if (!inter)
138                 return linear(fraction, p1, p2 - p1);
139         switch (inter->function)
140         {
141                 case IF_LINEAR: return linear(fraction, p1, p2 - p1);
142         case IF_QUAD_IN: return quadIn(fraction, p1, p2 - p1, inter->slope);
143         case IF_QUAD_OUT: return quadOut(fraction, p1, p2 - p1, inter->slope);
144         case IF_QUAD_IN_OUT: return quadInOut(fraction, p1, p2 - p1, inter->slope);
145         case IF_CUBIC_IN: return cubicIn(fraction, p1, p2 - p1, inter->slope);
146         case IF_CUBIC_OUT: return cubicOut(fraction, p1, p2 - p1, inter->slope);
147         case IF_CUBIC_IN_OUT: return cubicInOut(fraction, p1, p2 - p1, inter->slope);
148         case IF_QUART_IN: return quartIn(fraction, p1, p2 - p1, inter->slope);
149         case IF_QUART_OUT: return quartOut(fraction, p1, p2 - p1, inter->slope);
150         case IF_QUART_IN_OUT: return quartInOut(fraction, p1, p2 - p1, inter->slope);
151         case IF_QUINT_IN: return quintIn(fraction, p1, p2 - p1, inter->slope);
152         case IF_QUINT_OUT: return quintOut(fraction, p1, p2 - p1, inter->slope);
153         case IF_QUINT_IN_OUT: return quintInOut(fraction, p1, p2 - p1, inter->slope);
154         case IF_CIRCLE_IN: return circleIn(fraction, p1, p2 - p1, inter->slope);
155         case IF_CIRCLE_OUT: return circleOut(fraction, p1, p2 - p1, inter->slope);
156         case IF_CIRCLE_IN_OUT: return circleInOut(fraction, p1, p2 - p1, inter->slope);
157                 case IF_EXPONENTIAL_IN: return exponentialIn(fraction, p1, p2 - p1);
158                 case IF_EXPONENTIAL_OUT: return exponentialOut(fraction, p1, p2 - p1);
159                 case IF_EXPONENTIAL_IN_OUT: return exponentialInOut(fraction, p1, p2 - p1);
160                 case IF_SINE_IN: return sineIn(fraction, p1, p2 - p1);
161                 case IF_SINE_OUT: return sineOut(fraction, p1, p2 - p1);
162                 case IF_SINE_IN_OUT: return sineInOut(fraction, p1, p2 - p1);
163                 case IF_ELASTIC_IN: return elasticIn(fraction, p1, p2 - p1, inter->amplitude, inter->bounces, inter->damping);
164                 case IF_ELASTIC_OUT: return elasticOut(fraction, p1, p2 - p1, inter->amplitude, inter->bounces, inter->damping);
165                 case IF_ELASTIC_IN_OUT: return elasticInOut(fraction, p1, p2 - p1, inter->amplitude, inter->bounces, inter->damping);
166                 case IF_BACK_IN: return backIn(fraction, p1, p2 - p1, inter->speed);
167                 case IF_BACK_OUT: return backOut(fraction, p1, p2 - p1, inter->speed);
168                 case IF_BACK_IN_OUT: return backInOut(fraction, p1, p2 - p1, inter->speed);
169                 case IF_BOUNCE_IN: return bounceIn(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping);
170                 case IF_BOUNCE_OUT: return bounceOut(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping);
171                 case IF_BOUNCE_IN_OUT: return bounceInOut(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping);
172                 case IF_FAST_BOUNCE_IN: return fastBounceIn(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping);
173                 case IF_FAST_BOUNCE_OUT: return fastBounceOut(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping);
174                 case IF_FAST_BOUNCE_IN_OUT: return fastBounceInOut(fraction, p1, p2 - p1, inter->bounces, inter->growth, inter->damping);
175                 default: return linear(fraction, p1, p2 - p1);
176         }
177 }
178
179 float calculateSweep(state_t* modification, float fraction)
180 {
181     arc_t* a = &(modification->arc);
182     float angle = a->angle + fraction * a->delta_angle;
183     if (a->X)
184         return a->cX + a->r * cos(angle);
185     else
186         return a->cY + a->r * sin(angle);
187
188 }
189
190 int state_differs(state_t* modification, U16 frame)
191 {
192     state_t* previous = modification;
193     while (modification && modification->frame < frame)
194         {
195         previous = modification;
196         modification = modification->next;
197     }
198     if (!modification)
199         return 0;
200     if (modification->frame == frame)
201         return 1;
202     return (modification->function != CF_JUMP);
203         }
204
205 float state_tangent(state_t* modification, U16 frame, int tangent)
206 {
207     float deltaFrame = 0.1;
208     switch (tangent)
209 {
210         case T_BEFORE:
211             return (state_value(modification, frame) - state_value(modification, frame - deltaFrame)) / deltaFrame;
212         case T_AFTER:
213             return (state_value(modification, frame + deltaFrame) - state_value(modification, frame)) / deltaFrame;
214         default:
215             return (state_value(modification, frame + deltaFrame) - state_value(modification, frame - deltaFrame)) / (2 * deltaFrame);
216     }
217 }
218
219 float state_value(state_t* modification, float frame)
220 {
221     state_t* previous = modification;
222     while (modification && modification->frame < frame)
223     {
224         previous = modification;
225         modification = modification->next;
226     }
227     if (!modification)
228                 return previous->value;
229     if (modification->frame == frame)
230         {
231                 do 
232                 {
233             previous = modification;
234             modification = modification->next;
235                 }
236         while (modification && modification->frame == frame);
237         return previous->value;
238         }
239     switch (modification->function)
240         {
241                 case CF_PUT:
242             return modification->value;
243                 case CF_CHANGE:
244                 {
245             float fraction = (frame - previous->frame) / (float)(modification->frame - previous->frame);
246             return interpolateScalar(previous->value, modification->value, fraction, modification->interpolation);
247         }
248         case CF_SCHANGE:
249         {
250             float fraction = (frame - previous->frame) / (float)(modification->frame - previous->frame);
251             fraction = interpolateScalar(0, 1, fraction, modification->interpolation);
252             return calculateSpline(modification, fraction);
253                 }
254         case CF_SWEEP:
255         {
256             float fraction = (frame - previous->frame) / (float)(modification->frame - previous->frame);
257             fraction = interpolateScalar(0, 1, fraction, modification->interpolation);
258             return calculateSweep(modification, fraction);
259         }
260                 case CF_JUMP:
261                         return previous->value;
262                 default:
263                         return 0;
264         }
265 }
266
267 filterState_t* filterState_new(U16 frame, int function, FILTERLIST* value, interpolation_t* inter)
268 {
269     filterState_t* newChange = (filterState_t*)malloc(sizeof(filterState_t));
270     filterState_init(newChange);
271         newChange->frame = frame;
272         newChange->function = function;
273         newChange->value = value;
274         newChange->interpolation = inter;
275         return newChange;
276 }
277
278 void filterState_free(filterState_t *change)
279 {
280         if (change->next)
281         filterState_free(change->next);
282     free(change->value);
283         free(change);
284 }
285
286 void filterState_init(filterState_t* change)
287 {
288     memset(change, 0, sizeof(filterState_t));
289 }
290
291 void filterState_append(filterState_t* first, filterState_t* newChange)
292 {
293         while (first->next)
294                 first = first->next;
295     if (!first->value || !newChange->value)
296         first->next = newChange;
297     else
298     {
299         int i, mergedCount = 0;
300         int common = first->value->num < newChange->value->num ? first->value->num : newChange->value->num;
301         for (i = 0; i < common; i++)
302         {
303             mergedCount++;
304             if (newChange->value->filter[i]->type != first->value->filter[i]->type)
305                 mergedCount++;
306         }
307         mergedCount = mergedCount + first->value->num - common + newChange->value->num - common;
308         if (mergedCount > 8)
309         {
310             char* list1;
311             char* list2;
312             char* newList;
313             list1 = (char*)malloc(1);
314             *list1 = '\0';
315             for (i = 0; i < first->value->num; i++)
316             {
317                 newList = (char*)malloc(strlen(list1) + strlen(filtername[first->value->filter[i]->type]) + 2);
318                 newList = strcat(strcat(list1, "+"), filtername[first->value->filter[i]->type]);
319                 free(list1);
320                 list1 = newList;
321             }
322             list2 = (char*)malloc(1);
323             *list2 = '\0';
324             for (i = 0; i < newChange->value->num; i++)
325             {
326                 newList = (char*)malloc(strlen(list1) + strlen(filtername[newChange->value->filter[i]->type]) + 2);
327                 newList = strcat(strcat(list2, "+"), filtername[newChange->value->filter[i]->type]);
328                 free(list2);
329                 list2 = newList;
330             }
331             syntaxerror("filterlists %s and %s cannot be interpolated.", list1, list2);
332         }
333         first->next = newChange;
334     }
335 }
336
337 RGBA interpolateColor(RGBA c1, RGBA c2, float ratio, interpolation_t* inter)
338 {
339     RGBA c;
340     c.r = interpolateScalar(c1.r, c2.r, ratio, inter);
341     c.g = interpolateScalar(c1.g, c2.g, ratio, inter);
342     c.b = interpolateScalar(c1.b, c2.b, ratio, inter);
343     c.a = interpolateScalar(c1.a, c2.a, ratio, inter);
344     return c;
345 }
346
347 GRADIENT* interpolateNodes(GRADIENT* g1, GRADIENT* g2, float fraction, interpolation_t* inter)
348 {
349     if (g1->num != g2->num)
350         syntaxerror("Internal error: gradients are not equal in size");
351
352     int i;
353     GRADIENT* g = (GRADIENT*) malloc(sizeof(GRADIENT));
354     g->ratios = rfx_calloc(16*sizeof(U8));
355     g->rgba = rfx_calloc(16*sizeof(RGBA));
356     g->num = g1->num;
357     for (i = 0; i < g->num; i++)
358     {
359         g->ratios[i] = interpolateScalar(g1->ratios[i], g2->ratios[i], fraction, inter);
360         g->rgba[i] = interpolateColor(g1->rgba[i], g2->rgba[i], fraction, inter);
361     }
362     return g;
363 }
364
365 void copyGradient(GRADIENT* dest, GRADIENT* source)
366 {
367     dest->num = source->num;
368     memcpy(dest->ratios, source->ratios, source->num * sizeof(U8));
369     memcpy(dest->rgba, source->rgba, source->num * sizeof(RGBA));
370 }
371
372 void insertNode(GRADIENT* g, int pos)
373 {
374     memmove(&g->ratios[pos + 1], &g->ratios[pos], (g->num - pos) * sizeof(U8));
375     memmove(&g->rgba[pos + 1], &g->rgba[pos], (g->num - pos) * sizeof(RGBA));
376     if (pos == 0)
377     {
378         g->ratios[0] = g->ratios[1] / 2;
379         g->rgba[0] = g->rgba[1];
380     }
381     else
382         if (pos == g->num)
383         {
384             g->ratios[pos] = (255 + g->ratios[g->num - 1]) / 2;
385             g->rgba[pos] = g->rgba[pos - 1];
386         }
387         else
388         {
389             g->ratios[pos] = (g->ratios[pos - 1] + g->ratios[pos + 1]) / 2;
390             g->rgba[pos] = interpolateColor(g->rgba[pos - 1], g->rgba[pos + 1], 0.5, 0);
391         }
392     g->num++;
393 }
394
395 void insertOptimalNode(GRADIENT* g)
396 {
397     int i, next_gap;
398     int pos = 0;
399     int gap = g->ratios[0];
400     for (i = 0; i < g->num - 1; i++)
401     {
402         next_gap = g->ratios[i + 1] - g->ratios[i];
403         if (next_gap > gap)
404         {
405             gap = next_gap;
406             pos = i + 1;
407         }
408     }
409     next_gap = 255 - g->ratios[g->num -1];
410     if (next_gap > gap)
411         pos = g->num;
412     insertNode(g, pos);
413 }
414    
415 void growGradient(GRADIENT* start, int size)
416 {
417     while (start->num < size)
418         insertOptimalNode(start);
419 }
420
421 GRADIENT* interpolateGradient(GRADIENT* g1, GRADIENT* g2, float fraction, interpolation_t* inter)
422 {
423     int i;
424     GRADIENT g;
425     g.ratios = rfx_calloc(16*sizeof(U8));
426     g.rgba = rfx_calloc(16*sizeof(RGBA));
427
428     if (g1->num > g2->num)
429     {
430         copyGradient(&g, g2);
431         growGradient(&g, g1->num);
432         GRADIENT* result = interpolateNodes(g1, &g, fraction, inter);
433         rfx_free(g.rgba);
434         rfx_free(g.ratios);
435         return result;
436     }
437     else
438         if (g1->num < g2->num)
439         {
440             copyGradient(&g, g1);
441             growGradient(&g, g2->num);
442             GRADIENT* result = interpolateNodes(&g, g2, fraction, inter);
443             rfx_free(g.rgba);
444             rfx_free(g.ratios);
445             return result;
446         }
447         else
448             return interpolateNodes(g1, g2, fraction, inter);
449 }
450
451 FILTER* copyFilter(FILTER* original)
452 {
453     if (!original)
454         return original;
455     FILTER* copy = swf_NewFilter(original->type);
456     switch (original->type)
457     {
458         case FILTERTYPE_BLUR:
459             memcpy(copy, original, sizeof(FILTER_BLUR));
460             break;
461         case FILTERTYPE_GRADIENTGLOW:
462         {
463             memcpy(copy, original, sizeof(FILTER_GRADIENTGLOW));
464             FILTER_GRADIENTGLOW* ggcopy = (FILTER_GRADIENTGLOW*)copy;
465             ggcopy->gradient = (GRADIENT*)malloc(sizeof(GRADIENT));
466             ggcopy->gradient->ratios = (U8*)malloc(16 * sizeof(U8));
467             ggcopy->gradient->rgba = (RGBA*)malloc(16 * sizeof(RGBA));
468             copyGradient(ggcopy->gradient, ((FILTER_GRADIENTGLOW*)original)->gradient);
469         }
470             break;
471         case FILTERTYPE_DROPSHADOW:
472             memcpy(copy, original, sizeof(FILTER_DROPSHADOW));
473             break;
474         case FILTERTYPE_BEVEL:
475             memcpy(copy, original, sizeof(FILTER_BEVEL));
476             break;
477         default: syntaxerror("Internal error: unsupported filterype, cannot copy");
478     }
479     return copy;
480 }
481
482 FILTER* interpolateBlur(FILTER* filter1, FILTER* filter2, float ratio, interpolation_t* inter)
483         {
484                 FILTER_BLUR*f1 = (FILTER_BLUR*)filter1;
485                 FILTER_BLUR*f2 = (FILTER_BLUR*)filter2;
486     if (!f1)
487         f1 = noBlur;
488     if (!f2)
489         f2 = noBlur;
490     if(f1->blurx == f2->blurx && f1->blury == f2->blury)
491         return copyFilter(filter1);
492                 FILTER_BLUR*f = (FILTER_BLUR*)swf_NewFilter(FILTERTYPE_BLUR);
493     f->blurx= interpolateScalar(f1->blurx, (f2->blurx), ratio, inter);
494     f->blury= interpolateScalar(f1->blury, (f2->blury), ratio, inter);
495     f->passes= interpolateScalar(f1->passes, (f2->passes), ratio, inter);
496                 return (FILTER*)f;
497                 }
498
499 void matchDropshadowFlags(FILTER_DROPSHADOW* unset, FILTER_DROPSHADOW* target)
500 {
501     unset->innershadow = target->innershadow;
502     unset->knockout = target->knockout;
503     unset->composite = target->composite;
504 }
505
506 FILTER* interpolateDropshadow(FILTER* filter1,FILTER* filter2, float ratio, interpolation_t* inter)
507                 {
508                         FILTER_DROPSHADOW*f1 = (FILTER_DROPSHADOW*)filter1;
509                         FILTER_DROPSHADOW*f2 = (FILTER_DROPSHADOW*)filter2;
510     if (!f1)
511         f1 = noDropshadow;
512     if (!f2)
513         f2 = noDropshadow;
514     if(!memcmp(&f1->color,&f2->color,sizeof(RGBA)) && f1->strength == f2->strength &&
515                                 f1->blurx == f2->blurx && f1->blury == f2->blury && 
516                                 f1->angle == f2->angle && f1->distance == f2->distance)
517                 return copyFilter(filter1);
518                         FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)swf_NewFilter(FILTERTYPE_DROPSHADOW);
519                         memcpy(f, f1, sizeof(FILTER_DROPSHADOW));
520                         f->color = interpolateColor(f1->color, f2->color, ratio, inter);
521     f->blurx= interpolateScalar(f1->blurx, (f2->blurx), ratio, inter);
522     f->blury= interpolateScalar(f1->blury, (f2->blury), ratio, inter);
523     f->passes= interpolateScalar(f1->passes, (f2->passes), ratio, inter);
524     f->angle= interpolateScalar(f1->angle, (f2->angle), ratio, inter);
525     f->distance= interpolateScalar(f1->distance, (f2->distance), ratio, inter);
526     f->strength= interpolateScalar(f1->strength, (f2->strength), ratio, inter);
527     if (f1 == noDropshadow)
528     {
529         if (f2 != noDropshadow)
530             matchDropshadowFlags(f, f2);
531                 }
532                 else
533         if (f2 == noDropshadow)
534             matchDropshadowFlags(f, f1);
535         else
536             if (ratio > 0.5)
537                 matchDropshadowFlags(f, f2);
538             else
539                 matchDropshadowFlags(f, f1);
540     return (FILTER*)f;
541 }
542
543 void matchBevelFlags(FILTER_BEVEL* unset, FILTER_BEVEL* target)
544 {
545     unset->innershadow = target->innershadow;
546     unset->knockout = target->knockout;
547     unset->composite = target->composite;
548     unset->ontop = target->ontop;
549 }
550
551 FILTER* interpolateBevel(FILTER* filter1,FILTER* filter2, float ratio, interpolation_t* inter)
552                         {
553                                 FILTER_BEVEL*f1 = (FILTER_BEVEL*)filter1;
554                                 FILTER_BEVEL*f2 = (FILTER_BEVEL*)filter2;
555     if (!f1)
556         f1 = noBevel;
557     if (!f2)
558         f2 = noBevel;
559     if(!memcmp(&f1->shadow,&f2->shadow,sizeof(RGBA)) &&
560                                         !memcmp(&f1->highlight,&f2->highlight,sizeof(RGBA)) && 
561                                         f1->blurx == f2->blurx && f1->blury == f2->blury && f1->angle == f2->angle && f1->strength == f2->strength && f1->distance == f2->distance)
562                 return copyFilter(filter1);
563                                 FILTER_BEVEL*f = (FILTER_BEVEL*)swf_NewFilter(FILTERTYPE_BEVEL);
564                                 memcpy(f, f1, sizeof(FILTER_BEVEL));
565                                 f->shadow = interpolateColor(f1->shadow, f2->shadow, ratio, inter);
566                                 f->highlight = interpolateColor(f1->highlight, f2->highlight, ratio, inter);
567     f->blurx= interpolateScalar(f1->blurx, (f2->blurx), ratio, inter);
568     f->blury= interpolateScalar(f1->blury, (f2->blury), ratio, inter);
569     f->passes= interpolateScalar(f1->passes, (f2->passes), ratio, inter);
570     f->angle= interpolateScalar(f1->angle, (f2->angle), ratio, inter);
571     f->distance= interpolateScalar(f1->distance, (f2->distance), ratio, inter);
572     f->strength= interpolateScalar(f1->strength, (f2->strength), ratio, inter);
573     if (f1 == noBevel)
574     {
575         if (f2 != noBevel)
576             matchBevelFlags(f, f2);
577     }
578     else
579         if (f2 == noBevel)
580             matchBevelFlags(f, f1);
581         else
582             if (ratio > 0.5)
583                 matchBevelFlags(f, f2);
584             else
585                 matchBevelFlags(f, f1);
586                                 return (FILTER*)f;
587 }
588
589 void matchGradientGlowFlags(FILTER_GRADIENTGLOW* unset, FILTER_GRADIENTGLOW* target)
590 {
591     unset->innershadow = target->innershadow;
592     unset->knockout = target->knockout;
593     unset->composite = target->composite;
594     unset->ontop = target->ontop;
595 }
596
597 FILTER* interpolateGradientGlow(FILTER* filter1,FILTER* filter2, float ratio, interpolation_t* inter)
598 {
599     FILTER_GRADIENTGLOW*f1 = (FILTER_GRADIENTGLOW*)filter1;
600     FILTER_GRADIENTGLOW*f2 = (FILTER_GRADIENTGLOW*)filter2;
601     if (!f1)
602         f1 = noGradientGlow;
603     if (!f2)
604         f2 = noGradientGlow;
605     if(f1->gradient->num == f2->gradient->num &&
606                 !memcmp(&f1->gradient->ratios,&f2->gradient->ratios,f1->gradient->num * sizeof(U8)) &&
607                 !memcmp(&f1->gradient->rgba,&f2->gradient->rgba,f1->gradient->num * sizeof(RGBA)) &&
608                 f1->blurx == f2->blurx && f1->blury == f2->blury && f1->angle == f2->angle && f1->strength == f2->strength && f1->distance == f2->distance)
609                 return copyFilter(filter1);
610         FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
611     memcpy(f, f1, sizeof(FILTER_GRADIENTGLOW));
612     f->blurx= interpolateScalar(f1->blurx, (f2->blurx), ratio, inter);
613     f->blury= interpolateScalar(f1->blury, (f2->blury), ratio, inter);
614     f->passes= interpolateScalar(f1->passes, (f2->passes), ratio, inter);
615     f->angle= interpolateScalar(f1->angle, (f2->angle), ratio, inter);
616     f->distance= interpolateScalar(f1->distance, (f2->distance), ratio, inter);
617     f->strength= interpolateScalar(f1->strength, (f2->strength), ratio, inter);
618     f->gradient= interpolateGradient(f1->gradient, f2->gradient, ratio, inter);
619     if (f1 == noGradientGlow)
620     {
621         if (f2 != noGradientGlow)
622             matchGradientGlowFlags(f, f2);
623     }
624     else
625         if (f2 == noGradientGlow)
626             matchGradientGlowFlags(f, f1);
627         else
628             if (ratio > 0.5)
629                 matchGradientGlowFlags(f, f2);
630             else
631                 matchGradientGlowFlags(f, f1);
632         return (FILTER*)f;
633 }
634
635 FILTER* interpolateFilter(FILTER* filter1,FILTER* filter2, float ratio, interpolation_t* inter)
636 {
637     if(!filter1 && !filter2)
638         return 0;
639
640     int filter_type;
641     if (!filter1)
642         filter_type = filter2->type;
643     else
644         if (!filter2)
645             filter_type = filter1->type;
646         else
647             if(filter2->type != filter1->type)
648                 syntaxerror("can't interpolate between %s and %s filters yet", filtername[filter1->type], filtername[filter2->type]);
649             else
650                 filter_type = filter1->type;
651
652     switch (filter_type)
653     {
654         case FILTERTYPE_BLUR:
655             return interpolateBlur(filter1, filter2, ratio, inter);
656         case FILTERTYPE_BEVEL:
657             return interpolateBevel(filter1, filter2, ratio, inter);
658         case FILTERTYPE_DROPSHADOW:
659             return interpolateDropshadow(filter1, filter2, ratio, inter);
660         case FILTERTYPE_GRADIENTGLOW:
661             return interpolateGradientGlow(filter1, filter2, ratio, inter);
662         default:
663             syntaxerror("Filtertype %s not supported yet.\n", filtername[filter1->type]);
664     }
665         return 0;
666 }
667
668 FILTERLIST* copyFilterList(FILTERLIST* original)
669 {
670         if (!original)
671                 return original;
672     int i;
673     FILTERLIST* copy = (FILTERLIST*)malloc(sizeof(FILTERLIST));
674     copy->num = original->num;
675     for (i = 0; i < copy->num; i++)
676         copy->filter[i] = copyFilter(original->filter[i]);
677     return copy;
678 }
679
680 FILTER* noFilter(int type)
681 {
682     switch (type)
683         {
684                 case FILTERTYPE_BLUR:
685             return (FILTER*)noBlur;
686                         break;
687         case FILTERTYPE_BEVEL:
688             return (FILTER*)noBevel;
689                         break;
690                 case FILTERTYPE_DROPSHADOW:
691             return (FILTER*)noDropshadow;
692                         break;
693         case FILTERTYPE_GRADIENTGLOW:
694             return (FILTER*)noGradientGlow;
695                         break;
696         default:
697             syntaxerror("Internal error: unsupported filtertype, cannot match filterlists");
698         }
699     return 0;
700 }
701
702 FILTERLIST* interpolateFilterList(FILTERLIST* list1, FILTERLIST* list2, float ratio, interpolation_t* inter)
703 {
704     if (!list1 && !list2)
705         return list1;
706     FILTERLIST start, target, dummy;
707     dummy.num = 0;
708     if (!list1)
709         list1 = &dummy;
710     if (!list2)
711         list2 = &dummy;
712     int i, j = 0;
713     int common = list1->num < list2->num ? list1->num : list2->num;
714         for (i = 0; i < common; i++)
715     {
716         start.filter[j] = list1->filter[i];
717         if (list2->filter[i]->type == list1->filter[i]->type)
718         {
719             target.filter[j] = list2->filter[i];
720             j++;
721         }
722         else
723         {
724             target.filter[j] = noFilter(list1->filter[i]->type);
725             j++;
726             start.filter[j] = noFilter(list2->filter[i]->type);
727             target.filter[j] = list2->filter[i];
728             j++;
729         }
730     }
731     if (list1->num > common)
732         for (i = common; i < list1->num; i++)
733         {
734             start.filter[j] = list1->filter[i];
735             target.filter[j] = noFilter(list1->filter[i]->type);
736             j++;
737         }
738     if (list2->num > common)
739         for (i = common; i < list2->num; i++)
740         {
741             start.filter[j] = noFilter(list2->filter[i]->type);
742             target.filter[j] = list2->filter[i];
743             j++;
744         }
745     start.num = j;
746     target.num = j;
747     FILTERLIST* mixedList = (FILTERLIST*)malloc(sizeof(FILTERLIST));
748     mixedList->num = j;
749     for (i = 0; i < j; i++)
750         mixedList->filter[i] = interpolateFilter(start.filter[i], target.filter[i], ratio, inter);
751     return mixedList;
752 }
753
754 int filterState_differs(filterState_t* modification, U16 frame)
755 {
756     filterState_t* previous = modification;
757     while (modification && modification->frame < frame)
758         {
759         previous = modification;
760         modification = modification->next;
761         }
762     if (!modification)
763         return 0;
764     if (modification->frame == frame)
765         return 1;
766     return (modification->function != CF_JUMP);
767 }
768
769 FILTERLIST* filterState_value(filterState_t* modification, U16 frame)
770 {
771     filterState_t* previous = modification;
772     while (modification && modification->frame < frame)
773     {
774         previous = modification;
775         modification = modification->next;
776     }
777     if (!modification)
778         return copyFilterList(previous->value);
779     if (modification->frame == frame)
780         {
781                 do 
782                 {
783             previous = modification;
784             modification = modification->next;
785                 }
786         while (modification && modification->frame == frame);
787         return copyFilterList(previous->value);
788         }
789     switch (modification->function)
790         {
791                 case CF_PUT:
792             return copyFilterList(modification->value);
793                 case CF_CHANGE:
794                 {
795             float fraction = (frame - previous->frame) / (float)(modification->frame - previous->frame);
796             return interpolateFilterList(previous->value, modification->value, fraction, modification->interpolation);
797                 }
798                 case CF_JUMP:
799             return copyFilterList(previous->value);
800                 default:
801                         return 0;
802         }
803 }
804
805 history_t* history_new()
806 {
807         history_t* newHistory = (history_t*)malloc(sizeof(history_t));
808         history_init(newHistory);
809         return newHistory;
810 }
811
812 void history_free(history_t* past)
813 {
814     state_free(dictionary_lookup(past->states, "x"));
815     state_free(dictionary_lookup(past->states, "y"));
816     state_free(dictionary_lookup(past->states, "scalex"));
817     state_free(dictionary_lookup(past->states, "scaley"));
818     state_free(dictionary_lookup(past->states, "cxform.r0"));
819     state_free(dictionary_lookup(past->states, "cxform.g0"));
820     state_free(dictionary_lookup(past->states, "cxform.b0"));
821     state_free(dictionary_lookup(past->states, "cxform.a0"));
822     state_free(dictionary_lookup(past->states, "cxform.r1"));
823     state_free(dictionary_lookup(past->states, "cxform.g1"));
824     state_free(dictionary_lookup(past->states, "cxform.b1"));
825     state_free(dictionary_lookup(past->states, "cxform.a1"));
826     state_free(dictionary_lookup(past->states, "rotate"));
827     state_free(dictionary_lookup(past->states, "shear"));
828     state_free(dictionary_lookup(past->states, "pivot.x"));
829     state_free(dictionary_lookup(past->states, "pivot.y"));
830     state_free(dictionary_lookup(past->states, "pin.x"));
831     state_free(dictionary_lookup(past->states, "pin.y"));
832     state_free(dictionary_lookup(past->states, "blendmode"));
833     state_free(dictionary_lookup(past->states, "flags"));
834     filterState_free(dictionary_lookup(past->states, "filter"));
835     dictionary_destroy(past->states);
836         free(past);
837 }
838
839 void history_init(history_t* past)
840 {
841     past->states = (dictionary_t*)malloc(sizeof(dictionary_t));
842     dictionary_init(past->states);
843 }
844
845 void history_begin(history_t* past, char* parameter, U16 frame, TAG* tag, float value)
846 {
847     state_t* first = state_new(frame, CF_PUT, value, 0);
848         past->firstTag = tag;
849         past->firstFrame = frame;
850     dictionary_put2(past->states, parameter, first);
851 }
852
853 void history_beginFilter(history_t* past, U16 frame, TAG* tag, FILTERLIST* value)
854 {
855     filterState_t* first = filterState_new(frame, CF_PUT, value, 0);
856         past->firstTag = tag;
857         past->firstFrame = frame;
858     dictionary_put2(past->states, "filter", first);
859 }
860
861 void history_remember(history_t* past, char* parameter, U16 frame, int function, float value, interpolation_t* inter)
862 {
863     past->lastFrame = frame;
864     state_t* state = dictionary_lookup(past->states, parameter);
865     if (state) //should always be true
866     {
867         state_t* next = state_new(frame, function, value, inter);
868         state_append(state, next);
869     }
870     else
871         syntaxerror("Internal error: changing parameter %s, which is unknown for the instance.", parameter);
872 }
873
874 static float getAngle(float dX, float dY)
875 {
876     float radius = sqrt(dX * dX + dY * dY);
877     if (radius == 0)
878         return 0.0;
879     if (dX >= 0)
880         if (dY > 0)
881             return acos(dX / radius);
882         else
883             return 2 * M_PI - acos(dX / radius);
884     else
885         if (dY > 0)
886             return M_PI - acos(-dX / radius);
887         else
888             return M_PI + acos(-dX / radius);
889 }
890
891 static float getDeltaAngle(float angle1, float angle2, int clockwise)
892         {
893             if (!clockwise)
894             {
895                 if (angle1 > angle2)
896                     return angle2 - angle1;
897                 else
898                     return angle2 - angle1 - 2 * M_PI;
899             }
900             else
901             {
902                 if (angle1 > angle2)
903                     return 2 * M_PI - angle1 + angle2;
904                 else
905                     return angle2 - angle1;
906         }
907 }
908
909 void history_rememberSweep(history_t* past, U16 frame, float x, float y, float r, int clockwise, int short_arc, interpolation_t* inter)
910 {
911     float lastX, lastY, dX, dY;
912     U16 lastFrame;
913
914     past->lastFrame = frame;
915     state_t* change = dictionary_lookup(past->states, "x");
916     if (change) //should always be true
917     {
918         while (change->next)
919             change = change->next;
920         lastFrame = change->frame;
921         lastX = change->value;
922         change = dictionary_lookup(past->states, "y");
923         if (change) //should always be true
924         {
925             while (change->next)
926                 change = change->next;
927             lastY = change->value;
928             dX = x - lastX;
929             dY = y - lastY;
930             if (dX == 0 && dY == 0)
931                 syntaxerror("sweep not possible: startpoint and endpoint must not be equal");
932             if ((dX) * (dX) + (dY) * (dY) > 4 * r * r)
933                 syntaxerror("sweep not possible: radius is to small");
934             if (change->frame > lastFrame)
935             {
936                 lastFrame = change->frame;
937                 history_remember(past, "x", lastFrame, CF_JUMP, lastX, 0);
938             }
939             else
940                 if (change->frame < lastFrame)
941                     history_remember(past, "y", lastFrame, CF_JUMP, lastY, 0);
942             float c1X, c1Y, c2X, c2Y;
943             if (dX == 0) //vertical
944             {
945                 c1Y = c2Y = (lastY + y) / 2;
946                 c1X = x + sqrt(r * r - (c1Y - y) * (c1Y - y));
947                 c2X = 2 * x -c1X;
948             }
949             else
950                 if (dY == 0) //horizontal
951                 {
952                     c1X = c2X = (lastX + x) / 2;
953                     c1Y = y +sqrt(r * r - (c1X - x) * (c1X - x));
954                     c2Y = 2 * y -c1Y;
955                 }
956                 else
957                 {
958                     c1X = sqrt((r * r - (dX * dX + dY * dY) / 4) / (1 + dX * dX / dY / dY));
959                     c2X = -c1X;
960                     c1Y = -dX / dY * c1X;
961                     c2Y = -c1Y;
962                     c1X += (x + lastX) / 2;
963                     c2X += (x + lastX) / 2;
964                     c1Y += (y + lastY) / 2;
965                     c2Y += (y + lastY) / 2;
966                 }
967             float angle1, angle2, delta_angle, centerX, centerY;
968             angle1 = getAngle(lastX - c1X, lastY - c1Y);
969             angle2 = getAngle(x - c1X, y - c1Y);
970             delta_angle = getDeltaAngle(angle1, angle2, clockwise);
971             if ((short_arc && fabs(delta_angle) <= M_PI) || (! short_arc && fabs(delta_angle) >= M_PI))
972             {
973                 centerX = c1X;
974                 centerY = c1Y;
975             }
976             else
977             {
978                 angle1 = getAngle(lastX - c2X, lastY - c2Y);
979                 angle2 = getAngle(x - c2X, y - c2Y);
980                 delta_angle = getDeltaAngle(angle1, angle2, clockwise);
981                 centerX = c2X;
982                 centerY = c2Y;
983             }
984             change = dictionary_lookup(past->states, "x");
985             state_t* nextX = state_new(frame, CF_SWEEP, x, inter);
986             nextX->arc.r = r;
987             nextX->arc.angle = angle1;
988             nextX->arc.delta_angle = delta_angle;
989             nextX->arc.cX = centerX;
990             nextX->arc.cY = centerY;
991             nextX->arc.X = 1;
992             state_append(change, nextX);
993             change = dictionary_lookup(past->states, "y");
994             state_t* nextY = state_new(frame, CF_SWEEP, y, inter);
995             nextY->arc.r = r;
996             nextY->arc.angle = angle1;
997             nextY->arc.delta_angle = delta_angle;
998             nextY->arc.cX = centerX;
999             nextY->arc.cY = centerY;
1000             nextY->arc.X = 0;
1001             state_append(change, nextY);
1002         }
1003         else
1004             syntaxerror("Internal error: changing parameter y in sweep, which is unknown for the instance.");
1005     }
1006     else
1007         syntaxerror("Internal error: changing parameter x in sweep, which is unknown for the instance.");
1008 }
1009
1010 void history_rememberFilter(history_t* past, U16 frame, int function, FILTERLIST* value, interpolation_t* inter)
1011 {
1012     past->lastFrame = frame;
1013     filterState_t* first = dictionary_lookup(past->states, "filter");
1014         if (first) //should always be true
1015         {
1016         filterState_t* next = filterState_new(frame, function, value, inter);
1017         filterState_append(first, next);
1018     }
1019     else
1020         syntaxerror("Internal error: changing a filter not set for the instance.");
1021 }
1022
1023 void history_processFlags(history_t* past)
1024 // to be called after completely recording this history, before calculating any values.
1025 {
1026     state_t* flagState = dictionary_lookup(past->states, "flags");
1027     state_t* nextState;
1028     U16 nextFlags, toggledFlags, currentFlags = (U16)flagState->value;
1029     while (flagState->next)
1030     {
1031         nextState = flagState->next;
1032         nextFlags = (U16)nextState->value;
1033         toggledFlags = currentFlags ^ nextFlags;
1034         if (toggledFlags & IF_FIXED_ALIGNMENT)
1035         { // the IF_FIXED_ALIGNMENT bit will change in the next state
1036             if (nextFlags & IF_FIXED_ALIGNMENT)
1037             { // the IF_FIXED_ALIGNMENT bit will be set
1038                 int onFrame = nextState->frame;
1039                 state_t* rotations = dictionary_lookup(past->states, "rotate");
1040                 nextState->params.instanceAngle = state_value(rotations, onFrame);
1041                 state_t* resetRotate = state_new(onFrame, CF_JUMP, 0, 0);
1042                 state_insert(rotations, resetRotate);
1043                 if (onFrame == past->firstFrame)
1044                     onFrame++;
1045                 state_t *x, *y;
1046                 float dx, dy;
1047                 do
1048                 {
1049                     x = dictionary_lookup(past->states, "x");
1050                     dx = state_tangent(x, onFrame, T_SYMMETRIC);
1051                     y = dictionary_lookup(past->states, "y");
1052                     dy = state_tangent(y, onFrame, T_SYMMETRIC);
1053                     onFrame++;
1054                 }
1055                 while (dx == 0 && dy == 0 && onFrame < past->lastFrame);
1056                 if (onFrame == past->lastFrame)
1057                     nextState->params.pathAngle = 0;
1058                 else
1059                     nextState->params.pathAngle = getAngle(dx, dy) / M_PI * 180;
1060             }
1061             else // the IF_FIXED_ALIGNMENT bit will be reset
1062             {
1063                 int offFrame = nextState->frame;
1064                 state_t* rotations = dictionary_lookup(past->states, "rotate");
1065                 state_t* setRotate = state_new(offFrame, CF_JUMP, flagState->params.instanceAngle + state_value(rotations, offFrame), 0);
1066                 state_insert(rotations, setRotate);
1067             }
1068         }
1069         else // the IF_FIXED_ALIGNMENT bit will not change but some processing may be
1070              // required just the same
1071         {
1072             if (nextFlags & IF_FIXED_ALIGNMENT)
1073             {
1074                 nextState->params.instanceAngle = flagState->params.instanceAngle;
1075                 nextState->params.pathAngle = flagState->params.pathAngle;
1076             }
1077         }
1078 // and so on for all the other bits.
1079         flagState = nextState;
1080         currentFlags = nextFlags;
1081         }
1082 }
1083
1084 int history_change(history_t* past, U16 frame, char* parameter)
1085 {
1086     state_t* first = dictionary_lookup(past->states, parameter);
1087     if (first)  //should always be true.
1088         return state_differs(first, frame);
1089     syntaxerror("no history found to predict changes for parameter %s.\n", parameter);
1090     return 0;
1091 }
1092
1093 float history_value(history_t* past, U16 frame, char* parameter)
1094 {
1095     state_t* state = dictionary_lookup(past->states, parameter);
1096     if (state)  //should always be true.
1097         return state_value(state, frame);
1098     syntaxerror("no history found to get a value for parameter %s.\n", parameter);
1099     return 0;
1100 }
1101
1102 float history_rotateValue(history_t* past, U16 frame)
1103 {
1104     state_t* rotations = dictionary_lookup(past->states, "rotate");
1105     if (rotations)      //should always be true.
1106     {
1107         float angle = state_value(rotations, frame);
1108         state_t* flags = dictionary_lookup(past->states, "flags");
1109         U16 currentflags = state_value(flags, frame);
1110         if (currentflags & IF_FIXED_ALIGNMENT)
1111         {
1112             flags = state_at(flags, frame);
1113             if (frame == past->firstFrame)
1114                 frame++;
1115             state_t *x, *y;
1116             float dx, dy, pathAngle;
1117             do
1118             {
1119                 x = dictionary_lookup(past->states, "x");
1120                 dx = state_value(x, frame) - state_value(x, frame - 1);
1121                 y = dictionary_lookup(past->states, "y");
1122                 dy = state_value(y, frame) - state_value(y, frame - 1);
1123                 frame--;
1124             }
1125             while (dx == 0 && dy == 0 && frame > past->firstFrame);
1126             if (frame == past->firstFrame)
1127                 pathAngle = 0;
1128             else
1129                 pathAngle = getAngle(dx, dy) / M_PI * 180;
1130             return angle + flags->params.instanceAngle + pathAngle - flags->params.pathAngle;
1131         }
1132         else
1133             return angle;
1134     }
1135     syntaxerror("no history found to get a value for parameter rotate.\n");
1136         return 0;
1137 }
1138
1139 int history_changeFilter(history_t* past, U16 frame)
1140 {
1141     filterState_t* first = dictionary_lookup(past->states, "filter");
1142     if (first)  //should always be true.
1143         return filterState_differs(first, frame);
1144     syntaxerror("no history found to predict changes for parameter filter.\n");
1145     return 0;
1146 }
1147
1148 FILTERLIST* history_filterValue(history_t* past, U16 frame)
1149 {
1150     filterState_t* first = dictionary_lookup(past->states, "filter");
1151         if (first)      //should always be true.
1152         return filterState_value(first, frame);
1153     syntaxerror("no history found to get a value for parameter filter.\n");
1154         return 0;
1155 }