2 Compiles swf code (.sc) files into .swf files.
4 Part of the swftools package.
6 Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
29 #include "../config.h"
30 #include "../lib/rfxswf.h"
31 #include "../lib/drawer.h"
32 #include "../lib/log.h"
33 #include "../lib/args.h"
35 #include "../lib/mp3.h"
36 #include "../lib/wav.h"
38 #include "../lib/png.h"
39 #include "swfc-feedback.h"
40 #include "swfc-interpolation.h"
41 #include "swfc-history.h"
44 static char * outputname = "output.swf";
45 static int verbose = 2;
46 static int optimize = 0;
47 static int override_outputname = 0;
48 static int do_cgi = 0;
49 static int change_sets_all = 0;
50 static int do_exports = 0;
52 static struct options_t options[] = {
61 int args_callback_option(char*name,char*val)
63 if(!strcmp(name, "V")) {
64 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
67 else if(!strcmp(name, "o")) {
69 override_outputname = 1;
72 else if(!strcmp(name, "O")) {
76 else if(!strcmp(name, "C")) {
80 else if(!strcmp(name, "v")) {
85 printf("Unknown option: -%s\n", name);
90 int args_callback_longoption(char*name,char*val)
92 return args_long2shortoption(options, name, val);
94 void args_callback_usage(char *name)
97 printf("Usage: %s [-o file.swf] file.sc\n", name);
99 printf("-h , --help Print short help message and exit\n");
100 printf("-V , --version Print version info and exit\n");
101 printf("-C , --cgi Output to stdout (for use in CGI environments)\n");
102 printf("-v , --verbose Increase verbosity. \n");
103 printf("-o , --output <filename> Set output file to <filename>.\n");
106 int args_callback_command(char*name,char*val)
109 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
116 static struct token_t* file;
123 static void readToken()
125 type = file[pos].type;
127 syntaxerror("unexpected end of file");
129 text = file[pos].text;
130 textlen = strlen(text);
131 line = file[pos].line;
132 column = file[pos].column;
134 //printf("---> %d(%s) %s\n", type, type_names[type], text);
137 static void pushBack()
140 if(!pos) syntaxerror("internal error 3");
145 textlen = strlen(text);
148 column = file[p].column;
151 static int noMoreTokens()
153 if(file[pos].type == END)
171 // ------------------------------ swf routines ----------------------------
175 int type; //0=swf, 1=sprite, 2=clip, 3=button
181 /* for sprites (1): */
187 dictionary_t oldinstances;
194 static int stackpos = 0;
196 static dictionary_t characters;
197 static dictionary_t images;
198 static dictionary_t textures;
199 static dictionary_t outlines;
200 static dictionary_t gradients;
201 static dictionary_t filters;
202 static dictionary_t interpolations;
203 static char idmap[65536];
204 static TAG*tag = 0; //current tag
206 static int id; //current character id
207 static int currentframe; //current frame in current level
208 static SRECT currentrect; //current bounding box in current level
209 static U16 currentdepth;
210 static dictionary_t instances;
211 static dictionary_t fonts;
212 static dictionary_t sounds;
213 static dictionary_t fontUsage;
215 typedef struct _parameters {
217 float scalex, scaley;
223 U8 blendmode; //not interpolated
225 U16 set; // bits indicating wether a parameter was set in the c_placement function
226 U16 flags; // bits to toggle anything you may care to implement as a toggle
229 typedef struct _character {
235 typedef struct _instance {
236 character_t*character;
238 parameters_t parameters;
242 typedef struct _outline {
247 typedef struct _gradient {
253 typedef struct _filter {
257 typedef struct _texture {
261 char* interpolationFunctions[] = {"linear", \
262 "quadIn", "quadOut", "quadInOut", \
263 "cubicIn", "cubicOut", "cubicInOut", \
264 "quartIn", "quartOut", "quartInOut", \
265 "quintIn", "quintOut", "quintInOut", \
266 "circleIn", "circleOut", "circleInOut", \
267 "exponentialIn", "exponentialOut", "exponentialInOut", \
268 "sineIn", "sineOut", "sineInOut", \
269 "elasticIn", "elasticOut", "elasticInOut", \
270 "backIn", "backOut", "backInOut", \
271 "bounceIn", "bounceOut", "bounceInOut", \
272 "fastBounceIn", "fastBounceOut", "fastBounceInOut"};
274 static void character_init(character_t*c)
276 memset(c, 0, sizeof(character_t));
279 static character_t* character_new()
282 c = (character_t*)malloc(sizeof(character_t));
287 static void instance_init(instance_t*i)
289 memset(i, 0, sizeof(instance_t));
290 i->history = history_new();
293 static void instance_free(instance_t* i)
295 history_free(i->history);
299 static instance_t* instance_new()
302 c = (instance_t*)malloc(sizeof(instance_t));
307 static void free_instance(void* i)
309 instance_free((instance_t*)i);
312 static void free_font(void* f)
314 swf_FontFree((SWFFONT*)f);
317 static void gradient_free(GRADIENT* grad)
324 static void free_gradient(void* grad)
326 gradient_free((GRADIENT*) grad);
329 static void outline_free(outline_t* o)
331 free(o->shape->data);
336 static void free_outline(void* o)
338 outline_free((outline_t*)o);
341 static void freeDictionaries()
343 dictionary_free_all(&instances, free_instance);
344 dictionary_free_all(&characters, free);
345 dictionary_free_all(&images, free);
346 dictionary_free_all(&textures, free);
347 dictionary_free_all(&outlines, free_outline);
348 dictionary_free_all(&gradients, free_gradient);
349 dictionary_free_all(&filters, free);
350 dictionary_free_all(&fonts, free_font);
351 dictionary_free_all(&sounds, free);
352 dictionary_free_all(&interpolations, free);
356 static void freeFontDictionary()
358 dictionary_free_all(&fonts, free_font);
361 static void incrementid()
365 syntaxerror("Out of character ids.");
370 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
372 if(dictionary_lookup(&characters, name))
373 syntaxerror("character %s defined twice", name);
374 character_t* c = character_new();
376 c->definingTag = ctag;
379 dictionary_put2(&characters, name, c);
382 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
384 swf_SetString(tag, name);
385 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
388 swf_SetString(tag, name);
391 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
393 if(dictionary_lookup(&images, name))
394 syntaxerror("image %s defined twice", name);
396 character_t* c = character_new();
397 c->definingTag = ctag;
400 dictionary_put2(&images, name, c);
402 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
404 if(dictionary_lookup(&instances, name))
405 syntaxerror("object %s defined twice", name);
406 instance_t* i = instance_new();
409 //swf_GetMatrix(0, &i->matrix);
410 dictionary_put2(&instances, name, i);
414 static void parameters_clear(parameters_t*p)
417 p->scalex = 1.0; p->scaley = 1.0;
420 p->pivot.x = 0; p->pivot.y = 0;
425 swf_GetCXForm(0, &p->cxform, 1);
428 static void makeMatrix(MATRIX*m, parameters_t*p)
437 sx = p->scalex*cos(p->rotate/360*2*M_PI);
438 r1 = -p->scalex*sin(p->rotate/360*2*M_PI)+sx*p->shear;
439 r0 = p->scaley*sin(p->rotate/360*2*M_PI);
440 sy = p->scaley*cos(p->rotate/360*2*M_PI)+r0*p->shear;
442 m->sx = (int)(sx*65536+0.5);
443 m->r1 = (int)(r1*65536+0.5);
444 m->r0 = (int)(r0*65536+0.5);
445 m->sy = (int)(sy*65536+0.5);
449 h = swf_TurnPoint(p->pin, m);
454 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
459 r = swf_TurnRect(rect, &m);
460 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
461 currentrect.xmax == 0 && currentrect.ymax == 0)
464 swf_ExpandRect2(¤trect, &r);
470 interpolation_t* new;
471 new = (interpolation_t*)malloc(sizeof(interpolation_t));
472 new->function = IF_LINEAR;
473 dictionary_put2(&interpolations, "linear", new);
475 new = (interpolation_t*)malloc(sizeof(interpolation_t));
476 new->function = IF_QUAD_IN;
478 dictionary_put2(&interpolations, "quadIn", new);
479 new = (interpolation_t*)malloc(sizeof(interpolation_t));
480 new->function = IF_QUAD_OUT;
482 dictionary_put2(&interpolations, "quadOut", new);
483 new = (interpolation_t*)malloc(sizeof(interpolation_t));
484 new->function = IF_QUAD_IN_OUT;
486 dictionary_put2(&interpolations, "quadInOut", new);
488 new = (interpolation_t*)malloc(sizeof(interpolation_t));
489 new->function = IF_CUBIC_IN;
491 dictionary_put2(&interpolations, "cubicIn", new);
492 new = (interpolation_t*)malloc(sizeof(interpolation_t));
493 new->function = IF_CUBIC_OUT;
495 dictionary_put2(&interpolations, "cubicOut", new);
496 new = (interpolation_t*)malloc(sizeof(interpolation_t));
497 new->function = IF_CUBIC_IN_OUT;
499 dictionary_put2(&interpolations, "cubicInOut", new);
501 new = (interpolation_t*)malloc(sizeof(interpolation_t));
502 new->function = IF_QUART_IN;
504 dictionary_put2(&interpolations, "quartIn", new);
505 new = (interpolation_t*)malloc(sizeof(interpolation_t));
506 new->function = IF_QUART_OUT;
508 dictionary_put2(&interpolations, "quartOut", new);
509 new = (interpolation_t*)malloc(sizeof(interpolation_t));
510 new->function = IF_QUART_IN_OUT;
512 dictionary_put2(&interpolations, "quartInOut", new);
514 new = (interpolation_t*)malloc(sizeof(interpolation_t));
515 new->function = IF_QUINT_IN;
517 dictionary_put2(&interpolations, "quintIn", new);
518 new = (interpolation_t*)malloc(sizeof(interpolation_t));
519 new->function = IF_QUINT_OUT;
521 dictionary_put2(&interpolations, "quintOut", new);
522 new = (interpolation_t*)malloc(sizeof(interpolation_t));
523 new->function = IF_QUINT_IN_OUT;
525 dictionary_put2(&interpolations, "quintInOut", new);
527 new = (interpolation_t*)malloc(sizeof(interpolation_t));
528 new->function = IF_CIRCLE_IN;
529 dictionary_put2(&interpolations, "circleIn", new);
530 new = (interpolation_t*)malloc(sizeof(interpolation_t));
531 new->function = IF_CIRCLE_OUT;
532 dictionary_put2(&interpolations, "circleOut", new);
533 new = (interpolation_t*)malloc(sizeof(interpolation_t));
534 new->function = IF_CIRCLE_IN_OUT;
535 dictionary_put2(&interpolations, "circleInOut", new);
537 new = (interpolation_t*)malloc(sizeof(interpolation_t));
538 new->function = IF_EXPONENTIAL_IN;
539 dictionary_put2(&interpolations, "exponentialIn", new);
540 new = (interpolation_t*)malloc(sizeof(interpolation_t));
541 new->function = IF_EXPONENTIAL_OUT;
542 dictionary_put2(&interpolations, "exponentialOut", new);
543 new = (interpolation_t*)malloc(sizeof(interpolation_t));
544 new->function = IF_EXPONENTIAL_IN_OUT;
545 dictionary_put2(&interpolations, "exponentialInOut", new);
547 new = (interpolation_t*)malloc(sizeof(interpolation_t));
548 new->function = IF_SINE_IN;
549 dictionary_put2(&interpolations, "sineIn", new);
550 new = (interpolation_t*)malloc(sizeof(interpolation_t));
551 new->function = IF_SINE_OUT;
552 dictionary_put2(&interpolations, "sineOut", new);
553 new = (interpolation_t*)malloc(sizeof(interpolation_t));
554 new->function = IF_SINE_IN_OUT;
555 dictionary_put2(&interpolations, "sineInOut", new);
558 memset(&c, 0, sizeof(RGBA));
559 gradient_t* noGradient = (gradient_t*)malloc(sizeof(gradient_t));
560 noGradient->gradient.ratios = (U8*)malloc(16 * sizeof(U8));
561 noGradient->gradient.rgba = (RGBA*)malloc(16 * sizeof(RGBA));
562 noGradient->gradient.num = 2;
563 noGradient->gradient.rgba[0] = c;
564 noGradient->gradient.ratios[0] = 0;
565 noGradient->gradient.rgba[1] = c;
566 noGradient->gradient.ratios[1] = 255;
567 noGradient->radial = 0;
568 noGradient->rotate = 0;
569 dictionary_put2(&gradients, "no_gradient", noGradient);
572 // put a no_filters entry in the filters dictionary to provoce a message when a user tries
573 // to define a no_filters filter. The real filter=no_filters case is handled in parseFilters.
574 FILTER* dummy = (FILTER*)malloc(sizeof(FILTER));
575 dictionary_put2(&filters, "no_filters", dummy);
576 noBlur = (FILTER_BLUR*) swf_NewFilter(FILTERTYPE_BLUR);
578 dictionary_put2(&filters, "no_blur", noBlur);
579 noBevel = (FILTER_BEVEL*) swf_NewFilter(FILTERTYPE_BEVEL);
581 noBevel->composite = 1;
582 dictionary_put2(&filters, "no_bevel", noBevel);
583 noDropshadow = (FILTER_DROPSHADOW*) swf_NewFilter(FILTERTYPE_DROPSHADOW);
584 noDropshadow->passes = 1;
585 noDropshadow->composite = 1;
586 dictionary_put2(&filters, "no_dropshadow", noDropshadow);
587 noGradientGlow = (FILTER_GRADIENTGLOW*) swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
588 noGradientGlow->passes = 1;
589 noGradientGlow->composite = 1;
590 noGradientGlow->gradient = &noGradient->gradient;
591 dictionary_put2(&filters, "no_gradientglow", noGradientGlow);
594 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
597 syntaxerror(".swf blocks can't be nested");
598 if(stackpos==sizeof(stack)/sizeof(stack[0]))
599 syntaxerror("too many levels of recursion");
601 SWF*swf = (SWF*)malloc(sizeof(SWF));
603 memset(swf, 0, sizeof(swf));
604 swf->fileVersion = version;
606 swf->frameRate = fps;
607 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
608 swf->compressed = compress;
609 swf_SetRGB(tag,&background);
611 dictionary_init(&characters);
612 dictionary_init(&images);
613 dictionary_init(&textures);
614 dictionary_init(&outlines);
615 dictionary_init(&gradients);
616 dictionary_init(&filters);
617 dictionary_init(&instances);
618 dictionary_init(&sounds);
619 dictionary_init(&interpolations);
621 cleanUp = &freeDictionaries;
623 memset(&stack[stackpos], 0, sizeof(stack[0]));
624 stack[stackpos].type = 0;
625 stack[stackpos].filename = strdup(name);
626 stack[stackpos].swf = swf;
627 stack[stackpos].oldframe = -1;
631 memset(¤trect, 0, sizeof(currentrect));
634 memset(idmap, 0, sizeof(idmap));
638 void s_sprite(char*name, SRECT*scalegrid)
640 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
641 swf_SetU16(tag, id); //id
642 swf_SetU16(tag, 0); //frames
644 memset(&stack[stackpos], 0, sizeof(stack[0]));
645 stack[stackpos].type = 1;
646 stack[stackpos].oldframe = currentframe;
647 stack[stackpos].olddepth = currentdepth;
648 stack[stackpos].oldrect = currentrect;
649 stack[stackpos].oldinstances = instances;
650 stack[stackpos].tag = tag;
651 stack[stackpos].id = id;
652 stack[stackpos].name = strdup(name);
654 stack[stackpos].scalegrid = *scalegrid;
656 memset(&stack[stackpos].scalegrid, 0, sizeof(SRECT));
659 /* FIXME: those four fields should be bundled together */
660 dictionary_init(&instances);
663 memset(¤trect, 0, sizeof(currentrect));
669 typedef struct _buttonrecord
677 typedef struct _button
681 buttonrecord_t records[4];
684 static button_t mybutton;
686 void s_button(char*name)
688 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
689 swf_SetU16(tag, id); //id
690 swf_ButtonSetFlags(tag, 0); //menu=no
692 memset(&mybutton, 0, sizeof(mybutton));
694 memset(&stack[stackpos], 0, sizeof(stack[0]));
695 stack[stackpos].type = 3;
696 stack[stackpos].tag = tag;
697 stack[stackpos].id = id;
698 stack[stackpos].name = strdup(name);
699 stack[stackpos].oldrect = currentrect;
700 memset(¤trect, 0, sizeof(currentrect));
705 void s_buttonput(char*character, char*as, parameters_t p)
707 character_t* c = dictionary_lookup(&characters, character);
712 if(!stackpos || (stack[stackpos-1].type != 3)) {
713 syntaxerror(".show may only appear in .button");
716 syntaxerror("character %s not known (in .shape %s)", character, character);
718 if(mybutton.endofshapes) {
719 syntaxerror("a .do may not precede a .show", character, character);
722 m = s_instancepos(c->size, &p);
730 if(*s==',' || *s==0) {
731 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
732 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
733 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
734 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
735 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
736 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
743 static void setbuttonrecords(TAG*tag)
745 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
746 if(!mybutton.endofshapes) {
749 if(!mybutton.records[3].set) {
750 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
754 if(mybutton.records[t].set) {
755 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
758 swf_SetU8(tag,0); // end of button records
759 mybutton.endofshapes = 1;
763 void s_buttonaction(int flags, char*action)
769 setbuttonrecords(stack[stackpos-1].tag);
771 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
773 syntaxerror("Couldn't compile ActionScript");
776 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
777 swf_ActionSet(stack[stackpos-1].tag, a);
778 mybutton.nr_actions++;
783 static void setactionend(TAG*tag)
785 if(!mybutton.nr_actions) {
786 /* no actions means we didn't have an actionoffset,
787 which means we can't signal the end of the
788 buttonaction records, so, *sigh*, we have
789 to insert a dummy record */
790 swf_SetU16(tag, 0); //offset
791 swf_SetU16(tag, 0); //condition
792 swf_SetU8(tag, 0); //action
796 static void s_endButton()
799 setbuttonrecords(stack[stackpos-1].tag);
800 setactionend(stack[stackpos-1].tag);
803 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
807 tag = stack[stackpos].tag;
808 currentrect = stack[stackpos].oldrect;
810 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
811 free(stack[stackpos].name);
814 TAG* removeFromTo(TAG*from, TAG*to)
816 TAG*save = from->prev;
818 TAG*next = from->next;
826 static int parametersChange(history_t* history, int frame)
830 willChange = willChange || history_change(history, frame, "x");
831 willChange = willChange || history_change(history, frame, "y");
832 willChange = willChange || history_change(history, frame, "scalex");
833 willChange = willChange || history_change(history, frame, "scaley");
834 willChange = willChange || history_change(history, frame, "cxform.r0");
835 willChange = willChange || history_change(history, frame, "cxform.g0");
836 willChange = willChange || history_change(history, frame, "cxform.b0");
837 willChange = willChange || history_change(history, frame, "cxform.a0");
838 willChange = willChange || history_change(history, frame, "cxform.r1");
839 willChange = willChange || history_change(history, frame, "cxform.g1");
840 willChange = willChange || history_change(history, frame, "cxform.b1");
841 willChange = willChange || history_change(history, frame, "cxform.a1");
842 willChange = willChange || history_change(history, frame, "rotate");
843 willChange = willChange || history_change(history, frame, "shear");
844 willChange = willChange || history_change(history, frame, "pivot.x");
845 willChange = willChange || history_change(history, frame, "pivot.y");
846 willChange = willChange || history_change(history, frame, "pin.x");
847 willChange = willChange || history_change(history, frame, "pin.y");
848 willChange = willChange || history_change(history, frame, "blendmode");
849 willChange = willChange || history_changeFilter(history, frame);
854 static void free_filterlist(FILTERLIST* f_list)
857 for (i = 0; i < f_list->num; i++)
859 if (f_list->filter[i]->type == FILTERTYPE_GRADIENTGLOW)
860 gradient_free(((FILTER_GRADIENTGLOW*)f_list->filter[i])->gradient);
861 free(f_list->filter[i]);
866 static void readParameters(history_t* history, parameters_t* p, int frame)
868 p->x = history_value(history, frame, "x");
869 p->y = history_value(history, frame, "y");
870 p->scalex = history_value(history, frame, "scalex");
871 p->scaley = history_value(history, frame, "scaley");
872 p->cxform.r0 = history_value(history, frame, "cxform.r0");
873 p->cxform.g0 = history_value(history, frame, "cxform.g0");
874 p->cxform.b0 = history_value(history, frame, "cxform.b0");
875 p->cxform.a0 = history_value(history, frame, "cxform.a0");
876 p->cxform.r1 = history_value(history, frame, "cxform.r1");
877 p->cxform.g1 = history_value(history, frame, "cxform.g1");
878 p->cxform.b1 = history_value(history, frame, "cxform.b1");
879 p->cxform.a1 = history_value(history, frame, "cxform.a1");
880 p->rotate = history_rotateValue(history, frame);
881 p->shear = history_value(history, frame, "shear");
882 p->pivot.x = history_value(history, frame, "pivot.x");
883 p->pivot.y = history_value(history, frame, "pivot.y");
884 p->pin.x = history_value(history, frame, "pin.x");
885 p->pin.y = history_value(history, frame, "pin.y");
886 p->blendmode = history_value(history, frame, "blendmode");
887 p->filters = history_filterValue(history, frame);
890 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move)
894 swf_GetPlaceObject(NULL, &po);
898 po.cxform = p->cxform;
904 po.blendmode = p->blendmode;
907 po.filters = p->filters;
908 swf_SetPlaceObject(tag, &po);
911 static void writeInstance(instance_t* i)
915 int frame = i->history->firstFrame;
916 TAG* tag = i->history->firstTag;
917 history_processFlags(i->history);
918 while (frame < currentframe)
921 while (tag->id != ST_SHOWFRAME)
923 if (parametersChange(i->history, frame))
925 readParameters(i->history, &p, frame);
926 m = s_instancepos(i->character->size, &p);
928 if(p.blendmode || p.filters)
929 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
931 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
932 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
934 free_filterlist(p.filters);
941 void dumpSWF(SWF*swf)
943 TAG* tag = swf->firstTag;
944 printf("vvvvvvvvvvvvvvvvvvvvv\n");
946 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
949 printf("^^^^^^^^^^^^^^^^^^^^^\n");
952 static void s_endSprite()
954 SRECT r = currentrect;
956 if(stack[stackpos].cut)
957 tag = removeFromTo(stack[stackpos].cut, tag);
961 stringarray_t* index =dictionary_index(&instances);
963 for (num = 0; num < dictionary_count(&instances); num++)
965 char* name = stringarray_at(index, num);
968 i = dictionary_lookup(&instances, name);
973 // the writeInstance loop above may have inserted tags after what used yo be the current tag,
974 // so let's make sure 'tag' point to the current tag again.
978 tag = swf_InsertTag(tag, ST_SHOWFRAME);
979 tag = swf_InsertTag(tag, ST_END);
981 tag = stack[stackpos].tag;
984 if(stack[stackpos].scalegrid.xmin | stack[stackpos].scalegrid.ymin |
985 stack[stackpos].scalegrid.xmax | stack[stackpos].scalegrid.ymax)
987 tag = swf_InsertTag(tag, ST_DEFINESCALINGGRID);
988 swf_SetU16(tag, stack[stackpos].id);
989 swf_SetRect(tag, &stack[stackpos].scalegrid);
993 syntaxerror("internal error(7)");
994 /* TODO: before clearing, prepend "<spritename>." to names and
995 copy into old instances dict */
996 dictionary_free_all(&instances, free_instance);
998 currentframe = stack[stackpos].oldframe;
999 currentrect = stack[stackpos].oldrect;
1000 currentdepth = stack[stackpos].olddepth;
1001 instances = stack[stackpos].oldinstances;
1003 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
1004 free(stack[stackpos].name);
1007 static void s_endSWF()
1014 stringarray_t* index = dictionary_index(&instances);
1016 for (num = 0; num < dictionary_count(&instances); num++)
1018 char* name = stringarray_at(index, num);
1021 i = dictionary_lookup(&instances, name);
1026 if(stack[stackpos].cut)
1027 tag = removeFromTo(stack[stackpos].cut, tag);
1031 swf = stack[stackpos].swf;
1032 filename = stack[stackpos].filename;
1034 // the writeInstance loop above may have inserted tags after what used yo be the current tag,
1035 // so let's make sure 'tag' point to the current tag again.
1039 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
1040 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
1041 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1043 tag = swf_InsertTag(tag, ST_END);
1045 swf_OptimizeTagOrder(swf);
1051 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1052 swf->movieSize = currentrect; /* "autocrop" */
1055 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1056 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
1057 swf->movieSize.ymax += 20;
1058 warning("Empty bounding box for movie");
1061 if(do_cgi || !strcmp(filename, "-"))
1062 fi = fileno(stdout);
1064 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
1066 syntaxerror("couldn't create output file %s", filename);
1069 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
1071 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
1085 if(stack[stackpos-1].type == 0)
1086 syntaxerror("End of file encountered in .flash block");
1087 if(stack[stackpos-1].type == 1)
1088 syntaxerror("End of file encountered in .sprite block");
1089 if(stack[stackpos-1].type == 2)
1090 syntaxerror("End of file encountered in .clip block");
1096 return currentframe+1;
1099 void s_frame(int nr, int cut, char*name, char anchor)
1105 syntaxerror("Illegal frame number");
1106 nr--; // internally, frame 1 is frame 0
1108 for(t=currentframe;t<nr;t++) {
1109 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1110 if(t==nr-1 && name && *name) {
1111 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1112 swf_SetString(tag, name);
1114 swf_SetU8(tag, 1); //make this an anchor
1117 if(nr == 0 && currentframe == 0 && name && *name) {
1118 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1119 swf_SetString(tag, name);
1121 swf_SetU8(tag, 1); //make this an anchor
1126 syntaxerror("Can't cut, frame empty");
1128 stack[stackpos].cut = tag;
1134 int parseColor2(char*str, RGBA*color);
1136 int addFillStyle(SHAPE*s, SRECT*r, char*name)
1140 gradient_t*gradient;
1142 if(name[0] == '#') {
1143 parseColor2(name, &color);
1144 return swf_ShapeAddSolidFillStyle(s, &color);
1145 } else if ((texture = dictionary_lookup(&textures, name))) {
1146 return swf_ShapeAddFillStyle2(s, &texture->fs);
1147 } else if((image = dictionary_lookup(&images, name))) {
1149 swf_GetMatrix(0, &m);
1150 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1151 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1154 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1155 } else if ((gradient = dictionary_lookup(&gradients, name))) {
1159 swf_GetMatrix(0, &rot);
1160 ccos = cos(-gradient->rotate*2*M_PI/360);
1161 csin = sin(-gradient->rotate*2*M_PI/360);
1162 rot.sx = ccos*65536;
1163 rot.r1 = -csin*65536;
1164 rot.r0 = csin*65536;
1165 rot.sy = ccos*65536;
1166 r2 = swf_TurnRect(*r, &rot);
1167 swf_GetMatrix(0, &m);
1168 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1169 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1170 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1171 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1172 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1173 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1174 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1175 } else if (parseColor2(name, &color)) {
1176 return swf_ShapeAddSolidFillStyle(s, &color);
1178 syntaxerror("not a color/fillstyle: %s", name);
1183 RGBA black={r:0,g:0,b:0,a:0};
1184 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
1193 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1196 linewidth = linewidth>=20?linewidth-20:0;
1197 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1200 fs1 = addFillStyle(s, &r2, texture);
1203 r.xmin = r2.xmin-linewidth/2;
1204 r.ymin = r2.ymin-linewidth/2;
1205 r.xmax = r2.xmax+linewidth/2;
1206 r.ymax = r2.ymax+linewidth/2;
1207 swf_SetRect(tag,&r);
1208 swf_SetShapeHeader(tag,s);
1209 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1210 swf_ShapeSetLine(tag,s,width,0);
1211 swf_ShapeSetLine(tag,s,0,height);
1212 swf_ShapeSetLine(tag,s,-width,0);
1213 swf_ShapeSetLine(tag,s,0,-height);
1214 swf_ShapeSetEnd(tag);
1217 s_addcharacter(name, id, tag, r);
1221 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
1227 outline = dictionary_lookup(&outlines, outlinename);
1229 syntaxerror("outline %s not defined", outlinename);
1233 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1236 linewidth = linewidth>=20?linewidth-20:0;
1237 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1240 fs1 = addFillStyle(s, &r2, texture);
1243 rect.xmin = r2.xmin-linewidth/2;
1244 rect.ymin = r2.ymin-linewidth/2;
1245 rect.xmax = r2.xmax+linewidth/2;
1246 rect.ymax = r2.ymax+linewidth/2;
1248 swf_SetRect(tag,&rect);
1249 swf_SetShapeStyles(tag, s);
1250 swf_ShapeCountBits(s,0,0);
1251 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1252 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1253 swf_SetShapeBits(tag, s);
1254 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1257 s_addcharacter(name, id, tag, rect);
1261 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
1266 r2.xmin = r2.ymin = 0;
1270 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1273 linewidth = linewidth>=20?linewidth-20:0;
1274 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1277 fs1 = addFillStyle(s, &r2, texture);
1279 rect.xmin = r2.xmin-linewidth/2;
1280 rect.ymin = r2.ymin-linewidth/2;
1281 rect.xmax = r2.xmax+linewidth/2;
1282 rect.ymax = r2.ymax+linewidth/2;
1284 swf_SetRect(tag,&rect);
1285 swf_SetShapeHeader(tag,s);
1286 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1287 swf_ShapeSetCircle(tag, s, r,r,r,r);
1288 swf_ShapeSetEnd(tag);
1291 s_addcharacter(name, id, tag, rect);
1295 void s_textshape(char*name, char*fontname, float size, char*_text)
1298 U8*text = (U8*)_text;
1302 font = dictionary_lookup(&fonts, fontname);
1304 syntaxerror("font \"%s\" not known!", fontname);
1306 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1307 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1308 s_box(name, 0, 0, black, 20, 0);
1311 g = font->ascii2glyph[text[0]];
1313 outline = malloc(sizeof(outline_t));
1314 memset(outline, 0, sizeof(outline_t));
1315 outline->shape = font->glyph[g].shape;
1316 outline->bbox = font->layout->bounds[g];
1320 swf_Shape11DrawerInit(&draw, 0);
1321 swf_DrawText(&draw, font, (int)(size*100), _text);
1323 outline->shape = swf_ShapeDrawerToShape(&draw);
1324 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1325 draw.dealloc(&draw);
1328 if(dictionary_lookup(&outlines, name))
1329 syntaxerror("outline %s defined twice", name);
1330 dictionary_put2(&outlines, name, outline);
1333 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
1338 font = dictionary_lookup(&fonts, fontname);
1340 syntaxerror("font \"%s\" not known!", fontname);
1342 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1343 swf_SetU16(tag, id);
1344 if(!font->numchars) {
1345 s_box(name, 0, 0, black, 20, 0);
1348 r = swf_SetDefineText(tag, font, &color, text, size);
1350 if(stack[0].swf->fileVersion >= 8) {
1351 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1352 swf_SetU16(tag, id);
1353 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1354 swf_SetU32(tag, 0);//thickness
1355 swf_SetU32(tag, 0);//sharpness
1356 swf_SetU8(tag, 0);//reserved
1359 s_addcharacter(name, id, tag, r);
1363 void s_quicktime(char*name, char*url)
1368 memset(&r, 0, sizeof(r));
1370 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1371 swf_SetU16(tag, id);
1372 swf_SetString(tag, url);
1374 s_addcharacter(name, id, tag, r);
1378 void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags, int align)
1381 EditTextLayout layout;
1384 if(fontname && *fontname) {
1385 flags |= ET_USEOUTLINES;
1386 font = dictionary_lookup(&fonts, fontname);
1388 syntaxerror("font \"%s\" not known!", fontname);
1390 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1391 swf_SetU16(tag, id);
1392 layout.align = align;
1393 layout.leftmargin = 0;
1394 layout.rightmargin = 0;
1402 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
1404 s_addcharacter(name, id, tag, r);
1408 /* type: either "jpeg" or "png"
1410 void s_image(char*name, char*type, char*filename, int quality)
1412 /* an image is actually two folded: 1st bitmap, 2nd character.
1413 Both of them can be used separately */
1415 /* step 1: the bitmap */
1419 if(!strcmp(type,"jpeg")) {
1420 #ifndef HAVE_JPEGLIB
1421 warning("no jpeg support compiled in");
1422 s_box(name, 0, 0, black, 20, 0);
1425 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1426 swf_SetU16(tag, imageID);
1428 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1429 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1432 swf_GetJPEGSize(filename, &width, &height);
1439 s_addimage(name, id, tag, r);
1442 } else if(!strcmp(type,"png")) {
1444 swf_SetU16(tag, imageID);
1446 getPNG(filename, &width, &height, (unsigned char**)&data);
1449 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1452 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1453 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1454 swf_SetU16(tag, imageID);
1455 swf_SetLosslessImage(tag, data, width, height);
1462 s_addimage(name, id, tag, r);
1465 warning("image type \"%s\" not supported yet!", type);
1466 s_box(name, 0, 0, black, 20, 0);
1470 /* step 2: the character */
1471 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1472 swf_SetU16(tag, id);
1473 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1475 s_addcharacter(name, id, tag, r);
1479 void s_getBitmapSize(char*name, int*width, int*height)
1481 character_t* image = dictionary_lookup(&images, name);
1482 gradient_t* gradient = dictionary_lookup(&gradients,name);
1484 *width = image->size.xmax;
1485 *height = image->size.ymax;
1489 /* internal SWF gradient size */
1490 if(gradient->radial) {
1499 syntaxerror("No such bitmap/gradient: %s", name);
1502 void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1504 if(dictionary_lookup(&textures, name))
1505 syntaxerror("texture %s defined twice", name);
1506 gradient_t* gradient = dictionary_lookup(&gradients, object);
1507 character_t* bitmap = dictionary_lookup(&images, object);
1508 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1510 FILLSTYLE*fs = &texture->fs;
1512 memset(&p, 0, sizeof(parameters_t));
1515 fs->type = FILL_TILED;
1516 fs->id_bitmap = bitmap->id;
1517 } else if(gradient) {
1518 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1519 fs->gradient = gradient->gradient;
1521 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1522 makeMatrix(&fs->m, &p);
1523 if(gradient && !gradient->radial) {
1530 p2 = swf_TurnPoint(p1, &m);
1539 dictionary_put2(&textures, name, texture);
1542 void s_font(char*name, char*filename)
1545 font = dictionary_lookup(&fonts, name);
1548 /* fix the layout. Only needed for old fonts */
1550 for(t=0;t<font->numchars;t++) {
1551 font->glyph[t].advance = 0;
1554 swf_FontCreateLayout(font);
1557 swf_FontReduce_swfc(font);
1558 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1559 swf_FontSetDefine2(tag, font);
1561 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1563 swf_SetU16(tag, id);
1564 swf_SetString(tag, name);
1572 typedef struct _sound_t
1578 void s_sound(char*name, char*filename)
1580 struct WAV wav, wav2;
1584 unsigned numsamples = 1;
1585 unsigned blocksize = 1152;
1588 if(dictionary_lookup(&sounds, name))
1589 syntaxerror("sound %s defined twice", name);
1591 if(wav_read(&wav, filename))
1594 wav_convert2mono(&wav, &wav2, 44100);
1595 samples = (U16*)wav2.data;
1596 numsamples = wav2.size/2;
1598 #ifdef WORDS_BIGENDIAN
1600 for(t=0;t<numsamples;t++)
1601 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1605 if(mp3_read(&mp3, filename))
1607 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1613 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1618 if(numsamples%blocksize != 0)
1620 // apply padding, so that block is a multiple of blocksize
1621 int numblocks = (numsamples+blocksize-1)/blocksize;
1624 numsamples2 = numblocks * blocksize;
1625 samples2 = malloc(sizeof(U16)*numsamples2);
1626 memcpy(samples2, samples, numsamples*sizeof(U16));
1627 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1628 numsamples = numsamples2;
1633 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1634 swf_SetU16(tag, id); //id
1637 swf_SetSoundDefineMP3(
1638 tag, mp3.data, mp3.size,
1645 swf_SetSoundDefine(tag, samples, numsamples);
1648 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1649 swf_SetU16(tag, id);
1650 swf_SetString(tag, name);
1651 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1653 swf_SetU16(tag, id);
1654 swf_SetString(tag, name);
1657 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1661 dictionary_put2(&sounds, name, sound);
1669 static char* gradient_getToken(const char**p)
1673 while(**p && strchr(" \t\n\r", **p)) {
1677 while(**p && !strchr(" \t\n\r", **p)) {
1680 result = malloc((*p)-start+1);
1681 memcpy(result,start,(*p)-start+1);
1682 result[(*p)-start] = 0;
1686 float parsePercent(char*str);
1687 RGBA parseColor(char*str);
1689 GRADIENT parseGradient(const char*str)
1693 const char* p = str;
1694 memset(&gradient, 0, sizeof(GRADIENT));
1695 gradient.ratios = rfx_calloc(16*sizeof(U8));
1696 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1700 char*posstr,*colorstr;
1703 posstr = gradient_getToken(&p);
1709 pos = (int)(parsePercent(posstr)*255.0);
1714 rfx_free(gradient.ratios);
1715 rfx_free(gradient.rgba);
1717 syntaxerror("Error in shape data: Color expected after %s", posstr);
1719 colorstr = gradient_getToken(&p);
1720 color = parseColor(colorstr);
1721 if(gradient.num == 16)
1723 warning("gradient record too big- max size is 16, rest ignored");
1726 gradient.ratios[gradient.num] = pos;
1727 gradient.rgba[gradient.num] = color;
1736 FILTERLIST* parseFilters(char* list)
1738 if (!strcmp(list, "no_filters"))
1741 FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1743 char* f_start = list;
1747 f_end = strchr(f_start, ',');
1750 f = dictionary_lookup(&filters, f_start);
1754 syntaxerror("unknown filter %s", f_start);
1756 if (f_list->num == 8)
1758 warning("too many filters in filterlist, no more than 8 please, rest ignored");
1761 f_list->filter[f_list->num] = f;
1766 f_start = f_end + 1;
1774 void s_gradient(char*name, const char*text, int radial, int rotate)
1776 gradient_t* gradient;
1777 gradient = malloc(sizeof(gradient_t));
1778 memset(gradient, 0, sizeof(gradient_t));
1779 gradient->gradient = parseGradient(text);
1780 gradient->radial = radial;
1781 gradient->rotate = rotate;
1783 dictionary_put2(&gradients, name, gradient);
1786 void s_gradientglow(char*name, char*gradient, float blurx, float blury,
1787 float angle, float distance, float strength, char innershadow,
1788 char knockout, char composite, char ontop, int passes)
1790 if(dictionary_lookup(&filters, name))
1791 syntaxerror("filter %s defined twice", name);
1793 gradient_t* g = dictionary_lookup(&gradients, gradient);
1795 syntaxerror("unknown gradient %s", gradient);
1799 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1800 filter->type = FILTERTYPE_GRADIENTGLOW;
1801 filter->gradient = &g->gradient;
1802 filter->blurx = blurx;
1803 filter->blury = blury;
1804 filter->strength = strength;
1805 filter->angle = angle;
1806 filter->distance = distance;
1807 filter->innershadow = innershadow;
1808 filter->knockout = knockout;
1809 filter->composite = composite;
1810 filter->ontop = ontop;
1811 filter->passes = passes;
1813 dictionary_put2(&filters, name, filter);
1816 void s_dropshadow(char*name, RGBA color, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, int passes)
1818 if(dictionary_lookup(&filters, name))
1819 syntaxerror("filter %s defined twice", name);
1822 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1823 filter->type = FILTERTYPE_DROPSHADOW;
1824 filter->color= color;
1825 filter->blurx = blurx;
1826 filter->blury = blury;
1827 filter->strength = strength;
1828 filter->angle = angle;
1829 filter->distance = distance;
1830 filter->innershadow = innershadow;
1831 filter->knockout = knockout;
1832 filter->composite = composite;
1833 filter->passes = passes;
1835 dictionary_put2(&filters, name, filter);
1838 void s_bevel(char*name, RGBA shadow, RGBA highlight, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, char ontop, int passes)
1840 if(dictionary_lookup(&filters, name))
1841 syntaxerror("filter %s defined twice", name);
1844 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1845 filter->type = FILTERTYPE_BEVEL;
1846 filter->shadow = shadow;
1847 filter->highlight = highlight;
1848 filter->blurx = blurx;
1849 filter->blury = blury;
1850 filter->strength = strength;
1851 filter->angle = angle;
1852 filter->distance = distance;
1853 filter->innershadow = innershadow;
1854 filter->knockout = knockout;
1855 filter->composite = composite;
1856 filter->ontop = ontop;
1857 filter->passes = passes;
1859 dictionary_put2(&filters, name, filter);
1862 void s_blur(char*name, double blurx, double blury, int passes)
1864 if(dictionary_lookup(&filters, name))
1865 syntaxerror("filter %s defined twice", name);
1867 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1868 filter->type = FILTERTYPE_BLUR;
1869 filter->blurx = blurx;
1870 filter->blury = blury;
1871 filter->passes = passes;
1873 dictionary_put2(&filters, name, filter);
1876 void s_action(const char*text)
1879 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1883 syntaxerror("Couldn't compile ActionScript");
1886 tag = swf_InsertTag(tag, ST_DOACTION);
1888 swf_ActionSet(tag, a);
1893 void s_initaction(const char*character, const char*text)
1897 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1901 syntaxerror("Couldn't compile ActionScript");
1904 c = (character_t*)dictionary_lookup(&characters, character);
1906 tag = swf_InsertTag(tag, ST_DOINITACTION);
1907 swf_SetU16(tag, c->id);
1908 swf_ActionSet(tag, a);
1913 int s_swf3action(char*name, char*action)
1916 instance_t* object = 0;
1918 object = (instance_t*)dictionary_lookup(&instances, name);
1919 if(!object && name && *name) {
1920 /* we have a name, but couldn't find it. Abort. */
1923 a = action_SetTarget(0, name);
1924 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1925 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1926 else if(!strcmp(action, "stop")) a = action_Stop(a);
1927 else if(!strcmp(action, "play")) a = action_Play(a);
1928 a = action_SetTarget(a, "");
1931 tag = swf_InsertTag(tag, ST_DOACTION);
1932 swf_ActionSet(tag, a);
1937 void s_outline(char*name, char*format, char*source)
1939 if(dictionary_lookup(&outlines, name))
1940 syntaxerror("outline %s defined twice", name);
1949 //swf_Shape10DrawerInit(&draw, 0);
1950 swf_Shape11DrawerInit(&draw, 0);
1952 draw_string(&draw, source);
1954 shape = swf_ShapeDrawerToShape(&draw);
1955 bounds = swf_ShapeDrawerGetBBox(&draw);
1956 draw.dealloc(&draw);
1958 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1959 outline->shape = shape;
1960 outline->bbox = bounds;
1962 dictionary_put2(&outlines, name, outline);
1965 int s_playsound(char*name, int loops, int nomultiple, int stop)
1971 sound = dictionary_lookup(&sounds, name);
1975 tag = swf_InsertTag(tag, ST_STARTSOUND);
1976 swf_SetU16(tag, sound->id); //id
1977 memset(&info, 0, sizeof(info));
1980 info.nomultiple = nomultiple;
1981 swf_SetSoundInfo(tag, &info);
1985 void s_includeswf(char*name, char*filename)
1993 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1994 f = open(filename,O_RDONLY|O_BINARY);
1996 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1997 s_box(name, 0, 0, black, 20, 0);
2000 if (swf_ReadSWF(f,&swf)<0) {
2001 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
2002 s_box(name, 0, 0, black, 20, 0);
2007 /* FIXME: The following sets the bounding Box for the character.
2008 It is wrong for two reasons:
2009 a) It may be too small (in case objects in the movie clip at the borders)
2010 b) it may be too big (because the poor movie never got autocropped)
2014 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2015 swf_SetU16(tag, id);
2016 swf_SetU16(tag, swf.frameCount);
2018 swf_Relocate(&swf, idmap);
2020 ftag = swf.firstTag;
2024 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
2025 if(cutout[t] == ftag->id) {
2029 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
2031 if(ftag->id == ST_END)
2036 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
2037 /* We simply dump all tags right after the sprite
2038 header, relying on the fact that swf_OptimizeTagOrder() will
2039 sort things out for us later.
2040 We also rely on the fact that the imported SWF is well-formed.
2042 tag = swf_InsertTag(tag, ftag->id);
2043 swf_SetBlock(tag, ftag->data, ftag->len);
2049 syntaxerror("Included file %s contains errors", filename);
2050 tag = swf_InsertTag(tag, ST_END);
2054 s_addcharacter(name, id, tag, r);
2057 SRECT s_getCharBBox(char*name)
2059 character_t* c = dictionary_lookup(&characters, name);
2060 if(!c) syntaxerror("character '%s' unknown(2)", name);
2063 SRECT s_getInstanceBBox(char*name)
2065 instance_t * i = dictionary_lookup(&instances, name);
2067 if(!i) syntaxerror("instance '%s' unknown(4)", name);
2069 if(!c) syntaxerror("internal error(5)");
2072 void s_getParameters(char*name, parameters_t* p)
2074 instance_t * i = dictionary_lookup(&instances, name);
2076 syntaxerror("instance '%s' unknown(10)", name);
2077 if (change_sets_all)
2078 readParameters(i->history, p, currentframe);
2083 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2085 history_begin(i->history, "x", currentframe, tag, p->x);
2086 history_begin(i->history, "y", currentframe, tag, p->y);
2087 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2088 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2089 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2090 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2091 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2092 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2093 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2094 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2095 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2096 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2097 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2098 history_begin(i->history, "shear", currentframe, tag, p->shear);
2099 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2100 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2101 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2102 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2103 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2104 history_beginFilter(i->history, currentframe, tag, p->filters);
2105 history_begin(i->history, "flags", currentframe, tag, 0);
2108 void s_startclip(char*instance, char*character, parameters_t p)
2110 character_t* c = dictionary_lookup(&characters, character);
2114 syntaxerror("character %s not known", character);
2116 i = s_addinstance(instance, c, currentdepth);
2118 m = s_instancepos(i->character->size, &p);
2120 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2121 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2122 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2124 stack[stackpos].tag = tag;
2125 stack[stackpos].type = 2;
2128 setStartparameters(i, &p, tag);
2135 swf_SetTagPos(stack[stackpos].tag, 0);
2136 swf_GetPlaceObject(stack[stackpos].tag, &p);
2137 p.clipdepth = currentdepth;
2139 swf_ClearTag(stack[stackpos].tag);
2140 swf_SetPlaceObject(stack[stackpos].tag, &p);
2144 void s_put(char*instance, char*character, parameters_t p)
2146 character_t* c = dictionary_lookup(&characters, character);
2150 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2152 i = s_addinstance(instance, c, currentdepth);
2154 m = s_instancepos(i->character->size, &p);
2156 if(p.blendmode || p.filters)
2158 if(stack[0].swf->fileVersion < 8)
2161 warning("blendmodes only supported for flash version>=8");
2163 warning("filters only supported for flash version>=8");
2165 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2168 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2169 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2170 setStartparameters(i, &p, tag);
2174 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2177 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2179 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2180 if (p.set & SF_SCALEX)
2181 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2182 if (p.set & SF_SCALEY)
2183 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2184 if (p.set & SF_CX_R)
2186 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2187 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2189 if (p.set & SF_CX_G)
2191 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2192 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2194 if (p.set & SF_CX_B)
2196 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2197 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2199 if (p.set & SF_CX_A)
2201 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2202 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2204 if (p.set & SF_ROTATE)
2205 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2206 if (p.set & SF_SHEAR)
2207 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2208 if (p.set & SF_PIVOT)
2210 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2211 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2215 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2216 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2218 if (p.set & SF_BLEND)
2219 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2220 if (p.set & SF_FILTER)
2221 history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2224 void s_jump(char* instance, parameters_t p)
2226 instance_t* i = dictionary_lookup(&instances, instance);
2228 syntaxerror("instance %s not known", instance);
2229 recordChanges(i->history, p, CF_JUMP, 0);
2232 void s_change(char*instance, parameters_t p, interpolation_t* inter)
2234 instance_t* i = dictionary_lookup(&instances, instance);
2236 syntaxerror("instance %s not known", instance);
2237 recordChanges(i->history, p, CF_CHANGE, inter);
2240 void s_sweep(char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
2242 instance_t* i = dictionary_lookup(&instances, instance);
2244 syntaxerror("instance %s not known", instance);
2245 history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
2248 void s_toggle(char* instance, U16 flagsOn, U16 flagsOff)
2250 instance_t* i = dictionary_lookup(&instances, instance);
2252 syntaxerror("instance %s not known", instance);
2253 U16 flags = (U16)history_value(i->history, currentframe, "flags");
2256 history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
2259 void s_delinstance(char*instance)
2261 instance_t* i = dictionary_lookup(&instances, instance);
2263 syntaxerror("instance %s not known", instance);
2265 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2266 swf_SetU16(tag, i->depth);
2267 dictionary_del(&instances, instance);
2270 void s_schange(char*instance, parameters_t p, interpolation_t* inter)
2272 instance_t* i = dictionary_lookup(&instances, instance);
2274 syntaxerror("instance %s not known", instance);
2275 recordChanges(i->history, p, CF_SCHANGE, inter);
2281 syntaxerror(".end unexpected");
2282 switch (stack[stackpos-1].type)
2297 syntaxerror("internal error 1");
2301 // ------------------------------------------------------------------------
2303 typedef int command_func_t(map_t*args);
2305 SRECT parseBox(char*str)
2307 SRECT r = {0,0,0,0};
2308 float xmin, xmax, ymin, ymax;
2309 char*x = strchr(str, 'x');
2311 if(!strcmp(str, "autocrop")) {
2312 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2316 d1 = strchr(x+1, ':');
2318 d2 = strchr(d1+1, ':');
2320 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2324 else if(d1 && !d2) {
2325 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2331 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2336 r.xmin = (SCOORD)(xmin*20);
2337 r.ymin = (SCOORD)(ymin*20);
2338 r.xmax = (SCOORD)(xmax*20);
2339 r.ymax = (SCOORD)(ymax*20);
2342 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2345 float parseFloat(char*str)
2349 int parseInt(char*str)
2354 if(str[0]=='+' || str[0]=='-')
2358 if(str[t]<'0' || str[t]>'9')
2359 syntaxerror("Not an Integer: \"%s\"", str);
2362 int parseRawTwip(char*str)
2366 if(str[0]=='+' || str[0]=='-') {
2371 dot = strchr(str, '.');
2375 return sign*parseInt(str)*20;
2377 char* old = strdup(str);
2378 int l=strlen(dot+1);
2381 for(s=str;s<dot-1;s++)
2382 if(*s<'0' || *s>'9')
2385 syntaxerror("Not a coordinate: \"%s\"", str);
2388 if(*s<'0' || *s>'9')
2391 syntaxerror("Not a coordinate: \"%s\"", str);
2393 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2394 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2397 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2401 return sign*(atoi(str)*20);
2403 return sign*(atoi(str)*20+atoi(dot)*2);
2405 return sign*(atoi(str)*20+atoi(dot)/5);
2410 static dictionary_t defines;
2411 static int defines_initialized = 0;
2412 static mem_t define_values;
2414 int parseTwip(char*str)
2416 /* TODO: make this a proper expression parser */
2422 if(*p == '+' || *p == '-' || *p == '/' || *p == '*')
2427 if((*p == '+' || *p == '-' || *p == '/' || *p == '*' || *p == 0) && lastpos) {
2433 if(defines_initialized) {
2434 l = (int)dictionary_lookup(&defines, lastpos);
2437 v = *(int*)&define_values.buffer[l-1];
2439 v = parseRawTwip(lastpos);
2459 int parseArc(char* str)
2461 if (!strcmp(str, "short"))
2463 if (!strcmp(str, "long"))
2465 syntaxerror("invalid value for the arc parameter: %s", str);
2469 int parseDir(char* str)
2471 if (!strcmp(str, "clockwise"))
2473 if (!strcmp(str, "counterclockwise"))
2475 syntaxerror("invalid value for the dir parameter: %s", str);
2479 int isPoint(char*str)
2481 if(strchr(str, '('))
2487 SPOINT parsePoint(char*str)
2491 int l = strlen(str);
2492 char*comma = strchr(str, ',');
2493 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2494 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2495 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2496 p.x = parseTwip(tmp);
2497 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2498 p.y = parseTwip(tmp);
2502 int parseColor2(char*str, RGBA*color)
2504 int l = strlen(str);
2508 struct {unsigned char r,g,b;char*name;} colors[] =
2509 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2510 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2511 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2512 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2513 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2514 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2515 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2516 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2517 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2518 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2519 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2520 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2524 if(str[0]=='#' && (l==7 || l==9)) {
2525 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2527 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2529 color->r = r; color->g = g; color->b = b; color->a = a;
2532 int len=strlen(str);
2534 if(strchr(str, '/')) {
2535 len = strchr(str, '/')-str;
2536 sscanf(str+len+1,"%02x", &alpha);
2538 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2539 if(!strncmp(str, colors[t].name, len)) {
2544 color->r = r; color->g = g; color->b = b; color->a = a;
2550 RGBA parseColor(char*str)
2553 if(!parseColor2(str, &c))
2554 syntaxerror("Expression '%s' is not a color", str);
2558 typedef struct _muladd {
2563 MULADD parseMulAdd(char*str)
2566 char* str2 = (char*)malloc(strlen(str)+5);
2573 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2574 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2575 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2576 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2577 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2578 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2579 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2580 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2581 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2582 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2584 syntaxerror("'%s' is not a valid color transform expression", str);
2586 m.add = (int)(add*256);
2587 m.mul = (int)(mul*256);
2592 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2594 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2595 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2597 if(a<-32768) a=-32768;
2598 if(a>32767) a=32767;
2599 if(m<-32768) m=-32768;
2600 if(m>32767) m=32767;
2606 float parsePxOrPercent(char*fontname, char*str)
2608 int l = strlen(str);
2609 if(strchr(str, '%'))
2610 return parsePercent(str);
2611 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2612 float p = atof(str);
2613 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2615 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2619 float parsePercent(char*str)
2621 int l = strlen(str);
2625 return atoi(str)/100.0;
2627 syntaxerror("Expression '%s' is not a percentage", str);
2630 int isPercent(char*str)
2632 return str[strlen(str)-1]=='%';
2634 int parseNewSize(char*str, int size)
2637 return parsePercent(str)*size;
2639 return (int)(atof(str)*20);
2642 int isColor(char*str)
2645 return parseColor2(str, &c);
2648 static char* lu(map_t* args, char*name)
2650 char* value = map_lookup(args, name);
2652 map_dump(args, stdout, "");
2653 syntaxerror("internal error 2: value %s should be set", name);
2658 static int c_flash(map_t*args)
2660 char* filename = map_lookup(args, "filename");
2661 char* compressstr = lu(args, "compress");
2662 char* change_modestr = lu(args, "change-sets-all");
2663 char* exportstr = lu(args, "export");
2664 SRECT bbox = parseBox(lu(args, "bbox"));
2665 int version = parseInt(lu(args, "version"));
2666 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2667 RGBA color = parseColor(lu(args, "background"));
2670 if(!filename || !*filename) {
2671 /* for compatibility */
2672 filename = map_lookup(args, "name");
2673 if(!filename || !*filename) {
2676 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2677 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2681 if(!filename || override_outputname)
2682 filename = outputname;
2684 if(!strcmp(compressstr, "default"))
2685 compress = version>=6;
2686 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2688 else if(!strcmp(compressstr, "no"))
2690 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2692 if(!strcmp(change_modestr, "yes"))
2693 change_sets_all = 1;
2695 if(strcmp(change_modestr, "no"))
2696 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2698 do_exports=atoi(exportstr);
2700 s_swf(filename, bbox, version, fps, compress, color);
2703 int isRelative(char*str)
2705 return !strncmp(str, "<plus>", 6) ||
2706 !strncmp(str, "<minus>", 7);
2708 char* getOffset(char*str)
2710 if(!strncmp(str, "<plus>", 6))
2712 if(!strncmp(str, "<minus>", 7))
2714 syntaxerror("internal error (347)");
2717 int getSign(char*str)
2719 if(!strncmp(str, "<plus>", 6))
2721 if(!strncmp(str, "<minus>", 7))
2723 syntaxerror("internal error (348)");
2727 static dictionary_t points;
2728 static mem_t mpoints;
2729 static int points_initialized = 0;
2731 static int c_interpolation(map_t *args)
2734 char* name = lu(args, "name");
2735 if (dictionary_lookup(&interpolations, name))
2736 syntaxerror("interpolation %s defined twice", name);
2738 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2739 char* functionstr = lu(args, "function");
2740 inter->function = 0;
2741 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2742 if (!strcmp(functionstr,interpolationFunctions[i]))
2744 inter->function = i + 1;
2747 if (!inter->function)
2748 syntaxerror("unkown interpolation function %s", functionstr);
2749 inter->speed = parseFloat(lu(args, "speed"));
2750 inter->amplitude = parseTwip(lu(args, "amplitude"));
2751 inter->growth = parseFloat(lu(args, "growth"));
2752 inter->bounces = parseInt(lu(args, "bounces"));
2753 inter->damping = parseFloat(lu(args, "damping"));
2754 inter->slope = parseFloat(lu(args, "slope"));
2756 dictionary_put2(&interpolations, name, inter);
2760 SPOINT getPoint(SRECT r, char*name)
2763 if(!strcmp(name, "center")) {
2765 p.x = (r.xmin + r.xmax)/2;
2766 p.y = (r.ymin + r.ymax)/2;
2769 if (!strcmp(name, "bottom-center")) {
2771 p.x = (r.xmin + r.xmax)/2;
2775 if (!strcmp(name, "top-center")) {
2777 p.x = (r.xmin + r.xmax)/2;
2781 if (!strcmp(name, "top-left")) {
2787 if (!strcmp(name, "top-right")) {
2793 if (!strcmp(name, "bottom-right")) {
2799 if (!strcmp(name, "bottom-left")) {
2805 if (!strcmp(name, "left-center")) {
2808 p.y = (r.ymin + r.ymax)/2;
2811 if (!strcmp(name, "right-center")) {
2814 p.y = (r.ymin + r.ymax)/2;
2819 if(points_initialized)
2820 l = (int)dictionary_lookup(&points, name);
2822 syntaxerror("Invalid point: \"%s\".", name);
2824 return *(SPOINT*)&mpoints.buffer[l-1];
2828 static int texture2(char*name, char*object, map_t*args, int errors)
2831 char*xstr = map_lookup(args, "x");
2832 char*ystr = map_lookup(args, "y");
2833 char*widthstr = map_lookup(args, "width");
2834 char*heightstr = map_lookup(args, "height");
2835 char*scalestr = map_lookup(args, "scale");
2836 char*scalexstr = map_lookup(args, "scalex");
2837 char*scaleystr = map_lookup(args, "scaley");
2838 char*rotatestr = map_lookup(args, "rotate");
2839 char* shearstr = map_lookup(args, "shear");
2840 char* radiusstr = map_lookup(args, "r");
2842 float scalex = 1.0, scaley = 1.0;
2843 float rotate=0, shear=0;
2845 if(!*xstr && !*ystr) {
2847 syntaxerror("x and y must be set");
2850 if(*scalestr && (*scalexstr || *scaleystr)) {
2851 syntaxerror("scale and scalex/scaley can't both be set");
2854 if((*widthstr || *heightstr) && *radiusstr) {
2855 syntaxerror("width/height and radius can't both be set");
2858 widthstr = radiusstr;
2859 heightstr = radiusstr;
2861 if(!*xstr) xstr="0";
2862 if(!*ystr) ystr="0";
2863 if(!*rotatestr) rotatestr="0";
2864 if(!*shearstr) shearstr="0";
2867 scalex = scaley = parsePercent(scalestr);
2868 } else if(*scalexstr || *scaleystr) {
2869 if(scalexstr) scalex = parsePercent(scalexstr);
2870 if(scaleystr) scaley = parsePercent(scaleystr);
2871 } else if(*widthstr || *heightstr) {
2874 s_getBitmapSize(object, &width, &height);
2876 scalex = (float)parseTwip(widthstr)/(float)width;
2878 scaley = (float)parseTwip(heightstr)/(float)height;
2880 x = parseTwip(xstr);
2881 y = parseTwip(ystr);
2882 rotate = parseFloat(rotatestr);
2883 shear = parseFloat(shearstr);
2885 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2890 static int c_texture(map_t*args)
2892 char*name = lu(args, "instance");
2893 char*object = lu(args, "character");
2894 return texture2(name, object, args, 1);
2897 static int c_gradient(map_t*args)
2899 char*name = lu(args, "name");
2900 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2901 int rotate = parseInt(lu(args, "rotate"));
2905 syntaxerror("colon (:) expected");
2907 if(dictionary_lookup(&gradients, name))
2908 syntaxerror("gradient %s defined twice", name);
2910 s_gradient(name, text, radial, rotate);
2912 /* check whether we also have placement information,
2913 which would make this a positioned gradient.
2914 If there is placement information, texture2() will
2915 add a texture, which has priority over the gradient.
2917 texture2(name, name, args, 0);
2921 static char* checkFiltername(map_t* args)
2923 char* name = lu(args, "name");
2924 if (strchr(name, ','))
2925 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
2929 static int c_blur(map_t*args)
2931 char*name = checkFiltername(args);
2932 char*blurstr = lu(args, "blur");
2933 char*blurxstr = lu(args, "blurx");
2934 char*blurystr = lu(args, "blury");
2935 float blurx=1.0, blury=1.0;
2937 blurx = parseFloat(blurstr);
2938 blury = parseFloat(blurstr);
2941 blurx = parseFloat(blurxstr);
2943 blury = parseFloat(blurystr);
2944 int passes = parseInt(lu(args, "passes"));
2945 s_blur(name, blurx, blury, passes);
2949 static int c_gradientglow(map_t*args)
2951 char*name = checkFiltername(args);
2952 char*gradient = lu(args, "gradient");
2953 char*blurstr = lu(args, "blur");
2954 char*blurxstr = lu(args, "blurx");
2955 char*blurystr = lu(args, "blury");
2956 float blurx=1.0, blury=1.0;
2958 blurx = parseFloat(blurstr);
2959 blury = parseFloat(blurstr);
2962 blurx = parseFloat(blurxstr);
2964 blury = parseFloat(blurystr);
2966 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2967 float distance = parseFloat(lu(args, "distance"));
2968 float strength = parseFloat(lu(args, "strength"));
2969 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2970 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2971 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2972 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2973 int passes = parseInt(lu(args, "passes"));
2975 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2979 static int c_dropshadow(map_t*args)
2981 char*name = checkFiltername(args);
2982 RGBA color = parseColor(lu(args, "color"));
2983 char*blurstr = lu(args, "blur");
2984 char*blurxstr = lu(args, "blurx");
2985 char*blurystr = lu(args, "blury");
2986 float blurx=1.0, blury=1.0;
2988 blurx = parseFloat(blurstr);
2989 blury = parseFloat(blurstr);
2992 blurx = parseFloat(blurxstr);
2994 blury = parseFloat(blurystr);
2996 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2997 float distance = parseFloat(lu(args, "distance"));
2998 float strength = parseFloat(lu(args, "strength"));
2999 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3000 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3001 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3002 int passes = parseInt(lu(args, "passes"));
3004 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
3008 static int c_bevel(map_t*args)
3010 char*name = checkFiltername(args);
3011 RGBA shadow = parseColor(lu(args, "shadow"));
3012 RGBA highlight = parseColor(lu(args, "highlight"));
3013 char*blurstr = lu(args, "blur");
3014 char*blurxstr = lu(args, "blurx");
3015 char*blurystr = lu(args, "blury");
3016 float blurx=1.0, blury=1.0;
3018 blurx = parseFloat(blurstr);
3019 blury = parseFloat(blurstr);
3022 blurx = parseFloat(blurxstr);
3024 blury = parseFloat(blurystr);
3026 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3027 float distance = parseFloat(lu(args, "distance"));
3028 float strength = parseFloat(lu(args, "strength"));
3029 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3030 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3031 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3032 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3033 int passes = parseInt(lu(args, "passes"));
3035 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3039 static int c_define(map_t*args)
3041 char*name = lu(args, "name");
3042 char*value = lu(args, "value");
3044 if(!defines_initialized) {
3045 dictionary_init(&defines);
3046 mem_init(&define_values);
3047 defines_initialized = 1;
3049 int val = parseTwip(value);
3050 int pos = mem_put(&define_values, &val, sizeof(val));
3052 string_set(&s, name);
3053 dictionary_put(&defines, s, (void*)(pos+1));
3056 static int c_point(map_t*args)
3058 char*name = lu(args, "name");
3062 if(!points_initialized) {
3063 dictionary_init(&points);
3065 points_initialized = 1;
3067 p.x = parseTwip(lu(args, "x"));
3068 p.y = parseTwip(lu(args, "y"));
3069 pos = mem_put(&mpoints, &p, sizeof(p));
3070 string_set(&s1, name);
3071 dictionary_put(&points, s1, (void*)(pos+1));
3074 static int c_play(map_t*args)
3076 char*name = lu(args, "name");
3077 char*loop = lu(args, "loop");
3078 char*nomultiple = lu(args, "nomultiple");
3080 if(!strcmp(nomultiple, "nomultiple"))
3083 nm = parseInt(nomultiple);
3085 if(s_playsound(name, parseInt(loop), nm, 0)) {
3087 } else if(s_swf3action(name, "play")) {
3093 static int c_stop(map_t*args)
3095 char*name = map_lookup(args, "name");
3097 if(s_playsound(name, 0,0,1))
3099 else if(s_swf3action(name, "stop"))
3101 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
3105 static int c_nextframe(map_t*args)
3107 char*name = lu(args, "name");
3109 if(s_swf3action(name, "nextframe")) {
3112 syntaxerror("I don't know anything about movie \"%s\"", name);
3116 static int c_previousframe(map_t*args)
3118 char*name = lu(args, "name");
3120 if(s_swf3action(name, "previousframe")) {
3123 syntaxerror("I don't know anything about movie \"%s\"", name);
3127 static int c_movement(map_t*args, int type)
3129 char*instance = lu(args, "name");
3137 xstr = lu(args, "x");
3138 ystr = lu(args, "y");
3140 s_getParameters(instance, &p);
3145 if(isRelative(xstr))
3147 if(type == PT_PUT || type == PT_STARTCLIP)
3148 syntaxerror("relative x values not allowed for initial put or startclip");
3149 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3153 p.x = parseTwip(xstr);
3159 if(isRelative(ystr))
3161 if(type == PT_PUT || type == PT_STARTCLIP)
3162 syntaxerror("relative y values not allowed for initial put or startclip");
3163 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3167 p.y = parseTwip(ystr);
3172 if (change_sets_all)
3180 char* interstr = lu(args, "interpolation");
3181 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3183 syntaxerror("unkown interpolation %s", interstr);
3184 s_change(instance, p, inter);
3189 char* interstr = lu(args, "interpolation");
3190 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3192 syntaxerror("unkown interpolation %s", interstr);
3193 s_schange(instance, p, inter);
3198 char* rstr = lu(args, "r");
3199 int radius = parseTwip(rstr);
3201 syntaxerror("sweep not possible: radius must be greater than 0.");
3202 char* dirstr = lu(args, "dir");
3203 int clockwise = parseDir(dirstr);
3204 char* arcstr = lu(args, "arc");
3205 int short_arc = parseArc(arcstr);
3206 char* interstr = lu(args, "interpolation");
3207 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3209 syntaxerror("unkown interpolation %s", interstr);
3210 s_sweep(instance, p, radius, clockwise, short_arc, inter);
3217 static int c_placement(map_t*args, int type)
3219 char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3222 char* luminancestr = lu(args, "luminance");
3223 char* scalestr = lu(args, "scale");
3224 char* scalexstr = lu(args, "scalex");
3225 char* scaleystr = lu(args, "scaley");
3226 char* rotatestr = lu(args, "rotate");
3227 char* shearstr = lu(args, "shear");
3228 char* xstr="", *pivotstr="";
3229 char* ystr="", *anglestr="";
3230 char*above = lu(args, "above"); /*FIXME*/
3231 char*below = lu(args, "below");
3232 char* rstr = lu(args, "red");
3233 char* gstr = lu(args, "green");
3234 char* bstr = lu(args, "blue");
3235 char* astr = lu(args, "alpha");
3236 char* pinstr = lu(args, "pin");
3237 char* as = map_lookup(args, "as");
3238 char* blendmode = lu(args, "blend");
3239 char* filterstr = lu(args, "filter");
3250 { // (?) .rotate or .arcchange
3251 pivotstr = lu(args, "pivot");
3252 anglestr = lu(args, "angle");
3256 xstr = lu(args, "x");
3257 ystr = lu(args, "y");
3261 luminance = parseMulAdd(luminancestr);
3265 luminance.mul = 256;
3270 if(scalexstr[0]||scaleystr[0])
3271 syntaxerror("scalex/scaley and scale cannot both be set");
3272 scalexstr = scaleystr = scalestr;
3275 if(type == PT_PUT || type == PT_STARTCLIP) {
3277 character = lu(args, "character");
3278 parameters_clear(&p);
3279 } else if (type == PT_BUTTON) {
3280 character = lu(args, "name");
3281 parameters_clear(&p);
3284 s_getParameters(instance, &p);
3290 if(isRelative(xstr))
3292 if(type == PT_PUT || type == PT_STARTCLIP)
3293 syntaxerror("relative x values not allowed for initial put or startclip");
3294 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3298 p.x = parseTwip(xstr);
3304 if(isRelative(ystr))
3306 if(type == PT_PUT || type == PT_STARTCLIP)
3307 syntaxerror("relative y values not allowed for initial put or startclip");
3308 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3312 p.y = parseTwip(ystr);
3317 /* scale, scalex, scaley */
3319 oldbbox = s_getCharBBox(character);
3321 oldbbox = s_getInstanceBBox(instance);
3322 oldwidth = oldbbox.xmax - oldbbox.xmin;
3323 oldheight = oldbbox.ymax - oldbbox.ymin;
3330 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3331 set = set | SF_SCALEX;
3339 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3340 set = set | SF_SCALEY;
3346 if(isRelative(rotatestr))
3347 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3349 p.rotate = parseFloat(rotatestr);
3350 set = set | SF_ROTATE;
3356 if(isRelative(shearstr))
3357 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3359 p.shear = parseFloat(shearstr);
3360 set = set | SF_SHEAR;
3365 if(isPoint(pivotstr))
3366 p.pivot = parsePoint(pivotstr);
3368 p.pivot = getPoint(oldbbox, pivotstr);
3369 set = set | SF_PIVOT;
3375 p.pin = parsePoint(pinstr);
3377 p.pin = getPoint(oldbbox, pinstr);
3381 /* color transform */
3383 if(rstr[0] || luminancestr[0])
3387 r = parseMulAdd(rstr);
3390 r.add = p.cxform.r0;
3391 r.mul = p.cxform.r1;
3393 r = mergeMulAdd(r, luminance);
3394 p.cxform.r0 = r.mul;
3395 p.cxform.r1 = r.add;
3396 set = set | SF_CX_R;
3398 if(gstr[0] || luminancestr[0])
3402 g = parseMulAdd(gstr);
3405 g.add = p.cxform.g0;
3406 g.mul = p.cxform.g1;
3408 g = mergeMulAdd(g, luminance);
3409 p.cxform.g0 = g.mul;
3410 p.cxform.g1 = g.add;
3411 set = set | SF_CX_G;
3413 if(bstr[0] || luminancestr[0])
3417 b = parseMulAdd(bstr);
3420 b.add = p.cxform.b0;
3421 b.mul = p.cxform.b1;
3423 b = mergeMulAdd(b, luminance);
3424 p.cxform.b0 = b.mul;
3425 p.cxform.b1 = b.add;
3426 set = set | SF_CX_B;
3430 MULADD a = parseMulAdd(astr);
3431 p.cxform.a0 = a.mul;
3432 p.cxform.a1 = a.add;
3433 set = set | SF_CX_A;
3440 for(t = 0; blendModeNames[t]; t++)
3442 if(!strcmp(blendModeNames[t], blendmode))
3450 syntaxerror("unknown blend mode: '%s'", blendmode);
3452 p.blendmode = blend;
3453 set = set | SF_BLEND;
3458 p.filters = parseFilters(filterstr);
3459 set = set | SF_FILTER;
3462 if (type == PT_CHANGE && set & (SF_X | SF_Y))
3463 warning("As of version 0.8.2 using the .change command to modify an \
3464 object's position on the stage is considered deprecated. Future \
3465 versions may consider x and y parameters for the .change command \
3466 to be illegal; please use the .move command.");
3468 if (change_sets_all)
3475 s_put(instance, character, p);
3479 char* interstr = lu(args, "interpolation");
3480 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3482 syntaxerror("unkown interpolation %s", interstr);
3483 s_change(instance, p, inter);
3488 char* interstr = lu(args, "interpolation");
3489 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3491 syntaxerror("unkown interpolation %s", interstr);
3492 s_schange(instance, p, inter);
3496 s_jump(instance, p);
3499 s_startclip(instance, character, p);
3503 s_buttonput(character, as, p);
3505 s_buttonput(character, "shape", p);
3511 static int c_put(map_t*args)
3513 c_placement(args, PT_PUT);
3516 static int c_change(map_t*args)
3518 if (currentframe == 0)
3519 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3520 c_placement(args, PT_CHANGE);
3523 static int c_schange(map_t*args)
3525 c_placement(args, PT_SCHANGE);
3528 static int c_move(map_t* args)
3530 c_movement(args, PT_MOVE);
3533 static int c_smove(map_t* args)
3535 c_movement(args, PT_SMOVE);
3538 static int c_sweep(map_t* args)
3540 c_movement(args, PT_SWEEP);
3543 static int c_arcchange(map_t*args)
3545 c_placement(args, 0);
3548 static int c_jump(map_t*args)
3550 c_placement(args, PT_JUMP);
3553 static int c_startclip(map_t*args)
3555 c_placement(args, PT_STARTCLIP);
3558 static int c_show(map_t*args)
3560 c_placement(args, PT_BUTTON);
3563 static int c_toggle(map_t* args)
3565 char*instance = lu(args, "name");
3566 U16 flagsOn = 0x0000, flagsOff = 0xffff;
3567 char* alignstr = lu(args, "fixed_alignment");
3568 if (!strcmp(alignstr, "on"))
3569 flagsOn += IF_FIXED_ALIGNMENT;
3571 if (!strcmp(alignstr, "off"))
3572 flagsOff -= IF_FIXED_ALIGNMENT;
3574 syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3575 s_toggle(instance, flagsOn, flagsOff);
3578 static int c_del(map_t*args)
3580 char*instance = lu(args, "name");
3581 s_delinstance(instance);
3584 static int c_end(map_t*args)
3589 static int c_sprite(map_t*args)
3591 char* name = lu(args, "name");
3592 char* scalinggrid = lu(args, "scalinggrid");
3594 if(scalinggrid && *scalinggrid) {
3595 SRECT r = parseBox(scalinggrid);
3602 static int c_frame(map_t*args)
3604 char*framestr = lu(args, "n");
3605 char*cutstr = lu(args, "cut");
3607 char*name = lu(args, "name");
3608 char*anchor = lu(args, "anchor");
3611 if(!strcmp(anchor, "anchor") && !*name)
3616 if(strcmp(cutstr, "no"))
3618 if(isRelative(framestr)) {
3619 frame = s_getframe();
3620 if(getSign(framestr)<0)
3621 syntaxerror("relative frame expressions must be positive");
3622 frame += parseInt(getOffset(framestr));
3625 frame = parseInt(framestr);
3626 if(s_getframe() >= frame
3627 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3628 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3630 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3633 static int c_primitive(map_t*args)
3635 char*name = lu(args, "name");
3636 char*command = lu(args, "commandname");
3637 int width=0, height=0, r=0;
3638 int linewidth = parseTwip(lu(args, "line"));
3639 char*colorstr = lu(args, "color");
3640 RGBA color = parseColor(colorstr);
3641 char*fillstr = lu(args, "fill");
3648 if(!strcmp(command, "circle"))
3650 else if(!strcmp(command, "filled"))
3654 width = parseTwip(lu(args, "width"));
3655 height = parseTwip(lu(args, "height"));
3656 } else if (type==1) {
3657 r = parseTwip(lu(args, "r"));
3658 } else if (type==2) {
3659 outline = lu(args, "outline");
3662 if(!strcmp(fillstr, "fill"))
3664 if(!strcmp(fillstr, "none"))
3666 if(width<0 || height<0 || linewidth<0 || r<0)
3667 syntaxerror("values width, height, line, r must be positive");
3669 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3670 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3671 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3675 static int c_textshape(map_t*args)
3677 char*name = lu(args, "name");
3678 char*text = lu(args, "text");
3679 char*font = lu(args, "font");
3680 float size = parsePxOrPercent(font, lu(args, "size"));
3682 s_textshape(name, font, size, text);
3686 static int c_swf(map_t*args)
3688 char*name = lu(args, "name");
3689 char*filename = lu(args, "filename");
3690 char*command = lu(args, "commandname");
3691 if(!strcmp(command, "shape"))
3692 warning("Please use .swf instead of .shape");
3693 s_includeswf(name, filename);
3697 static int c_font(map_t*args)
3699 char*name = lu(args, "name");
3700 char*filename = lu(args, "filename");
3701 s_font(name, filename);
3705 static int c_sound(map_t*args)
3707 char*name = lu(args, "name");
3708 char*filename = lu(args, "filename");
3709 s_sound(name, filename);
3713 static int c_text(map_t*args)
3715 char*name = lu(args, "name");
3716 char*text = lu(args, "text");
3717 char*font = lu(args, "font");
3718 float size = parsePxOrPercent(font, lu(args, "size"));
3719 RGBA color = parseColor(lu(args, "color"));
3720 s_text(name, font, text, (int)(size*100), color);
3724 static int c_soundtrack(map_t*args)
3729 static int c_quicktime(map_t*args)
3731 char*name = lu(args, "name");
3732 char*url = lu(args, "url");
3733 s_quicktime(name, url);
3737 static int c_image(map_t*args)
3739 char*command = lu(args, "commandname");
3740 char*name = lu(args, "name");
3741 char*filename = lu(args, "filename");
3742 if(!strcmp(command,"jpeg")) {
3743 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3744 s_image(name, "jpeg", filename, quality);
3746 s_image(name, "png", filename, 0);
3751 static int c_outline(map_t*args)
3753 char*name = lu(args, "name");
3754 char*format = lu(args, "format");
3758 syntaxerror("colon (:) expected");
3760 s_outline(name, format, text);
3764 int fakechar(map_t*args)
3766 char*name = lu(args, "name");
3767 s_box(name, 0, 0, black, 20, 0);
3771 static int c_egon(map_t*args) {return fakechar(args);}
3772 static int c_button(map_t*args) {
3773 char*name = lu(args, "name");
3777 static int current_button_flags = 0;
3778 static int c_on_press(map_t*args)
3780 char*position = lu(args, "position");
3782 if(!strcmp(position, "inside")) {
3783 current_button_flags |= BC_OVERUP_OVERDOWN;
3784 } else if(!strcmp(position, "outside")) {
3785 //current_button_flags |= BC_IDLE_OUTDOWN;
3786 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3787 } else if(!strcmp(position, "anywhere")) {
3788 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3791 if(type == RAWDATA) {
3793 s_buttonaction(current_button_flags, action);
3794 current_button_flags = 0;
3800 static int c_on_release(map_t*args)
3802 char*position = lu(args, "position");
3804 if(!strcmp(position, "inside")) {
3805 current_button_flags |= BC_OVERDOWN_OVERUP;
3806 } else if(!strcmp(position, "outside")) {
3807 current_button_flags |= BC_OUTDOWN_IDLE;
3808 } else if(!strcmp(position, "anywhere")) {
3809 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3812 if(type == RAWDATA) {
3814 s_buttonaction(current_button_flags, action);
3815 current_button_flags = 0;
3821 static int c_on_move_in(map_t*args)
3823 char*position = lu(args, "state");
3825 if(!strcmp(position, "pressed")) {
3826 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3827 } else if(!strcmp(position, "not_pressed")) {
3828 current_button_flags |= BC_IDLE_OVERUP;
3829 } else if(!strcmp(position, "any")) {
3830 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3833 if(type == RAWDATA) {
3835 s_buttonaction(current_button_flags, action);
3836 current_button_flags = 0;
3842 static int c_on_move_out(map_t*args)
3844 char*position = lu(args, "state");
3846 if(!strcmp(position, "pressed")) {
3847 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3848 } else if(!strcmp(position, "not_pressed")) {
3849 current_button_flags |= BC_OVERUP_IDLE;
3850 } else if(!strcmp(position, "any")) {
3851 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3854 if(type == RAWDATA) {
3856 s_buttonaction(current_button_flags, action);
3857 current_button_flags = 0;
3863 static int c_on_key(map_t*args)
3865 char*key = lu(args, "key");
3867 if(strlen(key)==1) {
3870 current_button_flags |= 0x4000 + (key[0]*0x200);
3872 syntaxerror("invalid character: %c"+key[0]);
3877 <ctrl-x> = 0x200*(x-'a')
3881 syntaxerror("invalid key: %s",key);
3884 if(type == RAWDATA) {
3886 s_buttonaction(current_button_flags, action);
3887 current_button_flags = 0;
3894 static int c_edittext(map_t*args)
3896 //"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"},
3897 char*name = lu(args, "name");
3898 char*font = lu(args, "font");
3899 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3900 int width = parseTwip(lu(args, "width"));
3901 int height = parseTwip(lu(args, "height"));
3902 char*text = lu(args, "text");
3903 RGBA color = parseColor(lu(args, "color"));
3904 int maxlength = parseInt(lu(args, "maxlength"));
3905 char*variable = lu(args, "variable");
3906 char*passwordstr = lu(args, "password");
3907 char*wordwrapstr = lu(args, "wordwrap");
3908 char*multilinestr = lu(args, "multiline");
3909 char*htmlstr = lu(args, "html");
3910 char*noselectstr = lu(args, "noselect");
3911 char*readonlystr = lu(args, "readonly");
3912 char*borderstr = lu(args, "border");
3913 char*autosizestr = lu(args, "autosize");
3914 char*alignstr = lu(args, "align");
3918 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3919 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3920 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3921 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3922 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3923 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3924 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3925 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3926 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3927 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
3928 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
3929 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
3930 else syntaxerror("Unknown alignment: %s", alignstr);
3932 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
3936 static int c_morphshape(map_t*args) {return fakechar(args);}
3937 static int c_movie(map_t*args) {return fakechar(args);}
3939 static char* readfile(const char*filename)
3941 FILE*fi = fopen(filename, "rb");
3945 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
3946 fseek(fi, 0, SEEK_END);
3948 fseek(fi, 0, SEEK_SET);
3949 text = rfx_alloc(l+1);
3950 fread(text, l, 1, fi);
3956 static int c_action(map_t*args)
3958 char* filename = map_lookup(args, "filename");
3959 if(!filename ||!*filename) {
3961 if(type != RAWDATA) {
3962 syntaxerror("colon (:) expected");
3966 s_action(readfile(filename));
3972 static int c_initaction(map_t*args)
3974 char* character = lu(args, "name");
3975 char* filename = map_lookup(args, "filename");
3976 if(!filename ||!*filename) {
3978 if(type != RAWDATA) {
3979 syntaxerror("colon (:) expected");
3981 s_initaction(character, text);
3983 s_initaction(character, readfile(filename));
3991 command_func_t* func;
3994 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no @export=1"},
3995 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
3996 // "import" type stuff
3997 {"swf", c_swf, "name filename"},
3998 {"shape", c_swf, "name filename"},
3999 {"jpeg", c_image, "name filename quality=80%"},
4000 {"png", c_image, "name filename"},
4001 {"movie", c_movie, "name filename"},
4002 {"sound", c_sound, "name filename"},
4003 {"font", c_font, "name filename glyphs="},
4004 {"soundtrack", c_soundtrack, "filename"},
4005 {"quicktime", c_quicktime, "url"},
4007 // generators of primitives
4009 {"define", c_define, "name value=0"},
4010 {"point", c_point, "name x=0 y=0"},
4011 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
4012 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
4013 {"outline", c_outline, "name format=simple"},
4014 {"textshape", c_textshape, "name font size=100% text"},
4017 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
4018 {"gradientglow", c_gradientglow, "name gradient blur= blurx= blury= angle=0.0 distance=0.0 strength=1.0 @innershadow=0 @knockout=0 @composite=0 @ontop=0 passes=1"},
4019 {"dropshadow", c_dropshadow, "name color blur= blurx= blury= angle=0.0 distance=0.0 strength=1.0 @innershadow=0 @knockout=0 @composite=0 passes=1"},
4020 {"bevel", c_bevel, "name shadow highlight blur= blurx= blury= angle=0.0 distance=0.0 strength=1.0 @innershadow=0 @knockout=0 @composite=0 @ontop=0 passes=1"},
4022 // character generators
4023 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
4024 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
4025 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
4027 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
4028 {"text", c_text, "name text font size=100% color=white"},
4029 {"edittext", c_edittext, "name font= size=100% width height text="" color=white maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0 @border=0 @autosize=0 align="},
4030 {"morphshape", c_morphshape, "name start end"},
4031 {"button", c_button, "name"},
4032 {"show", c_show, "name 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= as="},
4033 {"on_press", c_on_press, "position=inside"},
4034 {"on_release", c_on_release, "position=anywhere"},
4035 {"on_move_in", c_on_move_in, "state=not_pressed"},
4036 {"on_move_out", c_on_move_out, "state=not_pressed"},
4037 {"on_key", c_on_key, "key=any"},
4040 {"play", c_play, "name loop=0 @nomultiple=0"},
4041 {"stop", c_stop, "name= "},
4042 {"nextframe", c_nextframe, "name"},
4043 {"previousframe", c_previousframe, "name"},
4045 // object placement tags
4046 {"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="},
4047 {"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="},
4048 {"move", c_move, "name x= y= interpolation=linear"},
4049 {"smove", c_smove, "name x= y= interpolation=linear"},
4050 {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
4051 {"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"},
4052 //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4053 {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4054 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4055 {"del", c_del, "name"},
4056 // virtual object placement
4057 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
4059 {"toggle", c_toggle, "name fixed_alignment="},
4061 // commands which start a block
4062 //startclip (see above)
4063 {"sprite", c_sprite, "name scalinggrid="},
4064 {"action", c_action, "filename="},
4065 {"initaction", c_initaction, "name filename="},
4071 static map_t parseArguments(char*command, char*pattern)
4087 string_set(&t1, "commandname");
4088 string_set(&t2, command);
4089 map_put(&result, t1, t2);
4091 if(!pattern || !*pattern)
4098 if(!strncmp("<i> ", x, 3)) {
4100 if(type == COMMAND || type == RAWDATA) {
4102 syntaxerror("character name expected");
4104 name[pos].str = "instance";
4106 value[pos].str = text;
4107 value[pos].len = strlen(text);
4111 if(type == ASSIGNMENT)
4114 name[pos].str = "character";
4116 value[pos].str = text;
4117 value[pos].len = strlen(text);
4125 isboolean[pos] = (x[0] =='@');
4138 name[pos].len = d-x;
4143 name[pos].len = e-x;
4144 value[pos].str = e+1;
4145 value[pos].len = d-e-1;
4153 /* for(t=0;t<len;t++) {
4154 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4155 isboolean[t]?"(boolean)":"");
4160 if(type == RAWDATA || type == COMMAND) {
4165 // first, search for boolean arguments
4166 for(pos=0;pos<len;pos++)
4168 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4170 if(type == ASSIGNMENT)
4172 value[pos].str = text;
4173 value[pos].len = strlen(text);
4174 /*printf("setting boolean parameter %s (to %s)\n",
4175 strdup_n(name[pos], namelen[pos]),
4176 strdup_n(value[pos], valuelen[pos]));*/
4181 // second, search for normal arguments
4183 for(pos=0;pos<len;pos++)
4185 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4186 (type != ASSIGNMENT && !set[pos])) {
4188 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4190 if(type == ASSIGNMENT)
4193 value[pos].str = text;
4194 value[pos].len = strlen(text);
4196 printf("setting parameter %s (to %s)\n",
4197 strdup_n(name[pos].str, name[pos].len),
4198 strdup_n(value[pos].str, value[pos].len));
4204 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4208 for(t=0;t<len;t++) {
4209 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4212 for(t=0;t<len;t++) {
4213 if(value[t].str && value[t].str[0] == '*') {
4214 //relative default- take value from some other parameter
4216 for(s=0;s<len;s++) {
4217 if(value[s].len == value[t].len-1 &&
4218 !strncmp(&value[t].str[1], value[s].str, value[s].len))
4219 value[t].str = value[s].str;
4222 if(value[t].str == 0) {
4224 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4228 /* ok, now construct the dictionary from the parameters */
4232 map_put(&result, name[t], value[t]);
4236 static void parseArgumentsForCommand(char*command)
4241 msg("<verbose> parse Command: %s (line %d)", command, line);
4243 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4244 if(!strcmp(arguments[t].command, command)) {
4246 /* ugly hack- will be removed soon (once documentation and .sc generating
4247 utilities have been changed) */
4248 if(!strcmp(command, "swf") && !stackpos) {
4249 warning("Please use .flash instead of .swf- this will be mandatory soon");
4254 args = parseArguments(command, arguments[t].arguments);
4260 syntaxerror("command %s not known", command);
4262 // catch missing .flash directives at the beginning of a file
4263 if(strcmp(command, "flash") && !stackpos)
4265 syntaxerror("No movie defined- use .flash first");
4269 printf(".%s\n", command);fflush(stdout);
4270 map_dump(&args, stdout, "\t");fflush(stdout);
4273 (*arguments[nr].func)(&args);
4275 /*if(!strcmp(command, "button") ||
4276 !strcmp(command, "action")) {
4279 if(type == COMMAND) {
4280 if(!strcmp(text, "end"))
4295 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4296 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4297 * No syntax checking is done */
4298 static void analyseArgumentsForCommand(char*command)
4304 U8* glyphs_to_include;
4305 msg("<verbose> analyse Command: %s (line %d)", command, line);
4307 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4309 if(!strcmp(arguments[t].command, command))
4311 args = parseArguments(command, arguments[t].arguments);
4317 printf(".%s\n", command);fflush(stdout);
4318 map_dump(&args, stdout, "\t");fflush(stdout);
4320 char* name = lu(&args, "name");
4321 if (!strcmp(command, "font"))
4323 if(dictionary_lookup(&fonts, name))
4324 syntaxerror("font %s defined twice", name);
4327 fontfile = lu(&args, "filename");
4328 font = swf_LoadFont(fontfile);
4330 warning("Couldn't open font file \"%s\"", fontfile);
4331 font = (SWFFONT*)malloc(sizeof(SWFFONT));
4332 memset(font, 0, sizeof(SWFFONT));
4336 swf_FontPrepareForEditText(font);
4337 glyphs_to_include = lu(&args, "glyphs");
4338 if (!strcmp(glyphs_to_include, "all"))
4340 swf_FontUseAll(font);
4341 font->use->glyphs_specified = 1;
4345 if (strcmp (glyphs_to_include, ""))
4347 swf_FontUseUTF8(font, glyphs_to_include);
4348 font->use->glyphs_specified = 1;
4351 swf_FontInitUsage(font);
4354 dictionary_put2(&fonts, name, font);
4358 SWFFONT* font = dictionary_lookup(&fonts, lu(&args, "font"));
4360 syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
4362 if (font->use && !font->use->glyphs_specified)
4364 if (!strcmp(command, "edittext"))
4366 swf_FontUseAll(font);
4367 font->use->glyphs_specified = 1;
4370 swf_FontUseUTF8(font, lu(&args, "text"));
4377 void skipParameters()
4381 while (type != COMMAND);
4385 void findFontUsage()
4387 char* fontRelated = "font;text;textshape;edittext;";
4388 while(!noMoreTokens())
4392 syntaxerror("command expected");
4393 if (strstr(fontRelated, text))
4394 analyseArgumentsForCommand(text);
4396 if(strcmp(text, "end"))
4405 dictionary_init(&fonts);
4406 cleanUp = &freeFontDictionary;
4410 int main (int argc,char ** argv)
4413 processargs(argc, argv);
4414 initLog(0,-1,0,0,-1,verbose);
4417 args_callback_usage(argv[0]);
4421 file = generateTokens(filename);
4423 fprintf(stderr, "parser returned error.\n");
4430 while(!noMoreTokens()) {
4433 syntaxerror("command expected");
4434 parseArgumentsForCommand(text);