added -Q option
[swftools.git] / src / swfc.c
index f4d55da..c07a8a0 100644 (file)
@@ -4,7 +4,7 @@
    Part of the swftools package.
 
    Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
@@ -36,8 +36,9 @@
 #include "../lib/wav.h"
 #include "parser.h"
 #include "../lib/png.h"
-#include "../lib/interpolation.h"
-#include "../lib/history.h"
+#include "swfc-feedback.h"
+#include "swfc-interpolation.h"
+#include "swfc-history.h"
 
 //#define DEBUG
 static char * outputname = "output.swf";
@@ -45,6 +46,7 @@ static int verbose = 2;
 static int optimize = 0;
 static int override_outputname = 0;
 static int do_cgi = 0;
+static int change_sets_all = 0;
 
 static struct options_t options[] = {
 {"h", "help"},
@@ -54,7 +56,7 @@ static struct options_t options[] = {
 {"o", "output"},
 {0,0}
 };
-    
+
 int args_callback_option(char*name,char*val)
 {
     if(!strcmp(name, "V")) {
@@ -152,6 +154,19 @@ static int noMoreTokens()
     return 0;
 }
 
+enum
+{
+    PT_PUT = 0,
+    PT_CHANGE = 1,
+    PT_SCHANGE = 2,
+    PT_MOVE = 3,
+    PT_SMOVE = 4,
+    PT_SWEEP = 5,
+    PT_JUMP = 6,
+    PT_STARTCLIP = 7,
+    PT_BUTTON = 8
+};
+
 // ------------------------------ swf routines ----------------------------
 struct _character;
 static struct level
@@ -160,7 +175,7 @@ static struct level
 
    /* for swf (0): */
    SWF*swf;
-   char*filename; 
+   char*filename;
 
    /* for sprites (1): */
    TAG*tag;
@@ -195,16 +210,17 @@ static dictionary_t sounds;
 static dictionary_t fontUsage;
 
 typedef struct _parameters {
-    int x,y; 
-    float scalex, scaley; 
+    int x,y;
+    float scalex, scaley;
     CXFORM cxform;
     float rotate;
     float shear;
     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
+    U16 flags; // bits to toggle anything you may care to implement as a toggle
 } parameters_t;
 
 typedef struct _character {
@@ -217,8 +233,6 @@ 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
     history_t* history;
 } instance_t;
 
@@ -254,31 +268,6 @@ char* interpolationFunctions[] = {"linear", \
         "bounceIn", "bounceOut", "bounceInOut", \
         "fastBounceIn", "fastBounceOut", "fastBounceInOut"};
 
-typedef struct _fontData {
-    char *glyphs;
-    int notUsed, needsAll;
-} fontData;
-
-void addFontData(char *name)
-{
-    fontData* newFont;
-    newFont = (fontData *)malloc(sizeof(fontData));
-    memset(newFont, 0, sizeof(fontData));
-    newFont->notUsed = 1;
-    dictionary_put2(&fontUsage, name, newFont);
-}
-
-void freeFontData(fontData* font)
-{
-    free(font->glyphs);
-    free(font);
-}
-
-fontData *getFontData(char *name)
-{
-    return (fontData *)dictionary_lookup(&fontUsage, name);
-}
-
 static void character_init(character_t*c)
 {
     memset(c, 0, sizeof(character_t));
@@ -322,11 +311,6 @@ static void free_font(void* f)
     swf_FontFree((SWFFONT*)f);
 }
 
-static void free_fontData(void* fd)
-{
-    freeFontData((fontData*)fd);
-}
-
 static void gradient_free(GRADIENT* grad)
 {
     free(grad->ratios);
@@ -353,8 +337,8 @@ static void free_outline(void* o)
 
 static void freeDictionaries()
 {
-   dictionary_free_all(&instances, free_instance);
-   dictionary_free_all(&characters, free);
+    dictionary_free_all(&instances, free_instance);
+    dictionary_free_all(&characters, free);
     dictionary_free_all(&images, free);
     dictionary_free_all(&textures, free);
     dictionary_free_all(&outlines, free_outline);
@@ -362,10 +346,14 @@ static void freeDictionaries()
     dictionary_free_all(&filters, free);
     dictionary_free_all(&fonts, free_font);
     dictionary_free_all(&sounds, free);
-    dictionary_free_all(&fontUsage, free_fontData);
     dictionary_free_all(&interpolations, free);
 }
 
+static void freeFontDictionary()
+{
+    dictionary_free_all(&fonts, free_font);
+}
+
 static void incrementid()
 {
     while(idmap[++id]) {
@@ -380,7 +368,7 @@ static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
     if(dictionary_lookup(&characters, name))
         syntaxerror("character %s defined twice", name);
     character_t* c = character_new();
-    
+
     c->definingTag = ctag;
     c->id = id;
     c->size = r;
@@ -398,7 +386,7 @@ static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
 {
     if(dictionary_lookup(&images, name))
         syntaxerror("image %s defined twice", name);
-        
+
     character_t* c = character_new();
     c->definingTag = ctag;
     c->id = id;
@@ -419,15 +407,15 @@ static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
 
 static void parameters_clear(parameters_t*p)
 {
-    p->x = 0; p->y = 0; 
+    p->x = 0; p->y = 0;
     p->scalex = 1.0; p->scaley = 1.0;
     p->pin.x = 0;  //1??
     p->pin.y = 0;
     p->pivot.x = 0; p->pivot.y = 0;
-    p->rotate = 0; 
-    p->shear = 0; 
+    p->rotate = 0;
+    p->shear = 0;
     p->blendmode = 0;
-    p->filter = 0;
+    p->filters = 0;
     swf_GetCXForm(0, &p->cxform, 1);
 }
 
@@ -436,14 +424,14 @@ static void makeMatrix(MATRIX*m, parameters_t*p)
     SPOINT h;
     float sx,r1,r0,sy;
 
-    /*       /sx r1\ /x\ 
+    /*       /sx r1\ /x\
      *       \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);
@@ -451,7 +439,7 @@ static void makeMatrix(MATRIX*m, parameters_t*p)
     m->sy = (int)(sy*65536+0.5);
 
     m->tx = m->ty = 0;
-   
+
     h = swf_TurnPoint(p->pin, m);
     m->tx = p->x - h.x;
     m->ty = p->y - h.y;
@@ -463,7 +451,7 @@ static MATRIX s_instancepos(SRECT rect, parameters_t*p)
     SRECT r;
     makeMatrix(&m, p);
     r = swf_TurnRect(rect, &m);
-    if(currentrect.xmin == 0 && currentrect.ymin == 0 && 
+    if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
        currentrect.xmax == 0 && currentrect.ymax == 0)
        currentrect = r;
     else
@@ -471,7 +459,7 @@ static MATRIX s_instancepos(SRECT rect, parameters_t*p)
     return m;
 }
 
-void builtInInterpolations()
+void initBuiltIns()
 {
     interpolation_t* new;
     new = (interpolation_t*)malloc(sizeof(interpolation_t));
@@ -480,42 +468,54 @@ void builtInInterpolations()
 
     new = (interpolation_t*)malloc(sizeof(interpolation_t));
     new->function = IF_QUAD_IN;
+    new->slope = 0;
     dictionary_put2(&interpolations, "quadIn", new);
     new = (interpolation_t*)malloc(sizeof(interpolation_t));
     new->function = IF_QUAD_OUT;
+    new->slope = 0;
     dictionary_put2(&interpolations, "quadOut", new);
     new = (interpolation_t*)malloc(sizeof(interpolation_t));
     new->function = IF_QUAD_IN_OUT;
+    new->slope = 0;
     dictionary_put2(&interpolations, "quadInOut", new);
 
     new = (interpolation_t*)malloc(sizeof(interpolation_t));
     new->function = IF_CUBIC_IN;
+    new->slope = 0;
     dictionary_put2(&interpolations, "cubicIn", new);
     new = (interpolation_t*)malloc(sizeof(interpolation_t));
     new->function = IF_CUBIC_OUT;
+    new->slope = 0;
     dictionary_put2(&interpolations, "cubicOut", new);
     new = (interpolation_t*)malloc(sizeof(interpolation_t));
     new->function = IF_CUBIC_IN_OUT;
+    new->slope = 0;
     dictionary_put2(&interpolations, "cubicInOut", new);
 
     new = (interpolation_t*)malloc(sizeof(interpolation_t));
     new->function = IF_QUART_IN;
+    new->slope = 0;
     dictionary_put2(&interpolations, "quartIn", new);
     new = (interpolation_t*)malloc(sizeof(interpolation_t));
     new->function = IF_QUART_OUT;
+    new->slope = 0;
     dictionary_put2(&interpolations, "quartOut", new);
     new = (interpolation_t*)malloc(sizeof(interpolation_t));
     new->function = IF_QUART_IN_OUT;
+    new->slope = 0;
     dictionary_put2(&interpolations, "quartInOut", new);
 
     new = (interpolation_t*)malloc(sizeof(interpolation_t));
     new->function = IF_QUINT_IN;
+    new->slope = 0;
     dictionary_put2(&interpolations, "quintIn", new);
     new = (interpolation_t*)malloc(sizeof(interpolation_t));
     new->function = IF_QUINT_OUT;
+    new->slope = 0;
     dictionary_put2(&interpolations, "quintOut", new);
     new = (interpolation_t*)malloc(sizeof(interpolation_t));
     new->function = IF_QUINT_IN_OUT;
+    new->slope = 0;
     dictionary_put2(&interpolations, "quintInOut", new);
 
     new = (interpolation_t*)malloc(sizeof(interpolation_t));
@@ -547,6 +547,42 @@ void builtInInterpolations()
     new = (interpolation_t*)malloc(sizeof(interpolation_t));
     new->function = IF_SINE_IN_OUT;
     dictionary_put2(&interpolations, "sineInOut", new);
+
+    RGBA c;
+    memset(&c, 0, sizeof(RGBA));
+    gradient_t* noGradient = (gradient_t*)malloc(sizeof(gradient_t));
+    noGradient->gradient.ratios = (U8*)malloc(16 * sizeof(U8));
+    noGradient->gradient.rgba = (RGBA*)malloc(16 * sizeof(RGBA));
+    noGradient->gradient.num = 2;
+    noGradient->gradient.rgba[0] = c;
+    noGradient->gradient.ratios[0] = 0;
+    noGradient->gradient.rgba[1] = c;
+    noGradient->gradient.ratios[1] = 255;
+    noGradient->radial = 0;
+    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.
+    FILTER* dummy = (FILTER*)malloc(sizeof(FILTER));
+    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);
 }
 
 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
@@ -555,7 +591,7 @@ void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA backgrou
         syntaxerror(".swf blocks can't be nested");
     if(stackpos==sizeof(stack)/sizeof(stack[0]))
         syntaxerror("too many levels of recursion");
-        
+
     SWF*swf = (SWF*)malloc(sizeof(SWF));
 
     memset(swf, 0, sizeof(swf));
@@ -565,7 +601,7 @@ void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA backgrou
     swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
     swf->compressed = compress;
     swf_SetRGB(tag,&background);
-    
+
     dictionary_init(&characters);
     dictionary_init(&images);
     dictionary_init(&textures);
@@ -573,10 +609,9 @@ void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA backgrou
     dictionary_init(&gradients);
     dictionary_init(&filters);
     dictionary_init(&instances);
-    dictionary_init(&fonts);
     dictionary_init(&sounds);
     dictionary_init(&interpolations);
-    builtInInterpolations();
+    initBuiltIns();
     cleanUp = &freeDictionaries;
 
     memset(&stack[stackpos], 0, sizeof(stack[0]));
@@ -585,12 +620,11 @@ void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA backgrou
     stack[stackpos].swf = swf;
     stack[stackpos].oldframe = -1;
     stackpos++;
-    id = 0;
 
     currentframe = 0;
     memset(&currentrect, 0, sizeof(currentrect));
     currentdepth = 1;
-    
+
     memset(idmap, 0, sizeof(idmap));
     incrementid();
 }
@@ -610,7 +644,7 @@ void s_sprite(char*name)
     stack[stackpos].tag = tag;
     stack[stackpos].id = id;
     stack[stackpos].name = strdup(name);
-   
+
     /* FIXME: those four fields should be bundled together */
     dictionary_init(&instances);
     currentframe = 0;
@@ -673,7 +707,7 @@ void s_buttonput(char*character, char*as, parameters_t p)
     if(mybutton.endofshapes) {
        syntaxerror("a .do may not precede a .show", character, character);
     }
-   
+
     m = s_instancepos(c->size, &p);
 
     r.id = c->id;
@@ -700,7 +734,7 @@ static void setbuttonrecords(TAG*tag)
     int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
     if(!mybutton.endofshapes) {
        int t;
-               
+
        if(!mybutton.records[3].set) {
            memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
        }
@@ -722,7 +756,7 @@ void s_buttonaction(int flags, char*action)
        return;
     }
     setbuttonrecords(stack[stackpos-1].tag);
-    
+
     a = swf_ActionCompile(text, stack[0].swf->fileVersion);
     if(!a) {
        syntaxerror("Couldn't compile ActionScript");
@@ -754,7 +788,7 @@ static void s_endButton()
     setbuttonrecords(stack[stackpos-1].tag);
     setactionend(stack[stackpos-1].tag);
     stackpos--;
-      
+
     swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
 
     r = currentrect;
@@ -778,6 +812,46 @@ TAG* removeFromTo(TAG*from, TAG*to)
     return save;
 }
 
+static int parametersChange(history_t* history, int frame)
+{
+    int willChange = 0;
+
+    willChange = willChange || history_change(history, frame, "x");
+    willChange = willChange || history_change(history, frame, "y");
+    willChange = willChange || history_change(history, frame, "scalex");
+    willChange = willChange || history_change(history, frame, "scaley");
+    willChange = willChange || history_change(history, frame, "cxform.r0");
+    willChange = willChange || history_change(history, frame, "cxform.g0");
+    willChange = willChange || history_change(history, frame, "cxform.b0");
+    willChange = willChange || history_change(history, frame, "cxform.a0");
+    willChange = willChange || history_change(history, frame, "cxform.r1");
+    willChange = willChange || history_change(history, frame, "cxform.g1");
+    willChange = willChange || history_change(history, frame, "cxform.b1");
+    willChange = willChange || history_change(history, frame, "cxform.a1");
+    willChange = willChange || history_change(history, frame, "rotate");
+    willChange = willChange || history_change(history, frame, "shear");
+    willChange = willChange || history_change(history, frame, "pivot.x");
+    willChange = willChange || history_change(history, frame, "pivot.y");
+    willChange = willChange || history_change(history, frame, "pin.x");
+    willChange = willChange || history_change(history, frame, "pin.y");
+    willChange = willChange || history_change(history, frame, "blendmode");
+    willChange = willChange || history_changeFilter(history, 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");
@@ -792,14 +866,14 @@ static void readParameters(history_t* history, parameters_t* p, int frame)
     p->cxform.g1 = history_value(history, frame, "cxform.g1");
     p->cxform.b1 = history_value(history, frame, "cxform.b1");
     p->cxform.a1 = history_value(history, frame, "cxform.a1");
-    p->rotate = history_value(history, frame, "rotate");
+    p->rotate = history_rotateValue(history, frame);
     p->shear = history_value(history, frame, "shear");
     p->pivot.x = history_value(history, frame, "pivot.x");
     p->pivot.y = history_value(history, frame, "pivot.y");
     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_filterValue(history, frame);
 }
 
 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move)
@@ -818,11 +892,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);
 }
 
@@ -832,21 +903,27 @@ static void writeInstance(instance_t* i)
     MATRIX m;
     int frame = i->history->firstFrame;
     TAG* tag = i->history->firstTag;
+    history_processFlags(i->history);
     while (frame < currentframe)
     {
         frame++;
-        readParameters(i->history, &p, frame);
         while (tag->id != ST_SHOWFRAME)
             tag = tag->next;
-        m = s_instancepos(i->character->size, &p);
+        if (parametersChange(i->history, frame))
+        {
+            readParameters(i->history, &p, frame);
+            m = s_instancepos(i->character->size, &p);
 
-        if(p.blendmode || p.filter)
-            tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
+            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.filters)
+               free_filterlist(p.filters);
+        }
         else
-            tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
-        setPlacement(tag, 0, i->depth, m, 0, &p, 1);
-        if (p.filter)
-            free(p.filter);        
+            tag = tag->next;
     }
 }
 
@@ -864,23 +941,26 @@ void dumpSWF(SWF*swf)
 static void s_endSprite()
 {
     SRECT r = currentrect;
-    
+
     if(stack[stackpos].cut)
        tag = removeFromTo(stack[stackpos].cut, tag);
 
     stackpos--;
     instance_t *i;
     stringarray_t* index =dictionary_index(&instances);
-    int num = 0;
-    char* name = stringarray_at(index, num);
-    while (name)
+    int num;
+    for (num = 0; num < dictionary_count(&instances); num++)
     {
-        i = dictionary_lookup(&instances, name);
-        writeInstance(i);
-        num++;
-        name = stringarray_at(index, num);
+       char* name = stringarray_at(index, num);
+       if (name)
+       {
+            i = dictionary_lookup(&instances, name);
+            writeInstance(i);
+       }
     }
-    
+    while (tag->next)
+       tag = tag->next;
+
     tag = swf_InsertTag(tag, ST_SHOWFRAME);
     tag = swf_InsertTag(tag, ST_END);
 
@@ -906,27 +986,28 @@ static void s_endSWF()
     int fi;
     SWF* swf;
     char*filename;
-    
+
     instance_t *i;
-    stringarray_t* index =dictionary_index(&instances);
-    int num = 0;
-    char* name = stringarray_at(index, num);
-    while (name)
+    stringarray_t* index = dictionary_index(&instances);
+    int num;
+    for (num = 0; num < dictionary_count(&instances); num++)
     {
-        i = dictionary_lookup(&instances, name);
-        writeInstance(i);
-        num++;
-        name = stringarray_at(index, num);
+       char* name = stringarray_at(index, num);
+       if (name)
+       {
+            i = dictionary_lookup(&instances, name);
+            writeInstance(i);
+       }
     }
 
     if(stack[stackpos].cut)
        tag = removeFromTo(stack[stackpos].cut, tag);
 
     stackpos--;
-   
+
     swf = stack[stackpos].swf;
     filename = stack[stackpos].filename;
-  
+
     //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
     //    tag = swf_InsertTag(tag, ST_SHOWFRAME);
     tag = swf_InsertTag(tag, ST_SHOWFRAME);
@@ -934,21 +1015,21 @@ static void s_endSWF()
     tag = swf_InsertTag(tag, ST_END);
 
     swf_OptimizeTagOrder(swf);
-   
+
     if(optimize) {
        swf_Optimize(swf);
     }
-    
+
     if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
        swf->movieSize = currentrect; /* "autocrop" */
     }
-    
+
     if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
        swf->movieSize.xmax += 20; /* 1 by 1 pixels */
        swf->movieSize.ymax += 20;
        warning("Empty bounding box for movie");
     }
-    
+
     if(do_cgi || !strcmp(filename, "-"))
        fi = fileno(stdout);
     else
@@ -958,8 +1039,6 @@ static void s_endSWF()
     }
     if(do_cgi)
        {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
-    else if(swf->compressed) 
-       {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
     else
        {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
 
@@ -994,7 +1073,7 @@ void s_frame(int nr, int cut, char*name, char anchor)
     int t;
     TAG*now = tag;
 
-    if(nr<1) 
+    if(nr<1)
        syntaxerror("Illegal frame number");
     nr--; // internally, frame 1 is frame 0
 
@@ -1050,8 +1129,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;
@@ -1072,7 +1151,7 @@ int addFillStyle(SHAPE*s, SRECT*r, char*name)
        return 0;
     }
 }
-       
+
 RGBA black={r:0,g:0,b:0,a:0};
 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
 {
@@ -1106,7 +1185,7 @@ void s_box(char*name, int width, int height, RGBA color, int linewidth, char*tex
     swf_ShapeSetLine(tag,s,0,-height);
     swf_ShapeSetEnd(tag);
     swf_ShapeFree(s);
-   
+
     s_addcharacter(name, id, tag, r);
     incrementid();
 }
@@ -1131,7 +1210,7 @@ void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*textu
     }
     if(texture)
        fs1 = addFillStyle(s, &r2, texture);
-    
+
     swf_SetU16(tag,id);
     rect.xmin = r2.xmin-linewidth/2;
     rect.ymin = r2.ymin-linewidth/2;
@@ -1141,7 +1220,7 @@ void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*textu
     swf_SetRect(tag,&rect);
     swf_SetShapeStyles(tag, s);
     swf_ShapeCountBits(s,0,0);
-    swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line, 
+    swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
                         &s->data,             &s->bitlen,             s->bits.fill,              s->bits.line);
     swf_SetShapeBits(tag, s);
     swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
@@ -1180,7 +1259,7 @@ void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
     swf_ShapeSetCircle(tag, s, r,r,r,r);
     swf_ShapeSetEnd(tag);
     swf_ShapeFree(s);
-   
+
     s_addcharacter(name, id, tag, rect);
     incrementid();
 }
@@ -1195,7 +1274,7 @@ void s_textshape(char*name, char*fontname, float size, char*_text)
     font = dictionary_lookup(&fonts, fontname);
     if(!font)
        syntaxerror("font \"%s\" not known!", fontname);
-    
+
     if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
        warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
        s_box(name, 0, 0, black, 20, 0);
@@ -1207,7 +1286,7 @@ void s_textshape(char*name, char*fontname, float size, char*_text)
     memset(outline, 0, sizeof(outline_t));
     outline->shape = font->glyph[g].shape;
     outline->bbox = font->layout->bounds[g];
-    
+
     {
        drawer_t draw;
        swf_Shape11DrawerInit(&draw, 0);
@@ -1231,7 +1310,7 @@ void s_text(char*name, char*fontname, char*text, int size, RGBA color)
     font = dictionary_lookup(&fonts, fontname);
     if(!font)
        syntaxerror("font \"%s\" not known!", fontname);
-    
+
     tag = swf_InsertTag(tag, ST_DEFINETEXT2);
     swf_SetU16(tag, id);
     if(!font->numchars) {
@@ -1248,7 +1327,7 @@ void s_text(char*name, char*fontname, char*text, int size, RGBA color)
        swf_SetU32(tag, 0);//sharpness
        swf_SetU8(tag, 0);//reserved
     }
-   
+
     s_addcharacter(name, id, tag, r);
     incrementid();
 }
@@ -1259,11 +1338,11 @@ void s_quicktime(char*name, char*url)
     MATRIX _m,*m=0;
 
     memset(&r, 0, sizeof(r));
-    
+
     tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
     swf_SetU16(tag, id);
     swf_SetString(tag, url);
-    
+
     s_addcharacter(name, id, tag, r);
     incrementid();
 }
@@ -1291,7 +1370,7 @@ void s_edittext(char*name, char*fontname, int size, int width, int height, char*
     r.ymin = 0;
     r.xmax = width;
     r.ymax = height;
-    
+
     swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
 
     s_addcharacter(name, id, tag, r);
@@ -1304,7 +1383,7 @@ void s_image(char*name, char*type, char*filename, int quality)
 {
     /* an image is actually two folded: 1st bitmap, 2nd character.
        Both of them can be used separately */
-    
+
     /* step 1: the bitmap */
     SRECT r;
     int imageID = id;
@@ -1432,22 +1511,10 @@ void s_texture(char*name, char*object, int x, int y, float scalex, float scaley,
     dictionary_put2(&textures, name, texture);
 }
 
-void s_font(char*name, char*filename, char *glyphs)
+void s_font(char*name, char*filename)
 {
-    if(dictionary_lookup(&fonts, name))
-        syntaxerror("font %s defined twice", name);
-        
     SWFFONT* font;
-    font = swf_LoadFont(filename, glyphs);
-   
-    if(font == 0) {
-       warning("Couldn't open font file \"%s\"", filename);
-       font = (SWFFONT*)malloc(sizeof(SWFFONT));
-       memset(font, 0, sizeof(SWFFONT));
-       dictionary_put2(&fonts, name, font);
-       return;
-    }
-
+    font = dictionary_lookup(&fonts, name);
     if(0)
     {
        /* fix the layout. Only needed for old fonts */
@@ -1458,19 +1525,16 @@ void s_font(char*name, char*filename, char *glyphs)
        font->layout = 0;
        swf_FontCreateLayout(font);
     }
-    /* just in case this thing is used in .edittext later on */
-    swf_FontPrepareForEditText(font);
-
     font->id = id;
+       swf_FontReduce_swfc(font);
     tag = swf_InsertTag(tag, ST_DEFINEFONT2);
     swf_FontSetDefine2(tag, font);
     tag = swf_InsertTag(tag, ST_EXPORTASSETS);
     swf_SetU16(tag, 1);
     swf_SetU16(tag, id);
     swf_SetString(tag, name);
-    incrementid();
 
-    dictionary_put2(&fonts, name, font);
+    incrementid();
 }
 
 
@@ -1493,7 +1557,7 @@ void s_sound(char*name, char*filename)
 
     if(dictionary_lookup(&sounds, name))
         syntaxerror("sound %s defined twice", name);
-        
+
     if(wav_read(&wav, filename))
     {
         int t;
@@ -1520,7 +1584,7 @@ void s_sound(char*name, char*filename)
             samples = 0;
             numsamples = 0;
         }
-    
+
     if(numsamples%blocksize != 0)
     {
        // apply padding, so that block is a multiple of blocksize
@@ -1549,7 +1613,7 @@ void s_sound(char*name, char*filename)
     }
     else
         swf_SetSoundDefine(tag, samples, numsamples);
-    
+
     tag = swf_InsertTag(tag, ST_NAMECHARACTER);
     swf_SetU16(tag, id);
     swf_SetString(tag, name);
@@ -1563,7 +1627,7 @@ void s_sound(char*name, char*filename)
     sound->id = id;
 
     dictionary_put2(&sounds, name, sound);
-    
+
     incrementid();
 
     if (samples)
@@ -1576,7 +1640,7 @@ static char* gradient_getToken(const char**p)
     char*result;
     while(**p && strchr(" \t\n\r", **p)) {
        (*p)++;
-    } 
+    }
     start = *p;
     while(**p && !strchr(" \t\n\r", **p)) {
        (*p)++;
@@ -1598,7 +1662,7 @@ GRADIENT parseGradient(const char*str)
     memset(&gradient, 0, sizeof(GRADIENT));
     gradient.ratios = rfx_calloc(16*sizeof(U8));
     gradient.rgba = rfx_calloc(16*sizeof(RGBA));
-    
+
     while(*p)
     {
         char*posstr,*colorstr;
@@ -1637,6 +1701,44 @@ GRADIENT parseGradient(const char*str)
     return gradient;
 }
 
+FILTERLIST* parseFilters(char* list)
+{
+    if (!strcmp(list, "no_filters"))
+       return 0;
+    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;
@@ -1648,20 +1750,20 @@ void s_gradient(char*name, const char*text, int radial, int rotate)
 
     dictionary_put2(&gradients, name, gradient);
 }
-    
-void s_gradientglow(char*name, char*gradient, float blurx, float blury, 
-                   float angle, float distance, float strength, char innershadow, 
+
+void s_gradientglow(char*name, char*gradient, float blurx, float blury,
+                   float angle, float distance, float strength, char innershadow,
                    char knockout, char composite, char ontop, int passes)
 {
     if(dictionary_lookup(&filters, name))
         syntaxerror("filter %s defined twice", name);
-    
+
     gradient_t* g = dictionary_lookup(&gradients, gradient);
+    if(!g)
+       syntaxerror("unknown gradient %s", gradient);
 
     composite = 1;
 
-    if(!g)
-       syntaxerror("unknown gradient %s", gradient);
     FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
     filter->type = FILTERTYPE_GRADIENTGLOW;
     filter->gradient = &g->gradient;
@@ -1761,7 +1863,7 @@ void s_initaction(const char*character, const char*text)
     ActionTAG* a = 0;
     character_t*c = 0;
     a = swf_ActionCompile(text, stack[0].swf->fileVersion);
-    if(!a) 
+    if(!a)
     {
         swf_ActionFree(a);
         syntaxerror("Couldn't compile ActionScript");
@@ -1780,7 +1882,7 @@ int s_swf3action(char*name, char*action)
 {
     ActionTAG* a = 0;
     instance_t* object = 0;
-    if(name) 
+    if(name)
        object = (instance_t*)dictionary_lookup(&instances, name);
     if(!object && name && *name) {
        /* we have a name, but couldn't find it. Abort. */
@@ -1804,14 +1906,14 @@ void s_outline(char*name, char*format, char*source)
 {
     if(dictionary_lookup(&outlines, name))
         syntaxerror("outline %s defined twice", name);
-        
+
     outline_t* outline;
 
     drawer_t draw;
     SHAPE* shape;
     SHAPE2* shape2;
     SRECT bounds;
-    
+
     //swf_Shape10DrawerInit(&draw, 0);
     swf_Shape11DrawerInit(&draw, 0);
 
@@ -1820,11 +1922,11 @@ void s_outline(char*name, char*format, char*source)
     shape = swf_ShapeDrawerToShape(&draw);
     bounds = swf_ShapeDrawerGetBBox(&draw);
     draw.dealloc(&draw);
-    
+
     outline = (outline_t*)rfx_calloc(sizeof(outline_t));
     outline->shape = shape;
     outline->bbox = bounds;
-    
+
     dictionary_put2(&outlines, name, outline);
 }
 
@@ -1858,25 +1960,25 @@ void s_includeswf(char*name, char*filename)
     int level = 0;
     U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
     f = open(filename,O_RDONLY|O_BINARY);
-    if (f<0) { 
+    if (f<0) {
        warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
        s_box(name, 0, 0, black, 20, 0);
        return;
     }
-    if (swf_ReadSWF(f,&swf)<0) { 
+    if (swf_ReadSWF(f,&swf)<0) {
        warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
        s_box(name, 0, 0, black, 20, 0);
        return;
     }
     close(f);
 
-    /* FIXME: The following sets the bounding Box for the character. 
+    /* FIXME: The following sets the bounding Box for the character.
               It is wrong for two reasons:
              a) It may be too small (in case objects in the movie clip at the borders)
              b) it may be too big (because the poor movie never got autocropped)
     */
     r = swf.movieSize;
-    
+
     s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
     swf_SetU16(tag, id);
     swf_SetU16(tag, swf.frameCount);
@@ -1902,7 +2004,7 @@ void s_includeswf(char*name, char*filename)
        if(ftag->id != ST_SETBACKGROUNDCOLOR) {
            /* We simply dump all tags right after the sprite
               header, relying on the fact that swf_OptimizeTagOrder() will
-              sort things out for us later. 
+              sort things out for us later.
               We also rely on the fact that the imported SWF is well-formed.
             */
            tag = swf_InsertTag(tag, ftag->id);
@@ -1935,11 +2037,15 @@ SRECT s_getInstanceBBox(char*name)
     if(!c) syntaxerror("internal error(5)");
     return c->size;
 }
-parameters_t s_getParameters(char*name)
+void s_getParameters(char*name, parameters_t* p)
 {
     instance_t * i = dictionary_lookup(&instances, name);
-    if(!i) syntaxerror("instance '%s' unknown(10)", name);
-    return i->parameters;
+    if(!i)
+       syntaxerror("instance '%s' unknown(10)", name);
+    if (change_sets_all)
+        readParameters(i->history, p, currentframe);
+    else
+       *p = i->parameters;
 }
 void s_startclip(char*instance, char*character, parameters_t p)
 {
@@ -1952,12 +2058,10 @@ void s_startclip(char*instance, char*character, parameters_t p)
     i = s_addinstance(instance, c, currentdepth);
     i->parameters = p;
     m = s_instancepos(i->character->size, &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;
@@ -1999,7 +2103,8 @@ 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);
+    history_begin(i->history, "flags", currentframe, tag, 0);
 }
 
 void s_put(char*instance, char*character, parameters_t p)
@@ -2007,16 +2112,16 @@ void s_put(char*instance, char*character, parameters_t p)
     character_t* c = dictionary_lookup(&characters, character);
     instance_t* i;
     MATRIX m;
-    if(!c) 
+    if(!c)
         syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
-    
+
     i = s_addinstance(instance, c, currentdepth);
     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) 
+        if(stack[0].swf->fileVersion < 8)
         {
             if(p.blendmode)
                 warning("blendmodes only supported for flash version>=8");
@@ -2029,8 +2134,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++;
 }
 
@@ -2081,7 +2184,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)
@@ -2092,12 +2195,31 @@ void s_jump(char* instance, parameters_t p)
     recordChanges(i->history, p, CF_JUMP, 0);
 }
 
-void s_change(char*instance, parameters_t p2, interpolation_t* inter)
+void s_change(char*instance, parameters_t p, interpolation_t* inter)
+{
+    instance_t* i = dictionary_lookup(&instances, instance);
+    if(!i)
+        syntaxerror("instance %s not known", instance);
+    recordChanges(i->history, p, CF_CHANGE, inter);
+}
+
+void s_sweep(char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
 {
     instance_t* i = dictionary_lookup(&instances, instance);
     if(!i)
         syntaxerror("instance %s not known", instance);
-    recordChanges(i->history, p2, CF_CHANGE, inter);
+    history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
+}
+
+void s_toggle(char* instance, U16 flagsOn, U16 flagsOff)
+{
+    instance_t* i = dictionary_lookup(&instances, instance);
+    if (!i)
+        syntaxerror("instance %s not known", instance);
+    U16 flags = (U16)history_value(i->history, currentframe, "flags");
+    flags |= flagsOn;
+    flags &= flagsOff;
+    history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
 }
 
 void s_delinstance(char*instance)
@@ -2105,17 +2227,18 @@ void s_delinstance(char*instance)
     instance_t* i = dictionary_lookup(&instances, instance);
     if(!i)
         syntaxerror("instance %s not known", instance);
+    writeInstance(i);
     tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
     swf_SetU16(tag, i->depth);
     dictionary_del(&instances, instance);
 }
 
-void s_qchange(char*instance, parameters_t p)
+void s_schange(char*instance, parameters_t p, interpolation_t* inter)
 {
     instance_t* i = dictionary_lookup(&instances, instance);
     if(!i)
         syntaxerror("instance %s not known", instance);
-    recordChanges(i->history, p, CF_QCHANGE, 0);
+    recordChanges(i->history, p, CF_SCHANGE, inter);
 }
 
 void s_end()
@@ -2250,6 +2373,26 @@ int parseTwip(char*str)
     return 0;
 }
 
+int parseArc(char* str)
+{
+    if (!strcmp(str, "short"))
+       return 1;
+    if (!strcmp(str, "long"))
+       return 0;
+    syntaxerror("invalid value for the arc parameter: %s", str);
+    return 1;
+}
+
+int parseDir(char* str)
+{
+    if (!strcmp(str, "clockwise"))
+       return 1;
+    if (!strcmp(str, "counterclockwise"))
+       return 0;
+    syntaxerror("invalid value for the dir parameter: %s", str);
+    return 1;
+}
+
 int isPoint(char*str)
 {
     if(strchr(str, '('))
@@ -2429,15 +2572,16 @@ static char* lu(map_t* args, char*name)
     return value;
 }
 
-static int c_flash(map_t*args) 
+static int c_flash(map_t*args)
 {
     char* filename = map_lookup(args, "filename");
     char* compressstr = lu(args, "compress");
+    char* change_modestr = lu(args, "change-sets-all");
     SRECT bbox = parseBox(lu(args, "bbox"));
     int version = parseInt(lu(args, "version"));
     int fps = (int)(parseFloat(lu(args, "fps"))*256);
-    int compress = 0;
     RGBA color = parseColor(lu(args, "background"));
+    int compress = 0;
 
     if(!filename || !*filename) {
        /* for compatibility */
@@ -2452,7 +2596,7 @@ static int c_flash(map_t*args)
 
     if(!filename || override_outputname)
        filename = outputname;
-    
+
     if(!strcmp(compressstr, "default"))
        compress = version>=6;
     else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
@@ -2461,6 +2605,12 @@ static int c_flash(map_t*args)
        compress = 0;
     else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
 
+    if(!strcmp(change_modestr, "yes"))
+       change_sets_all = 1;
+    else
+       if(strcmp(change_modestr, "no"))
+           syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
+
     s_swf(filename, bbox, version, fps, compress, color);
     return 0;
 }
@@ -2497,7 +2647,7 @@ static int c_interpolation(map_t *args)
     char* name = lu(args, "name");
     if (dictionary_lookup(&interpolations, name))
         syntaxerror("interpolation %s defined twice", name);
-    
+
     interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
     char* functionstr = lu(args, "function");
     inter->function = 0;
@@ -2510,11 +2660,12 @@ static int c_interpolation(map_t *args)
     if (!inter->function)
         syntaxerror("unkown interpolation function %s", functionstr);
     inter->speed = parseFloat(lu(args, "speed"));
-    inter->amplitude = parseFloat(lu(args, "amplitude"));
+    inter->amplitude = parseTwip(lu(args, "amplitude"));
     inter->growth = parseFloat(lu(args, "growth"));
     inter->bounces = parseInt(lu(args, "bounces"));
-    inter->damping = parseInt(lu(args, "damping"));
-    
+    inter->damping = parseFloat(lu(args, "damping"));
+    inter->slope = parseFloat(lu(args, "slope"));
+
     dictionary_put2(&interpolations, name, inter);
     return 0;
 }
@@ -2523,22 +2674,72 @@ SPOINT getPoint(SRECT r, char*name)
 {
     int l=0;
     if(!strcmp(name, "center")) {
-       SPOINT p;
-       p.x = (r.xmin + r.xmax)/2;
-       p.y = (r.ymin + r.ymax)/2;
-       return p;
+        SPOINT p;
+        p.x = (r.xmin + r.xmax)/2;
+        p.y = (r.ymin + r.ymax)/2;
+        return p;
+    }
+    if (!strcmp(name, "bottom-center")) {
+        SPOINT p;
+        p.x = (r.xmin + r.xmax)/2;
+        p.y = r.ymax;
+        return p;
+    }
+    if (!strcmp(name, "top-center")) {
+        SPOINT p;
+        p.x = (r.xmin + r.xmax)/2;
+        p.y = r.ymin;
+        return p;
+    }
+    if (!strcmp(name, "top-left")) {
+        SPOINT p;
+        p.x = r.xmin;
+        p.y = r.ymin;
+        return p;
+    }
+    if (!strcmp(name, "top-right")) {
+        SPOINT p;
+        p.x = r.xmax;
+        p.y = r.ymin;
+        return p;
+    }
+    if (!strcmp(name, "bottom-right")) {
+        SPOINT p;
+        p.x = r.xmax;
+        p.y = r.ymax;
+        return p;
+    }
+    if (!strcmp(name, "bottom-left")) {
+        SPOINT p;
+        p.x = r.xmin;
+        p.y = r.ymax;
+        return p;
+    }
+    if (!strcmp(name, "left-center")) {
+        SPOINT p;
+        p.x = r.xmin;
+        p.y = (r.ymin + r.ymax)/2;
+        return p;
+    }
+    if (!strcmp(name, "right-center")) {
+        SPOINT p;
+        p.x = r.xmax;
+        p.y = (r.ymin + r.ymax)/2;
+        return p;
     }
 
+
     if(points_initialized)
-       l = (int)dictionary_lookup(&points, name);
+        l = (int)dictionary_lookup(&points, name);
     if(l==0) {
-       syntaxerror("Invalid point: \"%s\".", name);
+        syntaxerror("Invalid point: \"%s\".", name);
     }
     l--;
     return *(SPOINT*)&mpoints.buffer[l];
 }
 
-static int texture2(char*name, char*object, map_t*args, int errors) 
+
+static int texture2(char*name, char*object, map_t*args, int errors)
 {
     SPOINT pos,size;
     char*xstr = map_lookup(args, "x");
@@ -2600,14 +2801,14 @@ static int texture2(char*name, char*object, map_t*args, int errors)
     return 0;
 }
 
-static int c_texture(map_t*args) 
+static int c_texture(map_t*args)
 {
     char*name = lu(args, "instance");
     char*object = lu(args, "character");
     return texture2(name, object, args, 1);
 }
 
-static int c_gradient(map_t*args) 
+static int c_gradient(map_t*args)
 {
     char*name = lu(args, "name");
     int radial= strcmp(lu(args, "radial"), "radial")?0:1;
@@ -2631,9 +2832,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");
+    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");
@@ -2641,7 +2850,7 @@ static int c_blur(map_t*args)
     if(blurstr[0]) {
        blurx = parseFloat(blurstr);
        blury = parseFloat(blurstr);
-    } 
+    }
     if(blurxstr[0])
        blurx = parseFloat(blurxstr);
     if(blurystr[0])
@@ -2651,9 +2860,9 @@ static int c_blur(map_t*args)
     return 0;
 }
 
-static int c_gradientglow(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");
@@ -2662,7 +2871,7 @@ static int c_gradientglow(map_t*args)
     if(blurstr[0]) {
        blurx = parseFloat(blurstr);
        blury = parseFloat(blurstr);
-    } 
+    }
     if(blurxstr[0])
        blurx = parseFloat(blurxstr);
     if(blurystr[0])
@@ -2681,9 +2890,9 @@ static int c_gradientglow(map_t*args)
     return 0;
 }
 
-static int c_dropshadow(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");
@@ -2692,7 +2901,7 @@ static int c_dropshadow(map_t*args)
     if(blurstr[0]) {
        blurx = parseFloat(blurstr);
        blury = parseFloat(blurstr);
-    } 
+    }
     if(blurxstr[0])
        blurx = parseFloat(blurxstr);
     if(blurystr[0])
@@ -2710,9 +2919,9 @@ static int c_dropshadow(map_t*args)
     return 0;
 }
 
-static int c_bevel(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");
@@ -2722,7 +2931,7 @@ static int c_bevel(map_t*args)
     if(blurstr[0]) {
        blurx = parseFloat(blurstr);
        blury = parseFloat(blurstr);
-    } 
+    }
     if(blurxstr[0])
        blurx = parseFloat(blurxstr);
     if(blurystr[0])
@@ -2741,7 +2950,7 @@ static int c_bevel(map_t*args)
     return 0;
 }
 
-static int c_point(map_t*args) 
+static int c_point(map_t*args)
 {
     char*name = lu(args, "name");
     int pos;
@@ -2760,7 +2969,7 @@ static int c_point(map_t*args)
     dictionary_put(&points, s1, (void*)pos);
     return 0;
 }
-static int c_play(map_t*args) 
+static int c_play(map_t*args)
 {
     char*name = lu(args, "name");
     char*loop = lu(args, "loop");
@@ -2779,7 +2988,7 @@ static int c_play(map_t*args)
     return 0;
 }
 
-static int c_stop(map_t*args) 
+static int c_stop(map_t*args)
 {
     char*name = map_lookup(args, "name");
 
@@ -2791,7 +3000,7 @@ static int c_stop(map_t*args)
        return 0;
 }
 
-static int c_nextframe(map_t*args) 
+static int c_nextframe(map_t*args)
 {
     char*name = lu(args, "name");
 
@@ -2802,7 +3011,7 @@ static int c_nextframe(map_t*args)
     return 0;
 }
 
-static int c_previousframe(map_t*args) 
+static int c_previousframe(map_t*args)
 {
     char*name = lu(args, "name");
 
@@ -2813,9 +3022,99 @@ static int c_previousframe(map_t*args)
     return 0;
 }
 
+static int c_movement(map_t*args, int type)
+{
+    char*instance = lu(args, "name");
+
+    char* xstr="";
+    char* ystr="";
+    SRECT oldbbox;
+    parameters_t p;
+    U16 set = 0x0000;
+
+    xstr = lu(args, "x");
+    ystr = lu(args, "y");
+
+    s_getParameters(instance, &p);
+
+    /* x,y position */
+    if(xstr[0])
+    {
+        if(isRelative(xstr))
+        {
+            if(type == PT_PUT || type == PT_STARTCLIP)
+                syntaxerror("relative x values not allowed for initial put or startclip");
+            p.x += parseTwip(getOffset(xstr))*getSign(xstr);
+        }
+        else
+        {
+            p.x = parseTwip(xstr);
+        }
+        set = set | SF_X;
+     }
+    if(ystr[0])
+    {
+        if(isRelative(ystr))
+        {
+            if(type == PT_PUT || type == PT_STARTCLIP)
+                syntaxerror("relative y values not allowed for initial put or startclip");
+            p.y += parseTwip(getOffset(ystr))*getSign(ystr);
+        }
+        else
+        {
+            p.y = parseTwip(ystr);
+        }
+        set = set | SF_Y;
+    }
+
+    if (change_sets_all)
+       set = SF_ALL;
+    p.set = set;
+
+    switch (type)
+    {
+        case PT_MOVE:
+            {
+                char* interstr = lu(args, "interpolation");
+                interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
+                if (!inter)
+                    syntaxerror("unkown interpolation %s", interstr);
+                s_change(instance, p, inter);
+            }
+            break;
+        case PT_SMOVE:
+            {
+                char* interstr = lu(args, "interpolation");
+                interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
+                if (!inter)
+                    syntaxerror("unkown interpolation %s", interstr);
+               s_schange(instance, p, inter);
+            }
+            break;
+        case PT_SWEEP:
+            {
+               char* rstr = lu(args, "r");
+               int radius = parseTwip(rstr);
+               if (radius <= 0)
+                       syntaxerror("sweep not possible: radius must be greater than 0.");
+               char* dirstr = lu(args, "dir");
+               int clockwise = parseDir(dirstr);
+               char* arcstr = lu(args, "arc");
+               int short_arc = parseArc(arcstr);
+                char* interstr = lu(args, "interpolation");
+                interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
+                if (!inter)
+                    syntaxerror("unkown interpolation %s", interstr);
+               s_sweep(instance, p, radius, clockwise, short_arc, inter);
+            }
+            break;
+       }
+    return 0;
+}
+
 static int c_placement(map_t*args, int type)
 {
-    char*instance = lu(args, (type==0||type==4)?"instance":"name");
+    char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
     char*character = 0;
 
     char* luminancestr = lu(args, "luminance");
@@ -2843,7 +3142,7 @@ static int c_placement(map_t*args, int type)
     SRECT oldbbox;
     MULADD luminance;
     parameters_t p;
-    U32 set = 0x00000000;
+    U16 set = 0x0000;
 
     if(type==9)
     { // (?) .rotate  or .arcchange
@@ -2855,7 +3154,7 @@ static int c_placement(map_t*args, int type)
         xstr = lu(args, "x");
         ystr = lu(args, "y");
     }
-    
+
     if(luminancestr[0])
         luminance = parseMulAdd(luminancestr);
     else
@@ -2870,25 +3169,25 @@ static int c_placement(map_t*args, int type)
             syntaxerror("scalex/scaley and scale cannot both be set");
         scalexstr = scaleystr = scalestr;
     }
-    
-    if(type == 0 || type == 4)  {
+
+    if(type == PT_PUT || type == PT_STARTCLIP)  {
        // put or startclip
        character = lu(args, "character");
        parameters_clear(&p);
-    } else if (type == 5) {
+    } else if (type == PT_BUTTON) {
        character = lu(args, "name");
        parameters_clear(&p);
        // button's show
     } else {
-       p = s_getParameters(instance);
+       s_getParameters(instance, &p);
     }
 
     /* x,y position */
-    if(xstr[0]) 
+    if(xstr[0])
     {
         if(isRelative(xstr))
         {
-            if(type == 0 || type == 4)
+            if(type == PT_PUT || type == PT_STARTCLIP)
                 syntaxerror("relative x values not allowed for initial put or startclip");
             p.x += parseTwip(getOffset(xstr))*getSign(xstr);
         }
@@ -2902,7 +3201,7 @@ static int c_placement(map_t*args, int type)
     {
         if(isRelative(ystr))
         {
-            if(type == 0 || type == 4)
+            if(type == PT_PUT || type == PT_STARTCLIP)
                 syntaxerror("relative y values not allowed for initial put or startclip");
             p.y += parseTwip(getOffset(ystr))*getSign(ystr);
         }
@@ -2938,7 +3237,7 @@ static int c_placement(map_t*args, int type)
                 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
         set = set | SF_SCALEY;
    }
-   
+
     /* rotation */
     if(rotatestr[0])
     {
@@ -2963,11 +3262,11 @@ static int c_placement(map_t*args, int type)
     {
         if(isPoint(pivotstr))
             p.pivot = parsePoint(pivotstr);
-        else 
+        else
             p.pivot = getPoint(oldbbox, pivotstr);
         set = set | SF_PIVOT;
     }
-    
+
     if(pinstr[0])
     {
         if(isPoint(pinstr))
@@ -2976,7 +3275,7 @@ static int c_placement(map_t*args, int type)
             p.pin = getPoint(oldbbox, pinstr);
         set = set | SF_PIN;
     }
-       
+
     /* color transform */
 
     if(rstr[0] || luminancestr[0])
@@ -3051,24 +3350,29 @@ static int c_placement(map_t*args, int type)
         p.blendmode = blend;
         set = set | SF_BLEND;
        }
-    
+
     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;
     }
 
+    if (type == PT_CHANGE && set & (SF_X | SF_Y))
+       warning("As of version 0.8.2 using the .change command to modify an \
+object's position on the stage is considered deprecated. Future \
+versions may consider x and y parameters for the .change command \
+to be illegal; please use the .move command.");
+
+    if (change_sets_all)
+       set = SF_ALL;
     p.set = set;
 
     switch (type)
     {
-        case 0:
+        case PT_PUT:
             s_put(instance, character, p);
             break;
-        case 1:
+        case PT_CHANGE:
             {
                 char* interstr = lu(args, "interpolation");
                 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
@@ -3077,84 +3381,120 @@ static int c_placement(map_t*args, int type)
                 s_change(instance, p, inter);
             }
             break;
-        case 2:
-            s_qchange(instance, p);
+        case PT_SCHANGE:
+            {
+                char* interstr = lu(args, "interpolation");
+                interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
+                if (!inter)
+                    syntaxerror("unkown interpolation %s", interstr);
+               s_schange(instance, p, inter);
+            }
             break;
-        case 3:
+        case PT_JUMP:
             s_jump(instance, p);
             break;
-        case 4:
+        case PT_STARTCLIP:
             s_startclip(instance, character, p);
             break;
-        case 5:
+        case PT_BUTTON:
             if(as && as[0])
                 s_buttonput(character, as, p);
             else
                 s_buttonput(character, "shape", p);
             break;
-//        default: 
+//        default:
        }
     return 0;
 }
-static int c_put(map_t*args) 
+static int c_put(map_t*args)
 {
-    c_placement(args, 0);
+    c_placement(args, PT_PUT);
     return 0;
 }
-static int c_change(map_t*args) 
+static int c_change(map_t*args)
 {
     if (currentframe == 0)
         warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
-    c_placement(args, 1);
+    c_placement(args, PT_CHANGE);
     return 0;
 }
-static int c_qchange(map_t*args) 
+static int c_schange(map_t*args)
 {
-    c_placement(args, 2);
+    c_placement(args, PT_SCHANGE);
     return 0;
 }
-static int c_arcchange(map_t*args) 
+static int c_move(map_t* args)
 {
-    c_placement(args, 2);
+    c_movement(args, PT_MOVE);
     return 0;
 }
-static int c_jump(map_t*args) 
+static int c_smove(map_t* args)
 {
-    c_placement(args, 3);
+    c_movement(args, PT_SMOVE);
     return 0;
 }
-static int c_startclip(map_t*args) 
+static int c_sweep(map_t* args)
 {
-    c_placement(args, 4);
+    c_movement(args, PT_SWEEP);
     return 0;
 }
-static int c_show(map_t*args) 
+static int c_arcchange(map_t*args)
 {
-    c_placement(args, 5);
+    c_placement(args, 0);
+    return 0;
+}
+static int c_jump(map_t*args)
+{
+    c_placement(args, PT_JUMP);
+    return 0;
+}
+static int c_startclip(map_t*args)
+{
+    c_placement(args, PT_STARTCLIP);
+    return 0;
+}
+static int c_show(map_t*args)
+{
+    c_placement(args, PT_BUTTON);
+    return 0;
+}
+static int c_toggle(map_t* args)
+{
+    char*instance = lu(args, "name");
+    U16 flagsOn = 0x0000, flagsOff = 0xffff;
+    char* alignstr = lu(args, "fixed_alignment");
+    if (!strcmp(alignstr, "on"))
+       flagsOn += IF_FIXED_ALIGNMENT;
+    else
+       if (!strcmp(alignstr, "off"))
+           flagsOff -= IF_FIXED_ALIGNMENT;
+       else
+           syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
+    s_toggle(instance, flagsOn, flagsOff);
     return 0;
 }
-static int c_del(map_t*args) 
+static int c_del(map_t*args)
 {
     char*instance = lu(args, "name");
     s_delinstance(instance);
     return 0;
 }
-static int c_end(map_t*args) 
+static int c_end(map_t*args)
 {
     s_end();
     return 0;
 }
-static int c_sprite(map_t*args) 
+static int c_sprite(map_t*args)
 {
     char* name = lu(args, "name");
     s_sprite(name);
     return 0;
 }
-static int c_frame(map_t*args) 
+static int c_frame(map_t*args)
 {
     char*framestr = lu(args, "n");
     char*cutstr = lu(args, "cut");
-    
+
     char*name = lu(args, "name");
     char*anchor = lu(args, "anchor");
     char buf[40];
@@ -3181,7 +3521,7 @@ static int c_frame(map_t*args)
     s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
     return 0;
 }
-static int c_primitive(map_t*args) 
+static int c_primitive(map_t*args)
 {
     char*name = lu(args, "name");
     char*command = lu(args, "commandname");
@@ -3200,7 +3540,7 @@ static int c_primitive(map_t*args)
        type = 1;
     else if(!strcmp(command, "filled"))
        type = 2;
-   
+
     if(type==0) {
        width = parseTwip(lu(args, "width"));
        height = parseTwip(lu(args, "height"));
@@ -3216,14 +3556,14 @@ static int c_primitive(map_t*args)
        fillstr = 0;
     if(width<0 || height<0 || linewidth<0 || r<0)
        syntaxerror("values width, height, line, r must be positive");
-    
+
     if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
     else if(type==1) s_circle(name, r, color, linewidth, fillstr);
     else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
     return 0;
 }
 
-static int c_textshape(map_t*args) 
+static int c_textshape(map_t*args)
 {
     char*name = lu(args, "name");
     char*text = lu(args, "text");
@@ -3234,7 +3574,7 @@ static int c_textshape(map_t*args)
     return 0;
 }
 
-static int c_swf(map_t*args) 
+static int c_swf(map_t*args)
 {
     char*name = lu(args, "name");
     char*filename = lu(args, "filename");
@@ -3245,25 +3585,15 @@ static int c_swf(map_t*args)
     return 0;
 }
 
-static int c_font(map_t*args) 
+static int c_font(map_t*args)
 {
     char*name = lu(args, "name");
     char*filename = lu(args, "filename");
-    fontData* usage = getFontData(name);
-    char* glyphs = usage->glyphs;
-    if (usage->needsAll)
-        glyphs = "";
-    else
-        if (usage->notUsed)
-        {
-            printf("font %s was defined but not used\n", name);
-            return 0;
-        }
-    s_font(name, filename, glyphs);
+    s_font(name, filename);
     return 0;
 }
 
-static int c_sound(map_t*args) 
+static int c_sound(map_t*args)
 {
     char*name = lu(args, "name");
     char*filename = lu(args, "filename");
@@ -3271,7 +3601,7 @@ static int c_sound(map_t*args)
     return 0;
 }
 
-static int c_text(map_t*args) 
+static int c_text(map_t*args)
 {
     char*name = lu(args, "name");
     char*text = lu(args, "text");
@@ -3282,12 +3612,12 @@ static int c_text(map_t*args)
     return 0;
 }
 
-static int c_soundtrack(map_t*args) 
+static int c_soundtrack(map_t*args)
 {
     return 0;
 }
 
-static int c_quicktime(map_t*args) 
+static int c_quicktime(map_t*args)
 {
     char*name = lu(args, "name");
     char*url = lu(args, "url");
@@ -3295,7 +3625,7 @@ static int c_quicktime(map_t*args)
     return 0;
 }
 
-static int c_image(map_t*args) 
+static int c_image(map_t*args)
 {
     char*command = lu(args, "commandname");
     char*name = lu(args, "name");
@@ -3309,7 +3639,7 @@ static int c_image(map_t*args)
     return 0;
 }
 
-static int c_outline(map_t*args) 
+static int c_outline(map_t*args)
 {
     char*name = lu(args, "name");
     char*format = lu(args, "format");
@@ -3434,7 +3764,7 @@ static int c_on_key(map_t*args)
            return 1;
        }
     } else {
-       /* TODO: 
+       /* TODO:
           <ctrl-x> = 0x200*(x-'a')
           esc = = 0x3600
           space = = 0x4000;
@@ -3452,7 +3782,7 @@ static int c_on_key(map_t*args)
     return 0;
 }
 
-static int c_edittext(map_t*args) 
+static int c_edittext(map_t*args)
 {
  //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0 @autosize=0"},
     char*name = lu(args, "name");
@@ -3502,7 +3832,7 @@ static char* readfile(const char*filename)
     FILE*fi = fopen(filename, "rb");
     int l;
     char*text;
-    if(!fi) 
+    if(!fi)
        syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
     fseek(fi, 0, SEEK_END);
     l = ftell(fi);
@@ -3514,7 +3844,7 @@ static char* readfile(const char*filename)
     return text;
 }
 
-static int c_action(map_t*args) 
+static int c_action(map_t*args)
 {
     char* filename  = map_lookup(args, "filename");
     if(!filename ||!*filename) {
@@ -3526,11 +3856,11 @@ static int c_action(map_t*args)
     } else {
        s_action(readfile(filename));
     }
-   
+
     return 0;
 }
 
-static int c_initaction(map_t*args) 
+static int c_initaction(map_t*args)
 {
     char* character = lu(args, "name");
     char* filename  = map_lookup(args, "filename");
@@ -3543,7 +3873,7 @@ static int c_initaction(map_t*args)
     } else {
        s_initaction(character, readfile(filename));
     }
-   
+
     return 0;
 }
 
@@ -3552,7 +3882,7 @@ static struct {
     command_func_t* func;
     char*arguments;
 } arguments[] =
-{{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default"},
+{{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no"},
  {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
  // "import" type stuff
  {"swf", c_swf, "name filename"},
@@ -3561,15 +3891,15 @@ static struct {
  {"png", c_image, "name filename"},
  {"movie", c_movie, "name filename"},
  {"sound", c_sound, "name filename"},
- {"font", c_font, "name filename"},
+ {"font", c_font, "name filename glyphs="},
  {"soundtrack", c_soundtrack, "filename"},
  {"quicktime", c_quicktime, "url"},
+
     // generators of primitives
 
  {"point", c_point, "name x=0 y=0"},
  {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
- {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5, damping=2"},
+ {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
  {"outline", c_outline, "name format=simple"},
  {"textshape", c_textshape, "name font size=100% text"},
 
@@ -3595,7 +3925,7 @@ static struct {
     {"on_move_in", c_on_move_in, "state=not_pressed"},
     {"on_move_out", c_on_move_out, "state=not_pressed"},
     {"on_key", c_on_key, "key=any"},
+
     // control tags
  {"play", c_play, "name loop=0 @nomultiple=0"},
  {"stop", c_stop, "name= "},
@@ -3605,13 +3935,18 @@ static struct {
     // object placement tags
  {"put", c_put,             "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
  {"startclip", c_startclip, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
+ {"move", c_move,      "name x= y= interpolation=linear"},
+ {"smove", c_smove,    "name x= y= interpolation=linear"},
+ {"sweep", c_sweep,    "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
  {"change", c_change,   "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
- {"arcchange", c_arcchange,   "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
- {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
+ //{"arcchange", c_arcchange,   "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
+ {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
  {"jump", c_jump,       "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
  {"del", c_del, "name"},
     // virtual object placement
  {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
+    // switching
+ {"toggle", c_toggle, "name fixed_alignment="},
 
     // commands which start a block
 //startclip (see above)
@@ -3627,7 +3962,7 @@ static map_t parseArguments(char*command, char*pattern)
 {
     char*x;
     char*d,*e;
-   
+
     string_t name[64];
     string_t value[64];
     int set[64];
@@ -3687,7 +4022,7 @@ static map_t parseArguments(char*command, char*pattern)
            d=&x[strlen(x)];
        set[pos] = 0;
 
-       if(!e || d<e) { 
+       if(!e || d<e) {
            // no default
            name[pos].str = x;
            name[pos].len = d-x;
@@ -3782,7 +4117,7 @@ static map_t parseArguments(char*command, char*pattern)
 
     /* ok, now construct the dictionary from the parameters */
 
-    for(t=0;t<len;t++) 
+    for(t=0;t<len;t++)
     {
        map_put(&result, name[t], value[t]);
     }
@@ -3801,7 +4136,7 @@ static void parseArgumentsForCommand(char*command)
            /* ugly hack- will be removed soon (once documentation and .sc generating
               utilities have been changed) */
            if(!strcmp(command, "swf") && !stackpos) {
-               warning("Please use .flash instead of .swf- this will be mandatory soon");      
+               warning("Please use .flash instead of .swf- this will be mandatory soon");
                command = "flash";
                t = 0;
            }
@@ -3813,7 +4148,7 @@ static void parseArgumentsForCommand(char*command)
     }
     if(nr<0)
        syntaxerror("command %s not known", command);
-   
+
     // catch missing .flash directives at the beginning of a file
     if(strcmp(command, "flash") && !stackpos)
     {
@@ -3846,8 +4181,99 @@ static void parseArgumentsForCommand(char*command)
     return;
 }
 
+
+/* for now only intended to find what glyphs of each font are to be included in the swf file.
+ * Therefore some knowledge about the command is assumed i.e. it is font/text-related
+ * No syntax checking is done */
+static void analyseArgumentsForCommand(char*command)
+{
+    int t;
+    map_t args;
+    char* fontfile;
+    int nr = -1;
+    msg("<verbose> analyse Command: %s (line %d)", command, line);
+
+    for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
+    {
+        if(!strcmp(arguments[t].command, command))
+        {
+            args = parseArguments(command, arguments[t].arguments);
+            nr = t;
+            break;
+        }
+    }
+#ifdef DEBUG
+    printf(".%s\n", command);fflush(stdout);
+    map_dump(&args, stdout, "\t");fflush(stdout);
+#endif
+    char* name = lu(&args, "name");
+    if (!strcmp(command, "font"))
+    {
+       if(dictionary_lookup(&fonts, name))
+            syntaxerror("font %s defined twice", name);
+
+       SWFFONT* font;
+       fontfile = lu(&args, "filename");
+       font = swf_LoadFont(fontfile);
+       if(font == 0) {
+           warning("Couldn't open font file \"%s\"", fontfile);
+           font = (SWFFONT*)malloc(sizeof(SWFFONT));
+           memset(font, 0, sizeof(SWFFONT));
+       }
+       swf_FontUseUTF8(font, lu(&args, "glyphs"));
+       swf_FontPrepareForEditText(font);
+       dictionary_put2(&fonts, name, font);
+    }
+    else
+    {
+        SWFFONT* font = dictionary_lookup(&fonts, lu(&args, "font"));
+        if (!font)
+            syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
+        else
+            if (!strcmp(command, "edittext"))
+               swf_FontUseAll(font);
+            else
+               swf_FontUseUTF8(font, lu(&args, "text"));
+    }
+    map_clear(&args);
+    return;
+}
+
+void skipParameters()
+{
+       do
+               readToken();
+       while (type != COMMAND);
+       pushBack();
+}
+
+void findFontUsage()
+{
+    char* fontRelated = "font;text;textshape;edittext;";
+    while(!noMoreTokens())
+    {
+        readToken();
+        if(type != COMMAND)
+            syntaxerror("command expected");
+        if (strstr(fontRelated, text))
+            analyseArgumentsForCommand(text);
+        else
+            if(strcmp(text, "end"))
+                skipParameters();
+    }
+}
+
+void firstPass()
+{
+    pos = 0;
+    id = 0;
+    dictionary_init(&fonts);
+    cleanUp = &freeFontDictionary;
+    findFontUsage();
+}
+
 int main (int argc,char ** argv)
-{ 
+{
     int t;
     processargs(argc, argv);
     initLog(0,-1,0,0,-1,verbose);
@@ -3856,12 +4282,13 @@ int main (int argc,char ** argv)
        args_callback_usage(argv[0]);
        exit(1);
     }
-    
+
     file = generateTokens(filename);
     if(!file) {
        fprintf(stderr, "parser returned error.\n");
        return 1;
     }
+    firstPass();
     pos=0;
     t=0;