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