X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=src%2Fswfc.c;h=14d5f9a90ce360a91859a7e5844913475f0ad271;hb=32bce7795076522c72a9c7f5720a6774f5f8223c;hp=41e5b93bc47f8b9433c55b3375e411c650dabcf6;hpb=57c76fea2ab1652cb1727342ab7caf02569eeab7;p=swftools.git diff --git a/src/swfc.c b/src/swfc.c index 41e5b93..14d5f9a 100644 --- a/src/swfc.c +++ b/src/swfc.c @@ -46,6 +46,8 @@ 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 int do_exports = 0; static struct options_t options[] = { {"h", "help"}, @@ -153,6 +155,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 @@ -173,6 +188,8 @@ static struct level SRECT oldrect; TAG* cut; + SRECT scalegrid; + } stack[256]; static int stackpos = 0; @@ -204,8 +221,9 @@ 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 + U16 flags; // bits to toggle anything you may care to implement as a toggle } parameters_t; typedef struct _character { @@ -218,8 +236,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; @@ -324,8 +340,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); @@ -334,6 +350,7 @@ static void freeDictionaries() dictionary_free_all(&fonts, free_font); dictionary_free_all(&sounds, free); dictionary_free_all(&interpolations, free); + cleanUp = 0; } static void freeFontDictionary() @@ -361,13 +378,15 @@ static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r) c->size = r; dictionary_put2(&characters, name, c); - tag = swf_InsertTag(tag, ST_NAMECHARACTER); - swf_SetU16(tag, id); - swf_SetString(tag, name); - tag = swf_InsertTag(tag, ST_EXPORTASSETS); - swf_SetU16(tag, 1); - swf_SetU16(tag, id); - swf_SetString(tag, name); + if(do_exports) { + tag = swf_InsertTag(tag, ST_NAMECHARACTER); + swf_SetU16(tag, id); + swf_SetString(tag, name); + tag = swf_InsertTag(tag, ST_EXPORTASSETS); + swf_SetU16(tag, 1); + swf_SetU16(tag, id); + swf_SetString(tag, name); + } } static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r) { @@ -402,7 +421,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); } @@ -415,10 +434,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); @@ -446,7 +465,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)); @@ -455,42 +474,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)); @@ -522,6 +553,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) @@ -550,7 +617,7 @@ void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA backgrou dictionary_init(&instances); dictionary_init(&sounds); dictionary_init(&interpolations); - builtInInterpolations(); + initBuiltIns(); cleanUp = &freeDictionaries; memset(&stack[stackpos], 0, sizeof(stack[0])); @@ -568,7 +635,7 @@ void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA backgrou incrementid(); } -void s_sprite(char*name) +void s_sprite(char*name, SRECT*scalegrid) { tag = swf_InsertTag(tag, ST_DEFINESPRITE); swf_SetU16(tag, id); //id @@ -583,6 +650,11 @@ void s_sprite(char*name) stack[stackpos].tag = tag; stack[stackpos].id = id; stack[stackpos].name = strdup(name); + if(scalegrid) { + stack[stackpos].scalegrid = *scalegrid; + } else { + memset(&stack[stackpos].scalegrid, 0, sizeof(SRECT)); + } /* FIXME: those four fields should be bundled together */ dictionary_init(&instances); @@ -751,6 +823,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"); @@ -765,14 +877,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) @@ -791,11 +903,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); } @@ -805,21 +914,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; } } @@ -844,21 +959,33 @@ static void s_endSprite() 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); tag = stack[stackpos].tag; swf_FoldSprite(tag); + + if(stack[stackpos].scalegrid.xmin | stack[stackpos].scalegrid.ymin | + stack[stackpos].scalegrid.xmax | stack[stackpos].scalegrid.ymax) + { + tag = swf_InsertTag(tag, ST_DEFINESCALINGGRID); + swf_SetU16(tag, stack[stackpos].id); + swf_SetRect(tag, &stack[stackpos].scalegrid); + } + if(tag->next != 0) syntaxerror("internal error(7)"); /* TODO: before clearing, prepend "." to names and @@ -882,14 +1009,15 @@ static void s_endSWF() 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); + } } if(stack[stackpos].cut) @@ -931,8 +1059,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");} @@ -1023,8 +1149,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; @@ -1420,7 +1546,7 @@ void s_font(char*name, char*filename) swf_FontCreateLayout(font); } font->id = id; - swf_FontReduce_swfc(font); + swf_FontReduce_swfc(font); tag = swf_InsertTag(tag, ST_DEFINEFONT2); swf_FontSetDefine2(tag, font); tag = swf_InsertTag(tag, ST_EXPORTASSETS); @@ -1595,6 +1721,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; @@ -1615,11 +1779,11 @@ void s_gradientglow(char*name, char*gradient, float blurx, float blury, 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; @@ -1893,12 +2057,42 @@ 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 setStartparameters(instance_t* i, parameters_t* p, TAG* tag) +{ + history_begin(i->history, "x", currentframe, tag, p->x); + history_begin(i->history, "y", currentframe, tag, p->y); + history_begin(i->history, "scalex", currentframe, tag, p->scalex); + history_begin(i->history, "scaley", currentframe, tag, p->scaley); + history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0); + history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0); + history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0); + history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0); + history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1); + history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1); + history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1); + history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1); + history_begin(i->history, "rotate", currentframe, tag, p->rotate); + history_begin(i->history, "shear", currentframe, tag, p->shear); + history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x); + history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y); + 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->filters); + history_begin(i->history, "flags", currentframe, tag, 0); +} + void s_startclip(char*instance, char*character, parameters_t p) { character_t* c = dictionary_lookup(&characters, character); @@ -1914,13 +2108,12 @@ 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; stackpos++; + setStartparameters(i, &p, tag); currentdepth++; } void s_endClip() @@ -1936,30 +2129,6 @@ void s_endClip() currentdepth++; } -void setStartparameters(instance_t* i, parameters_t* p, TAG* tag) -{ - history_begin(i->history, "x", currentframe, tag, p->x); - history_begin(i->history, "y", currentframe, tag, p->y); - history_begin(i->history, "scalex", currentframe, tag, p->scalex); - history_begin(i->history, "scaley", currentframe, tag, p->scaley); - history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0); - history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0); - history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0); - history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0); - history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1); - history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1); - history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1); - history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1); - history_begin(i->history, "rotate", currentframe, tag, p->rotate); - history_begin(i->history, "shear", currentframe, tag, p->shear); - history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x); - history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y); - 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); -} - void s_put(char*instance, char*character, parameters_t p) { character_t* c = dictionary_lookup(&characters, character); @@ -1972,7 +2141,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) { @@ -1987,8 +2156,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++; } @@ -2039,7 +2206,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) @@ -2050,12 +2217,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) @@ -2063,17 +2249,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() @@ -2160,7 +2347,7 @@ int parseInt(char*str) syntaxerror("Not an Integer: \"%s\"", str); return atoi(str); } -int parseTwip(char*str) +int parseRawTwip(char*str) { char*dot; int sign=1; @@ -2199,15 +2386,84 @@ int parseTwip(char*str) } free(old); if(l==0) - return sign*atoi(str)*20; + return sign*(atoi(str)*20); if(l==1) - return sign*atoi(str)*20+atoi(dot)*2; + return sign*(atoi(str)*20+atoi(dot)*2); if(l==2) - return sign*atoi(str)*20+atoi(dot)/5; + return sign*(atoi(str)*20+atoi(dot)/5); } return 0; } +static dictionary_t defines; +static int defines_initialized = 0; +static mem_t define_values; + +int parseTwip(char*str) +{ + /* TODO: make this a proper expression parser */ + char*p = str; + int val = 0; + char ex = 0; + char*lastpos = str; + while(*p) { + if(*p == '+' || *p == '-' || *p == '/' || *p == '*') + ex = *p; + else if(!lastpos) + lastpos = p; + p++; + if((*p == '+' || *p == '-' || *p == '/' || *p == '*' || *p == 0) && lastpos) { + char save = *p; + *p = 0; + + int l = 0; + int v = 0; + if(defines_initialized) { + l = (int)dictionary_lookup(&defines, lastpos); + } + if(l) { + v = *(int*)&define_values.buffer[l-1]; + } else { + v = parseRawTwip(lastpos); + } + *p = save; + if(ex == '+') + val += v; + else if(ex == '-') + val -= v; + else if(ex == '/') + val = (val*20) / v; + else if(ex == '*') + val = (val*v) / 20; + else + val += v; + ex = 0; + lastpos = 0; + } + } + return val; +} + +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, '(')) @@ -2391,11 +2647,13 @@ 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"); + char* exportstr = lu(args, "export"); 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 */ @@ -2419,6 +2677,14 @@ 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); + + do_exports=atoi(exportstr); + s_swf(filename, bbox, version, fps, compress, color); return 0; } @@ -2445,9 +2711,10 @@ int getSign(char*str) syntaxerror("internal error (348)"); return 0; } + static dictionary_t points; static mem_t mpoints; -int points_initialized = 0; +static int points_initialized = 0; static int c_interpolation(map_t *args) { @@ -2468,10 +2735,11 @@ 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; @@ -2481,21 +2749,70 @@ 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]; + return *(SPOINT*)&mpoints.buffer[l-1]; } + static int texture2(char*name, char*object, map_t*args, int errors) { SPOINT pos,size; @@ -2589,9 +2906,17 @@ static int c_gradient(map_t*args) return 0; } +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 = lu(args, "name"); + char*name = checkFiltername(args); char*blurstr = lu(args, "blur"); char*blurxstr = lu(args, "blurx"); char*blurystr = lu(args, "blury"); @@ -2611,7 +2936,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"); @@ -2641,7 +2966,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"); @@ -2670,7 +2995,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"); @@ -2699,6 +3024,23 @@ static int c_bevel(map_t*args) return 0; } +static int c_define(map_t*args) +{ + char*name = lu(args, "name"); + char*value = lu(args, "value"); + + if(!defines_initialized) { + dictionary_init(&defines); + mem_init(&define_values); + defines_initialized = 1; + } + int val = parseTwip(value); + int pos = mem_put(&define_values, &val, sizeof(val)); + string_t s; + string_set(&s, name); + dictionary_put(&defines, s, (void*)(pos+1)); + return 0; +} static int c_point(map_t*args) { char*name = lu(args, "name"); @@ -2714,8 +3056,7 @@ static int c_point(map_t*args) p.y = parseTwip(lu(args, "y")); pos = mem_put(&mpoints, &p, sizeof(p)); string_set(&s1, name); - pos++; - dictionary_put(&points, s1, (void*)pos); + dictionary_put(&points, s1, (void*)(pos+1)); return 0; } static int c_play(map_t*args) @@ -2771,9 +3112,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"); @@ -2801,7 +3232,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 @@ -2829,16 +3260,16 @@ static int c_placement(map_t*args, int type) 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 */ @@ -2846,7 +3277,7 @@ static int c_placement(map_t*args, int type) { 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); } @@ -2860,7 +3291,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); } @@ -3012,21 +3443,26 @@ 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; } + 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); @@ -3035,16 +3471,22 @@ 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 @@ -3056,39 +3498,69 @@ static int c_placement(map_t*args, int type) } 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) { 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_move(map_t* args) +{ + c_movement(args, PT_MOVE); + return 0; +} +static int c_smove(map_t* args) +{ + c_movement(args, PT_SMOVE); + return 0; +} +static int c_sweep(map_t* args) +{ + c_movement(args, PT_SWEEP); return 0; } static int c_arcchange(map_t*args) { - c_placement(args, 2); + c_placement(args, 0); return 0; } static int c_jump(map_t*args) { - c_placement(args, 3); + c_placement(args, PT_JUMP); return 0; } static int c_startclip(map_t*args) { - c_placement(args, 4); + c_placement(args, PT_STARTCLIP); return 0; } static int c_show(map_t*args) { - c_placement(args, 5); + 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) @@ -3105,7 +3577,14 @@ static int c_end(map_t*args) static int c_sprite(map_t*args) { char* name = lu(args, "name"); - s_sprite(name); + char* scalinggrid = lu(args, "scalinggrid"); + + if(scalinggrid && *scalinggrid) { + SRECT r = parseBox(scalinggrid); + s_sprite(name, &r); + } else { + s_sprite(name, 0); + } return 0; } static int c_frame(map_t*args) @@ -3500,7 +3979,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 @export=1"}, {"frame", c_frame, "n=1 name= @cut=no @anchor=no"}, // "import" type stuff {"swf", c_swf, "name filename"}, @@ -3509,15 +3988,16 @@ 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 + {"define", c_define, "name value=0"}, {"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"}, @@ -3553,17 +4033,22 @@ static struct { // object placement tags {"put", c_put, " 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, " 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, " 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) - {"sprite", c_sprite, "name"}, + {"sprite", c_sprite, "name scalinggrid="}, {"action", c_action, "filename="}, {"initaction", c_initaction, "name filename="}, @@ -3804,6 +4289,7 @@ static void analyseArgumentsForCommand(char*command) map_t args; char* fontfile; int nr = -1; + U8* glyphs_to_include; msg(" analyse Command: %s (line %d)", command, line); for(t=0;tuse->glyphs_specified = 1; + } + else + { + if (strcmp (glyphs_to_include, "")) + { + swf_FontUseUTF8(font, glyphs_to_include); + font->use->glyphs_specified = 1; + } + else + swf_FontInitUsage(font); + } + } dictionary_put2(&fonts, name, font); } else @@ -3842,10 +4347,16 @@ static void analyseArgumentsForCommand(char*command) 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")); + if (font->use && !font->use->glyphs_specified) + { + if (!strcmp(command, "edittext")) + { + swf_FontUseAll(font); + font->use->glyphs_specified = 1; + } + else + swf_FontUseUTF8(font, lu(&args, "text")); + } } map_clear(&args); return;