Huub Schaek's filterlist patch
authorkramm <kramm>
Wed, 8 Aug 2007 21:30:06 +0000 (21:30 +0000)
committerkramm <kramm>
Wed, 8 Aug 2007 21:30:06 +0000 (21:30 +0000)
src/swfc-history.c
src/swfc-history.h
src/swfc-interpolation.c
src/swfc-interpolation.h
src/swfc.c

index 1a8b609..0d74463 100644 (file)
@@ -206,7 +206,7 @@ float change_value(change_t* modification, U16 frame)
        }
 }
 
-changeFilter_t* changeFilter_new(U16 frame, int function, FILTER* value, interpolation_t* inter)
+changeFilter_t* changeFilter_new(U16 frame, int function, FILTERLIST* value, interpolation_t* inter)
 {
        changeFilter_t* newChange = (changeFilter_t*)malloc(sizeof(changeFilter_t));
        changeFilter_init(newChange);
@@ -221,6 +221,7 @@ void changeFilter_free(changeFilter_t *change)
 {
        if (change->next)
                changeFilter_free(change->next);
+    free(change->value);
        free(change);
 }
 
@@ -233,7 +234,46 @@ void changeFilter_append(changeFilter_t* first, changeFilter_t* newChange)
 {
        while (first->next)
                first = first->next;
+    if (!first->value || !newChange->value)
        first->next = newChange;
+    else
+    {
+       int i, mergedCount = 0;
+       int common = first->value->num < newChange->value->num ? first->value->num : newChange->value->num;
+       for (i = 0; i < common; i++)
+       {
+           mergedCount++;
+           if (newChange->value->filter[i]->type != first->value->filter[i]->type)
+               mergedCount++;
+       }
+       mergedCount = mergedCount + first->value->num - common + newChange->value->num - common;
+       if (mergedCount > 8)
+       {
+           char* list1;
+           char* list2;
+           char* newList;
+           list1 = (char*)malloc(1);
+           *list1 = '\0';
+           for (i = 0; i < first->value->num; i++)
+           {
+               newList = (char*)malloc(strlen(list1) + strlen(filtername[first->value->filter[i]->type]) + 2);
+               newList = strcat(strcat(list1, "+"), filtername[first->value->filter[i]->type]);
+               free(list1);
+               list1 = newList;
+           }
+           list2 = (char*)malloc(1);
+           *list2 = '\0';
+           for (i = 0; i < newChange->value->num; i++)
+           {
+               newList = (char*)malloc(strlen(list1) + strlen(filtername[newChange->value->filter[i]->type]) + 2);
+               newList = strcat(strcat(list2, "+"), filtername[newChange->value->filter[i]->type]);
+               free(list2);
+               list2 = newList;
+           }
+           syntaxerror("filterlists %s and %s cannot be interpolated.", list1, list2);
+       }
+       first->next = newChange;
+    }
 }
 
 RGBA interpolateColor(RGBA c1, RGBA c2, float ratio, interpolation_t* inter)
@@ -350,6 +390,37 @@ GRADIENT* interpolateGradient(GRADIENT* g1, GRADIENT* g2, float fraction, interp
            return interpolateNodes(g1, g2, fraction, inter);
 }
 
+FILTER* copyFilter(FILTER* original)
+{
+    if (!original)
+       return original;
+    FILTER* copy = swf_NewFilter(original->type);
+    switch (original->type)
+    {
+       case FILTERTYPE_BLUR:
+           memcpy(copy, original, sizeof(FILTER_BLUR));
+           break;
+       case FILTERTYPE_GRADIENTGLOW:
+       {
+           memcpy(copy, original, sizeof(FILTER_GRADIENTGLOW));
+           FILTER_GRADIENTGLOW* ggcopy = (FILTER_GRADIENTGLOW*)copy;
+           ggcopy->gradient = (GRADIENT*)malloc(sizeof(GRADIENT));
+           ggcopy->gradient->ratios = (U8*)malloc(16 * sizeof(U8));
+           ggcopy->gradient->rgba = (RGBA*)malloc(16 * sizeof(RGBA));
+           copyGradient(ggcopy->gradient, ((FILTER_GRADIENTGLOW*)original)->gradient);
+       }
+           break;
+       case FILTERTYPE_DROPSHADOW:
+           memcpy(copy, original, sizeof(FILTER_DROPSHADOW));
+           break;
+       case FILTERTYPE_BEVEL:
+           memcpy(copy, original, sizeof(FILTER_BEVEL));
+           break;
+       default: syntaxerror("Internal error: unsupported filterype, cannot copy");
+    }
+    return copy;
+}
+
 FILTER* interpolateBlur(FILTER* filter1, FILTER* filter2, float ratio, interpolation_t* inter)
        {
                FILTER_BLUR*f1 = (FILTER_BLUR*)filter1;
@@ -359,7 +430,7 @@ FILTER* interpolateBlur(FILTER* filter1, FILTER* filter2, float ratio, interpola
     if (!f2)
        f2 = noBlur;
     if(f1->blurx == f2->blurx && f1->blury == f2->blury)
-                       return 0;
+       return copyFilter(filter1);
                FILTER_BLUR*f = (FILTER_BLUR*)swf_NewFilter(FILTERTYPE_BLUR);
     f->blurx= interpolateScalar(f1->blurx, (f2->blurx), ratio, inter);
     f->blury= interpolateScalar(f1->blury, (f2->blury), ratio, inter);
@@ -385,7 +456,7 @@ FILTER* interpolateDropshadow(FILTER* filter1,FILTER* filter2, float ratio, inte
     if(!memcmp(&f1->color,&f2->color,sizeof(RGBA)) && f1->strength == f2->strength &&
                                f1->blurx == f2->blurx && f1->blury == f2->blury && 
                                f1->angle == f2->angle && f1->distance == f2->distance)
-                               return 0;
+               return copyFilter(filter1);
                        FILTER_DROPSHADOW*f = (FILTER_DROPSHADOW*)swf_NewFilter(FILTERTYPE_DROPSHADOW);
                        memcpy(f, f1, sizeof(FILTER_DROPSHADOW));
                        f->color = interpolateColor(f1->color, f2->color, ratio, inter);
@@ -430,7 +501,7 @@ FILTER* interpolateBevel(FILTER* filter1,FILTER* filter2, float ratio, interpola
     if(!memcmp(&f1->shadow,&f2->shadow,sizeof(RGBA)) &&
                                        !memcmp(&f1->highlight,&f2->highlight,sizeof(RGBA)) && 
                                        f1->blurx == f2->blurx && f1->blury == f2->blury && f1->angle == f2->angle && f1->strength == f2->strength && f1->distance == f2->distance)
-                                       return 0;
+               return copyFilter(filter1);
                                FILTER_BEVEL*f = (FILTER_BEVEL*)swf_NewFilter(FILTERTYPE_BEVEL);
                                memcpy(f, f1, sizeof(FILTER_BEVEL));
                                f->shadow = interpolateColor(f1->shadow, f2->shadow, ratio, inter);
@@ -477,7 +548,7 @@ FILTER* interpolateGradientGlow(FILTER* filter1,FILTER* filter2, float ratio, in
                !memcmp(&f1->gradient->ratios,&f2->gradient->ratios,f1->gradient->num * sizeof(U8)) &&
                !memcmp(&f1->gradient->rgba,&f2->gradient->rgba,f1->gradient->num * sizeof(RGBA)) &&
                f1->blurx == f2->blurx && f1->blury == f2->blury && f1->angle == f2->angle && f1->strength == f2->strength && f1->distance == f2->distance)
-               return 0;
+               return copyFilter(filter1);
        FILTER_GRADIENTGLOW*f = (FILTER_GRADIENTGLOW*)swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
     memcpy(f, f1, sizeof(FILTER_GRADIENTGLOW));
     f->blurx= interpolateScalar(f1->blurx, (f2->blurx), ratio, inter);
@@ -485,13 +556,6 @@ FILTER* interpolateGradientGlow(FILTER* filter1,FILTER* filter2, float ratio, in
     f->passes= interpolateScalar(f1->passes, (f2->passes), ratio, inter);
     f->angle= interpolateScalar(f1->angle, (f2->angle), ratio, inter);
     f->distance= interpolateScalar(f1->distance, (f2->distance), ratio, inter);
-    double d = f->distance;
-    double fr;
-    if (d < 0)
-       fr = ((int)d - d)*65536;
-    else
-       fr = (d - (int)d)*65536;
-       printf("%.3f <> %.3f : %.3f = %.3f [%.3f . %.3f] - %.5u.%.5u\n", f1->distance, f2->distance, ratio, f->distance, d, fr/65536, (U16)d, (U16)fr);
     f->strength= interpolateScalar(f1->strength, (f2->strength), ratio, inter);
     f->gradient= interpolateGradient(f1->gradient, f2->gradient, ratio, inter);
     if (f1 == noGradientGlow)
@@ -515,7 +579,6 @@ FILTER* interpolateFilter(FILTER* filter1,FILTER* filter2, float ratio, interpol
     if(!filter1 && !filter2)
        return 0;
 
-
     int filter_type;
     if (!filter1)
        filter_type = filter2->type;
@@ -528,7 +591,6 @@ FILTER* interpolateFilter(FILTER* filter1,FILTER* filter2, float ratio, interpol
            else
                filter_type = filter1->type;
 
-
     switch (filter_type)
     {
         case FILTERTYPE_BLUR:
@@ -545,35 +607,90 @@ FILTER* interpolateFilter(FILTER* filter1,FILTER* filter2, float ratio, interpol
        return 0;
 }
 
-FILTER* copyFilter(FILTER* original)
+FILTERLIST* copyFilterList(FILTERLIST* original)
 {
        if (!original)
                return original;
-       FILTER* copy = swf_NewFilter(original->type);
-       switch (original->type)
+    int i;
+    FILTERLIST* copy = (FILTERLIST*)malloc(sizeof(FILTERLIST));
+    copy->num = original->num;
+    for (i = 0; i < copy->num; i++)
+       copy->filter[i] = copyFilter(original->filter[i]);
+    return copy;
+}
+
+FILTER* noFilter(int type)
+{
+    switch (type)
        {
                case FILTERTYPE_BLUR:
-                       memcpy(copy, original, sizeof(FILTER_BLUR));
+           return (FILTER*)noBlur;
                        break;
-               case FILTERTYPE_GRADIENTGLOW:
-       {
-                       memcpy(copy, original, sizeof(FILTER_GRADIENTGLOW));
-           FILTER_GRADIENTGLOW* ggcopy = (FILTER_GRADIENTGLOW*)copy;
-           ggcopy->gradient = (GRADIENT*)malloc(sizeof(GRADIENT));
-           ggcopy->gradient->ratios = (U8*)malloc(16 * sizeof(U8));
-           ggcopy->gradient->rgba = (RGBA*)malloc(16 * sizeof(RGBA));
-           copyGradient(ggcopy->gradient, ((FILTER_GRADIENTGLOW*)original)->gradient);
-       }
+       case FILTERTYPE_BEVEL:
+           return (FILTER*)noBevel;
                        break;
                case FILTERTYPE_DROPSHADOW:
-                       memcpy(copy, original, sizeof(FILTER_DROPSHADOW)); 
+           return (FILTER*)noDropshadow;
                        break;
-               case FILTERTYPE_BEVEL:
-                       memcpy(copy, original, sizeof(FILTER_BEVEL)); 
+       case FILTERTYPE_GRADIENTGLOW:
+           return (FILTER*)noGradientGlow;
                        break;
-       default: syntaxerror("Internal error: unsupported filterype");
+       default:
+           syntaxerror("Internal error: unsupported filtertype, cannot match filterlists");
        }
-       return copy;
+    return 0;
+}
+
+FILTERLIST* interpolateFilterList(FILTERLIST* list1, FILTERLIST* list2, float ratio, interpolation_t* inter)
+{
+    if (!list1 && !list2)
+       return list1;
+    FILTERLIST start, target, dummy;
+    dummy.num = 0;
+    if (!list1)
+       list1 = &dummy;
+    if (!list2)
+       list2 = &dummy;
+    int i, j = 0;
+    int common = list1->num < list2->num ? list1->num : list2->num;
+        for (i = 0; i < common; i++)
+    {
+       start.filter[j] = list1->filter[i];
+       if (list2->filter[i]->type == list1->filter[i]->type)
+       {
+           target.filter[j] = list2->filter[i];
+           j++;
+       }
+       else
+       {
+           target.filter[j] = noFilter(list1->filter[i]->type);
+           j++;
+           start.filter[j] = noFilter(list2->filter[i]->type);
+           target.filter[j] = list2->filter[i];
+           j++;
+       }
+    }
+    if (list1->num > common)
+       for (i = common; i < list1->num; i++)
+       {
+           start.filter[j] = list1->filter[i];
+           target.filter[j] = noFilter(list1->filter[i]->type);
+           j++;
+       }
+    if (list2->num > common)
+       for (i = common; i < list2->num; i++)
+       {
+           start.filter[j] = noFilter(list2->filter[i]->type);
+           target.filter[j] = list2->filter[i];
+           j++;
+       }
+    start.num = j;
+    target.num = j;
+    FILTERLIST* mixedList = (FILTERLIST*)malloc(sizeof(FILTERLIST));
+    mixedList->num = j;
+    for (i = 0; i < j; i++)
+       mixedList->filter[i] = interpolateFilter(start.filter[i], target.filter[i], ratio, inter);
+    return mixedList;
 }
 
 int changeFilter_differs(changeFilter_t* modification, U16 frame)
@@ -591,7 +708,7 @@ int changeFilter_differs(changeFilter_t* modification, U16 frame)
     return (modification->function != CF_JUMP);
 }
 
-FILTER* changeFilter_value(changeFilter_t* modification, U16 frame)
+FILTERLIST* changeFilter_value(changeFilter_t* modification, U16 frame)
 {
     changeFilter_t* previous = modification;
     while (modification && modification->frame < frame)
@@ -600,7 +717,7 @@ FILTER* changeFilter_value(changeFilter_t* modification, U16 frame)
        modification = modification->next;
     }
     if (!modification)
-               return copyFilter(previous->value);
+       return copyFilterList(previous->value);
     if (modification->frame == frame)
        {
                do 
@@ -609,19 +726,19 @@ FILTER* changeFilter_value(changeFilter_t* modification, U16 frame)
            modification = modification->next;
                }
        while (modification && modification->frame == frame);
-       return copyFilter(previous->value);
+       return copyFilterList(previous->value);
        }
     switch (modification->function)
        {
                case CF_PUT:
-           return copyFilter(modification->value);
+           return copyFilterList(modification->value);
                case CF_CHANGE:
                {
            float fraction = (frame - previous->frame) / (float)(modification->frame - previous->frame);
-           return interpolateFilter(previous->value, modification->value, fraction, modification->interpolation);
+           return interpolateFilterList(previous->value, modification->value, fraction, modification->interpolation);
                }
                case CF_JUMP:
-                       return copyFilter(previous->value);
+           return copyFilterList(previous->value);
                default:
                        return 0;
        }
@@ -674,7 +791,7 @@ void history_begin(history_t* past, char* parameter, U16 frame, TAG* tag, float
        dictionary_put2(past->changes, parameter, first);
 }
 
-void history_beginFilter(history_t* past, U16 frame, TAG* tag, FILTER* value)
+void history_beginFilter(history_t* past, U16 frame, TAG* tag, FILTERLIST* value)
 {
        changeFilter_t* first = changeFilter_new(frame, CF_PUT, value, 0);
        past->firstTag = tag;
@@ -692,7 +809,7 @@ void history_remember(history_t* past, char* parameter, U16 frame, int function,
        }
 }
 
-void history_rememberFilter(history_t* past, U16 frame, int function, FILTER* value, interpolation_t* inter)
+void history_rememberFilter(history_t* past, U16 frame, int function, FILTERLIST* value, interpolation_t* inter)
 {
        changeFilter_t* first = dictionary_lookup(past->changes, "filter");
        if (first) //should always be true
@@ -729,7 +846,7 @@ int history_changeFilter(history_t* past, U16 frame)
     return 0;
 }
 
-FILTER* history_valueFilter(history_t* past, U16 frame)
+FILTERLIST* history_valueFilter(history_t* past, U16 frame)
 {
        changeFilter_t* first = dictionary_lookup(past->changes, "filter");
        if (first)      //should always be true.
index b8529df..55c212e 100644 (file)
@@ -53,6 +53,7 @@ enum
 #define SF_FILTER 0x2000
 #define SF_ALL 0x3fff
 
+FILTER* noFilters;
 FILTER_BLUR* noBlur;
 FILTER_BEVEL* noBevel;
 FILTER_DROPSHADOW* noDropshadow;
@@ -82,18 +83,18 @@ float change_value(change_t* first, U16 frame);
 typedef struct _changeFilter
 {
        U16 frame;
-       FILTER* value;
+    FILTERLIST* value;
        int function;
        interpolation_t* interpolation;
        struct _changeFilter* next;
     spline_t spline;
 } changeFilter_t;
 
-changeFilter_t* changeFilter_new(U16 frame, int function, FILTER* value, interpolation_t* inter);
+changeFilter_t* changeFilter_new(U16 frame, int function, FILTERLIST* value, interpolation_t* inter);
 void changeFilter_free(changeFilter_t* change);
 void changeFilter_init(changeFilter_t* change);
 void changeFilter_append(changeFilter_t* first, changeFilter_t* newChange);
-FILTER* changeFilter_value(changeFilter_t* first, U16 frame);
+FILTERLIST* changeFilter_value(changeFilter_t* first, U16 frame);
 
 typedef struct _history
 {
@@ -106,12 +107,12 @@ history_t* history_new();
 void history_free(history_t* past);
 void history_init(history_t* past);
 void history_begin(history_t* past, char* parameter, U16 frame, TAG* tag, float value);
-void history_beginFilter(history_t* past, U16 frame, TAG* tag, FILTER* value);
+void history_beginFilter(history_t* past, U16 frame, TAG* tag, FILTERLIST* value);
 void history_remember(history_t* past, char* parameter, U16 frame, int function, float value, interpolation_t* inter);
-void history_rememberFilter(history_t* past, U16 frame, int function, FILTER* value, interpolation_t* inter);
+void history_rememberFilter(history_t* past, U16 frame, int function, FILTERLIST* value, interpolation_t* inter);
 int history_change(history_t* past, U16 frame, char* parameter);
 float history_value(history_t* past, U16 frame, char* parameter);
 int history_changeFilter(history_t* past, U16 frame);
-FILTER* history_valueFilter(history_t* past, U16 frame);
+FILTERLIST* history_valueFilter(history_t* past, U16 frame);
 
 #endif
index 26c8374..7e845ae 100644 (file)
@@ -140,7 +140,7 @@ float exponentialInOut(float fraction, float start, float delta)
 
 float sineIn(float fraction, float start, float delta)
 {
-       return delta * (1 - cos(fraction * PI/2)) + start;
+       return delta * (1 - cos(fraction * M_PI/2)) + start;
 }
 
 float sineOut(float fraction, float start, float delta)
@@ -164,8 +164,7 @@ float elasticIn(float fraction, float start, float delta, float amplitude, int b
        if (amplitude < fabs(delta))
                amplitude = delta;
        float period = 1 / (bounces + 0.25);
-//     float s = asin(delta / amplitude) - 2 * PI / period;
-       return amplitude * pow(2, damping * (fraction - 1)) * sin(fraction * (2 * PI) / period /*+ fraction * s*/) + start;
+       return amplitude * pow(2, damping * (fraction - 1)) * sin(fraction * (2 * M_PI) / period) + start;
 }
 
 float elasticOut(float fraction, float start, float delta, float amplitude, int bounces, float damping)
index 173ae9b..5e0b59a 100644 (file)
@@ -65,8 +65,6 @@ enum {
        IF_FAST_BOUNCE_IN_OUT = 34
 };
 
-#define PI 3.14159265358979
-
 float linear(float fraction, float start, float delta);
 
 float quadIn(float fraction, float start, float delta);
index a93fea5..8ebb842 100644 (file)
@@ -205,7 +205,7 @@ typedef struct _parameters {
     SPOINT pivot;
     SPOINT pin;
     U8 blendmode; //not interpolated
-    FILTER*filter;
+    FILTERLIST* filters;
     U16 set; // bits indicating wether a parameter was set in the c_placement function
 } parameters_t;
 
@@ -219,8 +219,7 @@ typedef struct _instance {
     character_t*character;
     U16 depth;
     parameters_t parameters;
-    TAG* lastTag; //last tag which set the object
-    U16 lastFrame; //frame lastTag is in
+    U16 deathFrame;
     history_t* history;
 } instance_t;
 
@@ -403,7 +402,7 @@ static void parameters_clear(parameters_t*p)
     p->rotate = 0;
     p->shear = 0;
     p->blendmode = 0;
-    p->filter = 0;
+    p->filters = 0;
     swf_GetCXForm(0, &p->cxform, 1);
 }
 
@@ -416,10 +415,10 @@ static void makeMatrix(MATRIX*m, parameters_t*p)
      *       \r0 sy/ \y/
      */
 
-    sx =  p->scalex*cos(p->rotate/360*2*PI);
-    r1 = -p->scalex*sin(p->rotate/360*2*PI)+sx*p->shear;
-    r0 =  p->scaley*sin(p->rotate/360*2*PI);
-    sy =  p->scaley*cos(p->rotate/360*2*PI)+r0*p->shear;
+    sx =  p->scalex*cos(p->rotate/360*2*M_PI);
+    r1 = -p->scalex*sin(p->rotate/360*2*M_PI)+sx*p->shear;
+    r0 =  p->scaley*sin(p->rotate/360*2*M_PI);
+    sy =  p->scaley*cos(p->rotate/360*2*M_PI)+r0*p->shear;
 
     m->sx = (int)(sx*65536+0.5);
     m->r1 = (int)(r1*65536+0.5);
@@ -538,17 +537,25 @@ void initBuiltIns()
     noGradient->rotate = 0;
     dictionary_put2(&gradients, "no_gradient", noGradient);
 
+    noFilters = 0;
+// put a no_filters entry in the filters dictionary to provoce a message when a user tries
+// to define a no_filters filter. The real filter=no_filters case is handled in parseFilters.
+    char* dummy = (char*)malloc(2);
+    dictionary_put2(&filters, "no_filters", dummy);
     noBlur = (FILTER_BLUR*) swf_NewFilter(FILTERTYPE_BLUR);
     noBlur->passes = 1;
     dictionary_put2(&filters, "no_blur", noBlur);
     noBevel = (FILTER_BEVEL*) swf_NewFilter(FILTERTYPE_BEVEL);
     noBevel->passes = 1;
+    noBevel->composite = 1;
     dictionary_put2(&filters, "no_bevel", noBevel);
     noDropshadow = (FILTER_DROPSHADOW*) swf_NewFilter(FILTERTYPE_DROPSHADOW);
     noDropshadow->passes = 1;
+    noDropshadow->composite = 1;
     dictionary_put2(&filters, "no_dropshadow", noDropshadow);
     noGradientGlow = (FILTER_GRADIENTGLOW*) swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
     noGradientGlow->passes = 1;
+    noGradientGlow->composite = 1;
     noGradientGlow->gradient = &noGradient->gradient;
     dictionary_put2(&filters, "no_gradientglow", noGradientGlow);
 }
@@ -808,6 +815,18 @@ static int parametersChange(history_t* history, int frame)
     return willChange;
 }
 
+static void free_filterlist(FILTERLIST* f_list)
+{
+    int i;
+    for (i = 0; i < f_list->num; i++)
+    {
+        if (f_list->filter[i]->type == FILTERTYPE_GRADIENTGLOW)
+            gradient_free(((FILTER_GRADIENTGLOW*)f_list->filter[i])->gradient);
+        free(f_list->filter[i]);
+    }
+    free(f_list);
+}
+
 static void readParameters(history_t* history, parameters_t* p, int frame)
 {
     p->x = history_value(history, frame, "x");
@@ -829,7 +848,7 @@ static void readParameters(history_t* history, parameters_t* p, int frame)
     p->pin.x = history_value(history, frame, "pin.x");
     p->pin.y = history_value(history, frame, "pin.y");
     p->blendmode = history_value(history, frame, "blendmode");
-    p->filter = history_valueFilter(history, frame);
+    p->filters = history_valueFilter(history, frame);
 }
 
 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move)
@@ -848,11 +867,8 @@ void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*
     if(p->blendmode) {
     po.blendmode = p->blendmode;
     }
-    if(p->filter) {
-    flist.num = 1;
-    flist.filter[0] = p->filter;
-    po.filters = &flist;
-    }
+    if (p->filters)
+       po.filters = p->filters;
     swf_SetPlaceObject(tag, &po);
 }
 
@@ -867,22 +883,24 @@ static void writeInstance(instance_t* i)
         frame++;
         while (tag->id != ST_SHOWFRAME)
             tag = tag->next;
+        if (i->deathFrame == frame)
+        {
+           tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
+           swf_SetU16(tag, i->depth);
+           break;
+        }
         if (parametersChange(i->history, frame))
         {
             readParameters(i->history, &p, frame);
         m = s_instancepos(i->character->size, &p);
 
-        if(p.blendmode || p.filter)
+            if(p.blendmode || p.filters)
             tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
         else
             tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
         setPlacement(tag, 0, i->depth, m, 0, &p, 1);
-        if (p.filter)
-            {
-               if (p.filter->type == FILTERTYPE_GRADIENTGLOW)
-                   gradient_free(((FILTER_GRADIENTGLOW*)p.filter)->gradient);
-            free(p.filter);
-    }
+            if (p.filters)
+               free_filterlist(p.filters);
 }
         else
             tag = tag->next;
@@ -1091,8 +1109,8 @@ int addFillStyle(SHAPE*s, SRECT*r, char*name)
        MATRIX rot,m;
        double ccos,csin;
        swf_GetMatrix(0, &rot);
-    ccos = cos(-gradient->rotate*2*PI/360);
-    csin = sin(-gradient->rotate*2*PI/360);
+       ccos = cos(-gradient->rotate*2*M_PI/360);
+       csin = sin(-gradient->rotate*2*M_PI/360);
        rot.sx =  ccos*65536;
        rot.r1 = -csin*65536;
        rot.r0 =  csin*65536;
@@ -1663,6 +1681,44 @@ GRADIENT parseGradient(const char*str)
     return gradient;
 }
 
+FILTERLIST* parseFilters(char* list)
+{
+    if (!strcmp(list, "no_filters"))
+       return noFilters;
+    FILTER* f;
+    FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
+    f_list->num = 0;
+    char* f_start = list;
+    char* f_end;
+    while (f_start)
+    {
+       f_end = strchr(f_start, ',');
+       if (f_end)
+           *f_end = '\0';
+       f = dictionary_lookup(&filters, f_start);
+       if (!f)
+       {
+           free(f_list);
+           syntaxerror("unknown filter %s", f_start);
+       }
+       if (f_list->num == 8)
+       {
+           warning("too many filters in filterlist, no more than 8 please, rest ignored");
+           break;
+       }
+       f_list->filter[f_list->num] = f;
+       f_list->num++;
+       if (f_end)
+       {
+           *f_end = ',';
+           f_start = f_end + 1;
+       }
+       else
+           f_start = 0;
+    }
+    return f_list;
+}
+
 void s_gradient(char*name, const char*text, int radial, int rotate)
 {
     gradient_t* gradient;
@@ -1986,8 +2042,6 @@ void s_startclip(char*instance, char*character, parameters_t p)
     tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
     /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
     swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
-    i->lastTag = tag;
-    i->lastFrame= currentframe;
 
     stack[stackpos].tag = tag;
     stack[stackpos].type = 2;
@@ -2029,7 +2083,7 @@ void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
     history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
     history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
     history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
-    history_beginFilter(i->history, currentframe, tag, p->filter);
+    history_beginFilter(i->history, currentframe, tag, p->filters);
 }
 
 void s_put(char*instance, char*character, parameters_t p)
@@ -2044,7 +2098,7 @@ void s_put(char*instance, char*character, parameters_t p)
     i->parameters = p;
     m = s_instancepos(i->character->size, &p);
 
-    if(p.blendmode || p.filter)
+    if(p.blendmode || p.filters)
     {
         if(stack[0].swf->fileVersion < 8)
         {
@@ -2059,8 +2113,6 @@ void s_put(char*instance, char*character, parameters_t p)
         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
     setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
     setStartparameters(i, &p, tag);
-    i->lastTag = tag;
-    i->lastFrame = currentframe;
     currentdepth++;
 }
 
@@ -2111,7 +2163,7 @@ void recordChanges(history_t* history, parameters_t p, int changeFunction, inter
     if (p.set & SF_BLEND)
         history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
     if (p.set & SF_FILTER)
-        history_rememberFilter(history, currentframe, changeFunction, p.filter, inter);
+        history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
 }
 
 void s_jump(char* instance, parameters_t p)
@@ -2136,9 +2188,7 @@ void s_delinstance(char*instance)
     instance_t* i = dictionary_lookup(&instances, instance);
     if(!i)
         syntaxerror("instance %s not known", instance);
-    tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
-    swf_SetU16(tag, i->depth);
-    dictionary_del(&instances, instance);
+    i->deathFrame = currentframe;
 }
 
 void s_qchange(char*instance, parameters_t p)
@@ -2669,9 +2719,17 @@ static int c_gradient(map_t*args)
     return 0;
 }
 
-static int c_blur(map_t*args)
+static char* checkFiltername(map_t* args)
 {
     char*name = lu(args, "name");
+    if (strchr(name, ','))
+       syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
+    return name;
+}
+
+static int c_blur(map_t*args)
+{
+    char*name = checkFiltername(args);
     char*blurstr = lu(args, "blur");
     char*blurxstr = lu(args, "blurx");
     char*blurystr = lu(args, "blury");
@@ -2691,7 +2749,7 @@ static int c_blur(map_t*args)
 
 static int c_gradientglow(map_t*args)
 {
-    char*name = lu(args, "name");
+    char*name = checkFiltername(args);
     char*gradient = lu(args, "gradient");
     char*blurstr = lu(args, "blur");
     char*blurxstr = lu(args, "blurx");
@@ -2721,7 +2779,7 @@ static int c_gradientglow(map_t*args)
 
 static int c_dropshadow(map_t*args)
 {
-    char*name = lu(args, "name");
+    char*name = checkFiltername(args);
     RGBA color = parseColor(lu(args, "color"));
     char*blurstr = lu(args, "blur");
     char*blurxstr = lu(args, "blurx");
@@ -2750,7 +2808,7 @@ static int c_dropshadow(map_t*args)
 
 static int c_bevel(map_t*args)
 {
-    char*name = lu(args, "name");
+    char*name = checkFiltername(args);
     RGBA shadow = parseColor(lu(args, "shadow"));
     RGBA highlight = parseColor(lu(args, "highlight"));
     char*blurstr = lu(args, "blur");
@@ -3092,10 +3150,7 @@ static int c_placement(map_t*args, int type)
 
     if(filterstr[0])
     {
-        FILTER*f = dictionary_lookup(&filters, filterstr);
-        if(!f)
-            syntaxerror("Unknown filter %s", filterstr);
-        p.filter = f;
+        p.filters = parseFilters(filterstr);
         set = set | SF_FILTER;
     }