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;
50 static struct options_t options[] = {
59 int args_callback_option(char*name,char*val)
61 if(!strcmp(name, "V")) {
62 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
65 else if(!strcmp(name, "o")) {
67 override_outputname = 1;
70 else if(!strcmp(name, "O")) {
74 else if(!strcmp(name, "C")) {
78 else if(!strcmp(name, "v")) {
83 printf("Unknown option: -%s\n", name);
88 int args_callback_longoption(char*name,char*val)
90 return args_long2shortoption(options, name, val);
92 void args_callback_usage(char *name)
95 printf("Usage: %s [-o file.swf] file.sc\n", name);
97 printf("-h , --help Print short help message and exit\n");
98 printf("-V , --version Print version info and exit\n");
99 printf("-C , --cgi Output to stdout (for use in CGI environments)\n");
100 printf("-v , --verbose Increase verbosity. \n");
101 printf("-o , --output <filename> Set output file to <filename>.\n");
104 int args_callback_command(char*name,char*val)
107 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
114 static struct token_t* file;
121 static void readToken()
123 type = file[pos].type;
125 syntaxerror("unexpected end of file");
127 text = file[pos].text;
128 textlen = strlen(text);
129 line = file[pos].line;
130 column = file[pos].column;
132 //printf("---> %d(%s) %s\n", type, type_names[type], text);
135 static void pushBack()
138 if(!pos) syntaxerror("internal error 3");
143 textlen = strlen(text);
146 column = file[p].column;
149 static int noMoreTokens()
151 if(file[pos].type == END)
156 // ------------------------------ swf routines ----------------------------
160 int type; //0=swf, 1=sprite, 2=clip, 3=button
166 /* for sprites (1): */
172 dictionary_t oldinstances;
177 static int stackpos = 0;
179 static dictionary_t characters;
180 static dictionary_t images;
181 static dictionary_t textures;
182 static dictionary_t outlines;
183 static dictionary_t gradients;
184 static dictionary_t filters;
185 static dictionary_t interpolations;
186 static char idmap[65536];
187 static TAG*tag = 0; //current tag
189 static int id; //current character id
190 static int currentframe; //current frame in current level
191 static SRECT currentrect; //current bounding box in current level
192 static U16 currentdepth;
193 static dictionary_t instances;
194 static dictionary_t fonts;
195 static dictionary_t sounds;
196 static dictionary_t fontUsage;
198 typedef struct _parameters {
200 float scalex, scaley;
206 U8 blendmode; //not interpolated
208 U16 set; // bits indicating wether a parameter was set in the c_placement function
211 typedef struct _character {
217 typedef struct _instance {
218 character_t*character;
220 parameters_t parameters;
221 TAG* lastTag; //last tag which set the object
222 U16 lastFrame; //frame lastTag is in
226 typedef struct _outline {
231 typedef struct _gradient {
237 typedef struct _filter {
241 typedef struct _texture {
245 char* interpolationFunctions[] = {"linear", \
246 "quadIn", "quadOut", "quadInOut", \
247 "cubicIn", "cubicOut", "cubicInOut", \
248 "quartIn", "quartOut", "quartInOut", \
249 "quintIn", "quintOut", "quintInOut", \
250 "circleIn", "circleOut", "circleInOut", \
251 "exponentialIn", "exponentialOut", "exponentialInOut", \
252 "sineIn", "sineOut", "sineInOut", \
253 "elasticIn", "elasticOut", "elasticInOut", \
254 "backIn", "backOut", "backInOut", \
255 "bounceIn", "bounceOut", "bounceInOut", \
256 "fastBounceIn", "fastBounceOut", "fastBounceInOut"};
258 typedef struct _fontData {
260 int notUsed, needsAll;
263 void addFontData(char *name)
266 newFont = (fontData *)malloc(sizeof(fontData));
267 memset(newFont, 0, sizeof(fontData));
268 newFont->notUsed = 1;
269 dictionary_put2(&fontUsage, name, newFont);
272 void freeFontData(fontData* font)
278 fontData *getFontData(char *name)
280 return (fontData *)dictionary_lookup(&fontUsage, name);
283 static void character_init(character_t*c)
285 memset(c, 0, sizeof(character_t));
288 static character_t* character_new()
291 c = (character_t*)malloc(sizeof(character_t));
296 static void instance_init(instance_t*i)
298 memset(i, 0, sizeof(instance_t));
299 i->history = history_new();
302 static void instance_free(instance_t* i)
304 history_free(i->history);
308 static instance_t* instance_new()
311 c = (instance_t*)malloc(sizeof(instance_t));
316 static void free_instance(void* i)
318 instance_free((instance_t*)i);
321 static void free_font(void* f)
323 swf_FontFree((SWFFONT*)f);
326 static void free_fontData(void* fd)
328 freeFontData((fontData*)fd);
331 static void gradient_free(GRADIENT* grad)
338 static void free_gradient(void* grad)
340 gradient_free((GRADIENT*) grad);
343 static void outline_free(outline_t* o)
345 free(o->shape->data);
350 static void free_outline(void* o)
352 outline_free((outline_t*)o);
355 static void freeDictionaries()
357 dictionary_free_all(&instances, free_instance);
358 dictionary_free_all(&characters, free);
359 dictionary_free_all(&images, free);
360 dictionary_free_all(&textures, free);
361 dictionary_free_all(&outlines, free_outline);
362 dictionary_free_all(&gradients, free_gradient);
363 dictionary_free_all(&filters, free);
364 dictionary_free_all(&fonts, free_font);
365 dictionary_free_all(&sounds, free);
366 dictionary_free_all(&fontUsage, free_fontData);
367 dictionary_free_all(&interpolations, free);
370 static void incrementid()
374 syntaxerror("Out of character ids.");
379 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
381 if(dictionary_lookup(&characters, name))
382 syntaxerror("character %s defined twice", name);
383 character_t* c = character_new();
385 c->definingTag = ctag;
388 dictionary_put2(&characters, name, c);
390 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
392 swf_SetString(tag, name);
393 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
396 swf_SetString(tag, name);
398 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
400 if(dictionary_lookup(&images, name))
401 syntaxerror("image %s defined twice", name);
403 character_t* c = character_new();
404 c->definingTag = ctag;
407 dictionary_put2(&images, name, c);
409 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
411 if(dictionary_lookup(&instances, name))
412 syntaxerror("object %s defined twice", name);
413 instance_t* i = instance_new();
416 //swf_GetMatrix(0, &i->matrix);
417 dictionary_put2(&instances, name, i);
421 static void parameters_clear(parameters_t*p)
424 p->scalex = 1.0; p->scaley = 1.0;
427 p->pivot.x = 0; p->pivot.y = 0;
432 swf_GetCXForm(0, &p->cxform, 1);
435 static void makeMatrix(MATRIX*m, parameters_t*p)
444 sx = p->scalex*cos(p->rotate/360*2*PI);
445 r1 = -p->scalex*sin(p->rotate/360*2*PI)+sx*p->shear;
446 r0 = p->scaley*sin(p->rotate/360*2*PI);
447 sy = p->scaley*cos(p->rotate/360*2*PI)+r0*p->shear;
449 m->sx = (int)(sx*65536+0.5);
450 m->r1 = (int)(r1*65536+0.5);
451 m->r0 = (int)(r0*65536+0.5);
452 m->sy = (int)(sy*65536+0.5);
456 h = swf_TurnPoint(p->pin, m);
461 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
466 r = swf_TurnRect(rect, &m);
467 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
468 currentrect.xmax == 0 && currentrect.ymax == 0)
471 swf_ExpandRect2(¤trect, &r);
475 void builtInInterpolations()
477 interpolation_t* new;
478 new = (interpolation_t*)malloc(sizeof(interpolation_t));
479 new->function = IF_LINEAR;
480 dictionary_put2(&interpolations, "linear", new);
482 new = (interpolation_t*)malloc(sizeof(interpolation_t));
483 new->function = IF_QUAD_IN;
484 dictionary_put2(&interpolations, "quadIn", new);
485 new = (interpolation_t*)malloc(sizeof(interpolation_t));
486 new->function = IF_QUAD_OUT;
487 dictionary_put2(&interpolations, "quadOut", new);
488 new = (interpolation_t*)malloc(sizeof(interpolation_t));
489 new->function = IF_QUAD_IN_OUT;
490 dictionary_put2(&interpolations, "quadInOut", new);
492 new = (interpolation_t*)malloc(sizeof(interpolation_t));
493 new->function = IF_CUBIC_IN;
494 dictionary_put2(&interpolations, "cubicIn", new);
495 new = (interpolation_t*)malloc(sizeof(interpolation_t));
496 new->function = IF_CUBIC_OUT;
497 dictionary_put2(&interpolations, "cubicOut", new);
498 new = (interpolation_t*)malloc(sizeof(interpolation_t));
499 new->function = IF_CUBIC_IN_OUT;
500 dictionary_put2(&interpolations, "cubicInOut", new);
502 new = (interpolation_t*)malloc(sizeof(interpolation_t));
503 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;
507 dictionary_put2(&interpolations, "quartOut", new);
508 new = (interpolation_t*)malloc(sizeof(interpolation_t));
509 new->function = IF_QUART_IN_OUT;
510 dictionary_put2(&interpolations, "quartInOut", new);
512 new = (interpolation_t*)malloc(sizeof(interpolation_t));
513 new->function = IF_QUINT_IN;
514 dictionary_put2(&interpolations, "quintIn", new);
515 new = (interpolation_t*)malloc(sizeof(interpolation_t));
516 new->function = IF_QUINT_OUT;
517 dictionary_put2(&interpolations, "quintOut", new);
518 new = (interpolation_t*)malloc(sizeof(interpolation_t));
519 new->function = IF_QUINT_IN_OUT;
520 dictionary_put2(&interpolations, "quintInOut", new);
522 new = (interpolation_t*)malloc(sizeof(interpolation_t));
523 new->function = IF_CIRCLE_IN;
524 dictionary_put2(&interpolations, "circleIn", new);
525 new = (interpolation_t*)malloc(sizeof(interpolation_t));
526 new->function = IF_CIRCLE_OUT;
527 dictionary_put2(&interpolations, "circleOut", new);
528 new = (interpolation_t*)malloc(sizeof(interpolation_t));
529 new->function = IF_CIRCLE_IN_OUT;
530 dictionary_put2(&interpolations, "circleInOut", new);
532 new = (interpolation_t*)malloc(sizeof(interpolation_t));
533 new->function = IF_EXPONENTIAL_IN;
534 dictionary_put2(&interpolations, "exponentialIn", new);
535 new = (interpolation_t*)malloc(sizeof(interpolation_t));
536 new->function = IF_EXPONENTIAL_OUT;
537 dictionary_put2(&interpolations, "exponentialOut", new);
538 new = (interpolation_t*)malloc(sizeof(interpolation_t));
539 new->function = IF_EXPONENTIAL_IN_OUT;
540 dictionary_put2(&interpolations, "exponentialInOut", new);
542 new = (interpolation_t*)malloc(sizeof(interpolation_t));
543 new->function = IF_SINE_IN;
544 dictionary_put2(&interpolations, "sineIn", new);
545 new = (interpolation_t*)malloc(sizeof(interpolation_t));
546 new->function = IF_SINE_OUT;
547 dictionary_put2(&interpolations, "sineOut", new);
548 new = (interpolation_t*)malloc(sizeof(interpolation_t));
549 new->function = IF_SINE_IN_OUT;
550 dictionary_put2(&interpolations, "sineInOut", new);
553 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
556 syntaxerror(".swf blocks can't be nested");
557 if(stackpos==sizeof(stack)/sizeof(stack[0]))
558 syntaxerror("too many levels of recursion");
560 SWF*swf = (SWF*)malloc(sizeof(SWF));
562 memset(swf, 0, sizeof(swf));
563 swf->fileVersion = version;
565 swf->frameRate = fps;
566 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
567 swf->compressed = compress;
568 swf_SetRGB(tag,&background);
570 dictionary_init(&characters);
571 dictionary_init(&images);
572 dictionary_init(&textures);
573 dictionary_init(&outlines);
574 dictionary_init(&gradients);
575 dictionary_init(&filters);
576 dictionary_init(&instances);
577 dictionary_init(&fonts);
578 dictionary_init(&sounds);
579 dictionary_init(&interpolations);
580 builtInInterpolations();
581 cleanUp = &freeDictionaries;
583 memset(&stack[stackpos], 0, sizeof(stack[0]));
584 stack[stackpos].type = 0;
585 stack[stackpos].filename = strdup(name);
586 stack[stackpos].swf = swf;
587 stack[stackpos].oldframe = -1;
592 memset(¤trect, 0, sizeof(currentrect));
595 memset(idmap, 0, sizeof(idmap));
599 void s_sprite(char*name)
601 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
602 swf_SetU16(tag, id); //id
603 swf_SetU16(tag, 0); //frames
605 memset(&stack[stackpos], 0, sizeof(stack[0]));
606 stack[stackpos].type = 1;
607 stack[stackpos].oldframe = currentframe;
608 stack[stackpos].olddepth = currentdepth;
609 stack[stackpos].oldrect = currentrect;
610 stack[stackpos].oldinstances = instances;
611 stack[stackpos].tag = tag;
612 stack[stackpos].id = id;
613 stack[stackpos].name = strdup(name);
615 /* FIXME: those four fields should be bundled together */
616 dictionary_init(&instances);
619 memset(¤trect, 0, sizeof(currentrect));
625 typedef struct _buttonrecord
633 typedef struct _button
637 buttonrecord_t records[4];
640 static button_t mybutton;
642 void s_button(char*name)
644 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
645 swf_SetU16(tag, id); //id
646 swf_ButtonSetFlags(tag, 0); //menu=no
648 memset(&mybutton, 0, sizeof(mybutton));
650 memset(&stack[stackpos], 0, sizeof(stack[0]));
651 stack[stackpos].type = 3;
652 stack[stackpos].tag = tag;
653 stack[stackpos].id = id;
654 stack[stackpos].name = strdup(name);
655 stack[stackpos].oldrect = currentrect;
656 memset(¤trect, 0, sizeof(currentrect));
661 void s_buttonput(char*character, char*as, parameters_t p)
663 character_t* c = dictionary_lookup(&characters, character);
668 if(!stackpos || (stack[stackpos-1].type != 3)) {
669 syntaxerror(".show may only appear in .button");
672 syntaxerror("character %s not known (in .shape %s)", character, character);
674 if(mybutton.endofshapes) {
675 syntaxerror("a .do may not precede a .show", character, character);
678 m = s_instancepos(c->size, &p);
686 if(*s==',' || *s==0) {
687 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
688 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
689 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
690 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
691 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
692 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
699 static void setbuttonrecords(TAG*tag)
701 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
702 if(!mybutton.endofshapes) {
705 if(!mybutton.records[3].set) {
706 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
710 if(mybutton.records[t].set) {
711 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
714 swf_SetU8(tag,0); // end of button records
715 mybutton.endofshapes = 1;
719 void s_buttonaction(int flags, char*action)
725 setbuttonrecords(stack[stackpos-1].tag);
727 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
729 syntaxerror("Couldn't compile ActionScript");
732 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
733 swf_ActionSet(stack[stackpos-1].tag, a);
734 mybutton.nr_actions++;
739 static void setactionend(TAG*tag)
741 if(!mybutton.nr_actions) {
742 /* no actions means we didn't have an actionoffset,
743 which means we can't signal the end of the
744 buttonaction records, so, *sigh*, we have
745 to insert a dummy record */
746 swf_SetU16(tag, 0); //offset
747 swf_SetU16(tag, 0); //condition
748 swf_SetU8(tag, 0); //action
752 static void s_endButton()
755 setbuttonrecords(stack[stackpos-1].tag);
756 setactionend(stack[stackpos-1].tag);
759 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
763 tag = stack[stackpos].tag;
764 currentrect = stack[stackpos].oldrect;
766 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
767 free(stack[stackpos].name);
770 TAG* removeFromTo(TAG*from, TAG*to)
772 TAG*save = from->prev;
774 TAG*next = from->next;
782 static void readParameters(history_t* history, parameters_t* p, int frame)
784 p->x = history_value(history, frame, "x");
785 p->y = history_value(history, frame, "y");
786 p->scalex = history_value(history, frame, "scalex");
787 p->scaley = history_value(history, frame, "scaley");
788 p->cxform.r0 = history_value(history, frame, "cxform.r0");
789 p->cxform.g0 = history_value(history, frame, "cxform.g0");
790 p->cxform.b0 = history_value(history, frame, "cxform.b0");
791 p->cxform.a0 = history_value(history, frame, "cxform.a0");
792 p->cxform.r1 = history_value(history, frame, "cxform.r1");
793 p->cxform.g1 = history_value(history, frame, "cxform.g1");
794 p->cxform.b1 = history_value(history, frame, "cxform.b1");
795 p->cxform.a1 = history_value(history, frame, "cxform.a1");
796 p->rotate = history_value(history, frame, "rotate");
797 p->shear = history_value(history, frame, "shear");
798 p->pivot.x = history_value(history, frame, "pivot.x");
799 p->pivot.y = history_value(history, frame, "pivot.y");
800 p->pin.x = history_value(history, frame, "pin.x");
801 p->pin.y = history_value(history, frame, "pin.y");
802 p->blendmode = history_value(history, frame, "blendmode");
803 p->filter = history_valueFilter(history, frame);
806 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move)
810 swf_GetPlaceObject(NULL, &po);
814 po.cxform = p->cxform;
820 po.blendmode = p->blendmode;
824 flist.filter[0] = p->filter;
827 swf_SetPlaceObject(tag, &po);
830 static void writeInstance(instance_t* i)
834 int frame = i->history->firstFrame;
835 TAG* tag = i->history->firstTag;
836 while (frame < currentframe)
839 readParameters(i->history, &p, frame);
840 while (tag->id != ST_SHOWFRAME)
842 m = s_instancepos(i->character->size, &p);
844 if(p.blendmode || p.filter)
845 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
847 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
848 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
854 void dumpSWF(SWF*swf)
856 TAG* tag = swf->firstTag;
857 printf("vvvvvvvvvvvvvvvvvvvvv\n");
859 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
862 printf("^^^^^^^^^^^^^^^^^^^^^\n");
865 static void s_endSprite()
867 SRECT r = currentrect;
869 if(stack[stackpos].cut)
870 tag = removeFromTo(stack[stackpos].cut, tag);
874 stringarray_t* index =dictionary_index(&instances);
876 char* name = stringarray_at(index, num);
879 i = dictionary_lookup(&instances, name);
882 name = stringarray_at(index, num);
885 tag = swf_InsertTag(tag, ST_SHOWFRAME);
886 tag = swf_InsertTag(tag, ST_END);
888 tag = stack[stackpos].tag;
891 syntaxerror("internal error(7)");
892 /* TODO: before clearing, prepend "<spritename>." to names and
893 copy into old instances dict */
894 dictionary_free_all(&instances, free_instance);
896 currentframe = stack[stackpos].oldframe;
897 currentrect = stack[stackpos].oldrect;
898 currentdepth = stack[stackpos].olddepth;
899 instances = stack[stackpos].oldinstances;
901 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
902 free(stack[stackpos].name);
905 static void s_endSWF()
912 stringarray_t* index =dictionary_index(&instances);
914 char* name = stringarray_at(index, num);
917 i = dictionary_lookup(&instances, name);
920 name = stringarray_at(index, num);
923 if(stack[stackpos].cut)
924 tag = removeFromTo(stack[stackpos].cut, tag);
928 swf = stack[stackpos].swf;
929 filename = stack[stackpos].filename;
931 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
932 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
933 tag = swf_InsertTag(tag, ST_SHOWFRAME);
935 tag = swf_InsertTag(tag, ST_END);
937 swf_OptimizeTagOrder(swf);
943 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
944 swf->movieSize = currentrect; /* "autocrop" */
947 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
948 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
949 swf->movieSize.ymax += 20;
950 warning("Empty bounding box for movie");
953 if(do_cgi || !strcmp(filename, "-"))
956 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
958 syntaxerror("couldn't create output file %s", filename);
961 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
962 else if(swf->compressed)
963 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
965 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
979 if(stack[stackpos-1].type == 0)
980 syntaxerror("End of file encountered in .flash block");
981 if(stack[stackpos-1].type == 1)
982 syntaxerror("End of file encountered in .sprite block");
983 if(stack[stackpos-1].type == 2)
984 syntaxerror("End of file encountered in .clip block");
990 return currentframe+1;
993 void s_frame(int nr, int cut, char*name, char anchor)
999 syntaxerror("Illegal frame number");
1000 nr--; // internally, frame 1 is frame 0
1002 for(t=currentframe;t<nr;t++) {
1003 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1004 if(t==nr-1 && name && *name) {
1005 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1006 swf_SetString(tag, name);
1008 swf_SetU8(tag, 1); //make this an anchor
1011 if(nr == 0 && currentframe == 0 && name && *name) {
1012 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1013 swf_SetString(tag, name);
1015 swf_SetU8(tag, 1); //make this an anchor
1020 syntaxerror("Can't cut, frame empty");
1022 stack[stackpos].cut = tag;
1028 int parseColor2(char*str, RGBA*color);
1030 int addFillStyle(SHAPE*s, SRECT*r, char*name)
1034 gradient_t*gradient;
1036 if(name[0] == '#') {
1037 parseColor2(name, &color);
1038 return swf_ShapeAddSolidFillStyle(s, &color);
1039 } else if ((texture = dictionary_lookup(&textures, name))) {
1040 return swf_ShapeAddFillStyle2(s, &texture->fs);
1041 } else if((image = dictionary_lookup(&images, name))) {
1043 swf_GetMatrix(0, &m);
1044 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1045 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1048 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1049 } else if ((gradient = dictionary_lookup(&gradients, name))) {
1053 swf_GetMatrix(0, &rot);
1054 ccos = cos(-gradient->rotate*2*PI/360);
1055 csin = sin(-gradient->rotate*2*PI/360);
1056 rot.sx = ccos*65536;
1057 rot.r1 = -csin*65536;
1058 rot.r0 = csin*65536;
1059 rot.sy = ccos*65536;
1060 r2 = swf_TurnRect(*r, &rot);
1061 swf_GetMatrix(0, &m);
1062 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1063 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1064 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1065 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1066 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1067 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1068 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1069 } else if (parseColor2(name, &color)) {
1070 return swf_ShapeAddSolidFillStyle(s, &color);
1072 syntaxerror("not a color/fillstyle: %s", name);
1077 RGBA black={r:0,g:0,b:0,a:0};
1078 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
1087 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1090 linewidth = linewidth>=20?linewidth-20:0;
1091 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1094 fs1 = addFillStyle(s, &r2, texture);
1097 r.xmin = r2.xmin-linewidth/2;
1098 r.ymin = r2.ymin-linewidth/2;
1099 r.xmax = r2.xmax+linewidth/2;
1100 r.ymax = r2.ymax+linewidth/2;
1101 swf_SetRect(tag,&r);
1102 swf_SetShapeHeader(tag,s);
1103 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1104 swf_ShapeSetLine(tag,s,width,0);
1105 swf_ShapeSetLine(tag,s,0,height);
1106 swf_ShapeSetLine(tag,s,-width,0);
1107 swf_ShapeSetLine(tag,s,0,-height);
1108 swf_ShapeSetEnd(tag);
1111 s_addcharacter(name, id, tag, r);
1115 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
1121 outline = dictionary_lookup(&outlines, outlinename);
1123 syntaxerror("outline %s not defined", outlinename);
1127 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1130 linewidth = linewidth>=20?linewidth-20:0;
1131 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1134 fs1 = addFillStyle(s, &r2, texture);
1137 rect.xmin = r2.xmin-linewidth/2;
1138 rect.ymin = r2.ymin-linewidth/2;
1139 rect.xmax = r2.xmax+linewidth/2;
1140 rect.ymax = r2.ymax+linewidth/2;
1142 swf_SetRect(tag,&rect);
1143 swf_SetShapeStyles(tag, s);
1144 swf_ShapeCountBits(s,0,0);
1145 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1146 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1147 swf_SetShapeBits(tag, s);
1148 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1151 s_addcharacter(name, id, tag, rect);
1155 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
1160 r2.xmin = r2.ymin = 0;
1164 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1167 linewidth = linewidth>=20?linewidth-20:0;
1168 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1171 fs1 = addFillStyle(s, &r2, texture);
1173 rect.xmin = r2.xmin-linewidth/2;
1174 rect.ymin = r2.ymin-linewidth/2;
1175 rect.xmax = r2.xmax+linewidth/2;
1176 rect.ymax = r2.ymax+linewidth/2;
1178 swf_SetRect(tag,&rect);
1179 swf_SetShapeHeader(tag,s);
1180 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1181 swf_ShapeSetCircle(tag, s, r,r,r,r);
1182 swf_ShapeSetEnd(tag);
1185 s_addcharacter(name, id, tag, rect);
1189 void s_textshape(char*name, char*fontname, float size, char*_text)
1192 U8*text = (U8*)_text;
1196 font = dictionary_lookup(&fonts, fontname);
1198 syntaxerror("font \"%s\" not known!", fontname);
1200 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1201 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1202 s_box(name, 0, 0, black, 20, 0);
1205 g = font->ascii2glyph[text[0]];
1207 outline = malloc(sizeof(outline_t));
1208 memset(outline, 0, sizeof(outline_t));
1209 outline->shape = font->glyph[g].shape;
1210 outline->bbox = font->layout->bounds[g];
1214 swf_Shape11DrawerInit(&draw, 0);
1215 swf_DrawText(&draw, font, (int)(size*100), _text);
1217 outline->shape = swf_ShapeDrawerToShape(&draw);
1218 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1219 draw.dealloc(&draw);
1222 if(dictionary_lookup(&outlines, name))
1223 syntaxerror("outline %s defined twice", name);
1224 dictionary_put2(&outlines, name, outline);
1227 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
1232 font = dictionary_lookup(&fonts, fontname);
1234 syntaxerror("font \"%s\" not known!", fontname);
1236 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1237 swf_SetU16(tag, id);
1238 if(!font->numchars) {
1239 s_box(name, 0, 0, black, 20, 0);
1242 r = swf_SetDefineText(tag, font, &color, text, size);
1244 if(stack[0].swf->fileVersion >= 8) {
1245 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1246 swf_SetU16(tag, id);
1247 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1248 swf_SetU32(tag, 0);//thickness
1249 swf_SetU32(tag, 0);//sharpness
1250 swf_SetU8(tag, 0);//reserved
1253 s_addcharacter(name, id, tag, r);
1257 void s_quicktime(char*name, char*url)
1262 memset(&r, 0, sizeof(r));
1264 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1265 swf_SetU16(tag, id);
1266 swf_SetString(tag, url);
1268 s_addcharacter(name, id, tag, r);
1272 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)
1275 EditTextLayout layout;
1278 if(fontname && *fontname) {
1279 flags |= ET_USEOUTLINES;
1280 font = dictionary_lookup(&fonts, fontname);
1282 syntaxerror("font \"%s\" not known!", fontname);
1284 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1285 swf_SetU16(tag, id);
1286 layout.align = align;
1287 layout.leftmargin = 0;
1288 layout.rightmargin = 0;
1296 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
1298 s_addcharacter(name, id, tag, r);
1302 /* type: either "jpeg" or "png"
1304 void s_image(char*name, char*type, char*filename, int quality)
1306 /* an image is actually two folded: 1st bitmap, 2nd character.
1307 Both of them can be used separately */
1309 /* step 1: the bitmap */
1313 if(!strcmp(type,"jpeg")) {
1314 #ifndef HAVE_JPEGLIB
1315 warning("no jpeg support compiled in");
1316 s_box(name, 0, 0, black, 20, 0);
1319 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1320 swf_SetU16(tag, imageID);
1322 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1323 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1326 swf_GetJPEGSize(filename, &width, &height);
1333 s_addimage(name, id, tag, r);
1336 } else if(!strcmp(type,"png")) {
1338 swf_SetU16(tag, imageID);
1340 getPNG(filename, &width, &height, (unsigned char**)&data);
1343 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1346 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1347 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1348 swf_SetU16(tag, imageID);
1349 swf_SetLosslessImage(tag, data, width, height);
1356 s_addimage(name, id, tag, r);
1359 warning("image type \"%s\" not supported yet!", type);
1360 s_box(name, 0, 0, black, 20, 0);
1364 /* step 2: the character */
1365 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1366 swf_SetU16(tag, id);
1367 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1369 s_addcharacter(name, id, tag, r);
1373 void s_getBitmapSize(char*name, int*width, int*height)
1375 character_t* image = dictionary_lookup(&images, name);
1376 gradient_t* gradient = dictionary_lookup(&gradients,name);
1378 *width = image->size.xmax;
1379 *height = image->size.ymax;
1383 /* internal SWF gradient size */
1384 if(gradient->radial) {
1393 syntaxerror("No such bitmap/gradient: %s", name);
1396 void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1398 if(dictionary_lookup(&textures, name))
1399 syntaxerror("texture %s defined twice", name);
1400 gradient_t* gradient = dictionary_lookup(&gradients, object);
1401 character_t* bitmap = dictionary_lookup(&images, object);
1402 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1404 FILLSTYLE*fs = &texture->fs;
1406 memset(&p, 0, sizeof(parameters_t));
1409 fs->type = FILL_TILED;
1410 fs->id_bitmap = bitmap->id;
1411 } else if(gradient) {
1412 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1413 fs->gradient = gradient->gradient;
1415 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1416 makeMatrix(&fs->m, &p);
1417 if(gradient && !gradient->radial) {
1424 p2 = swf_TurnPoint(p1, &m);
1433 dictionary_put2(&textures, name, texture);
1436 void s_font(char*name, char*filename)
1438 if(dictionary_lookup(&fonts, name))
1439 syntaxerror("font %s defined twice", name);
1442 font = swf_LoadFont(filename);
1445 warning("Couldn't open font file \"%s\"", filename);
1446 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1447 memset(font, 0, sizeof(SWFFONT));
1448 dictionary_put2(&fonts, name, font);
1454 /* fix the layout. Only needed for old fonts */
1456 for(t=0;t<font->numchars;t++) {
1457 font->glyph[t].advance = 0;
1460 swf_FontCreateLayout(font);
1462 /* just in case this thing is used in .edittext later on */
1463 swf_FontPrepareForEditText(font);
1466 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1467 swf_FontSetDefine2(tag, font);
1468 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1470 swf_SetU16(tag, id);
1471 swf_SetString(tag, name);
1474 dictionary_put2(&fonts, name, font);
1479 typedef struct _sound_t
1485 void s_sound(char*name, char*filename)
1487 struct WAV wav, wav2;
1491 unsigned numsamples = 1;
1492 unsigned blocksize = 1152;
1495 if(dictionary_lookup(&sounds, name))
1496 syntaxerror("sound %s defined twice", name);
1498 if(wav_read(&wav, filename))
1501 wav_convert2mono(&wav, &wav2, 44100);
1502 samples = (U16*)wav2.data;
1503 numsamples = wav2.size/2;
1505 #ifdef WORDS_BIGENDIAN
1507 for(t=0;t<numsamples;t++)
1508 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1512 if(mp3_read(&mp3, filename))
1514 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1520 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1525 if(numsamples%blocksize != 0)
1527 // apply padding, so that block is a multiple of blocksize
1528 int numblocks = (numsamples+blocksize-1)/blocksize;
1531 numsamples2 = numblocks * blocksize;
1532 samples2 = malloc(sizeof(U16)*numsamples2);
1533 memcpy(samples2, samples, numsamples*sizeof(U16));
1534 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1535 numsamples = numsamples2;
1540 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1541 swf_SetU16(tag, id); //id
1544 swf_SetSoundDefineMP3(
1545 tag, mp3.data, mp3.size,
1552 swf_SetSoundDefine(tag, samples, numsamples);
1554 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1555 swf_SetU16(tag, id);
1556 swf_SetString(tag, name);
1557 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1559 swf_SetU16(tag, id);
1560 swf_SetString(tag, name);
1562 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1566 dictionary_put2(&sounds, name, sound);
1574 static char* gradient_getToken(const char**p)
1578 while(**p && strchr(" \t\n\r", **p)) {
1582 while(**p && !strchr(" \t\n\r", **p)) {
1585 result = malloc((*p)-start+1);
1586 memcpy(result,start,(*p)-start+1);
1587 result[(*p)-start] = 0;
1591 float parsePercent(char*str);
1592 RGBA parseColor(char*str);
1594 GRADIENT parseGradient(const char*str)
1598 const char* p = str;
1599 memset(&gradient, 0, sizeof(GRADIENT));
1600 gradient.ratios = rfx_calloc(16*sizeof(U8));
1601 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1605 char*posstr,*colorstr;
1608 posstr = gradient_getToken(&p);
1614 pos = (int)(parsePercent(posstr)*255.0);
1619 rfx_free(gradient.ratios);
1620 rfx_free(gradient.rgba);
1622 syntaxerror("Error in shape data: Color expected after %s", posstr);
1624 colorstr = gradient_getToken(&p);
1625 color = parseColor(colorstr);
1626 if(gradient.num == 16)
1628 warning("gradient record too big- max size is 16, rest ignored");
1631 gradient.ratios[gradient.num] = pos;
1632 gradient.rgba[gradient.num] = color;
1641 void s_gradient(char*name, const char*text, int radial, int rotate)
1643 gradient_t* gradient;
1644 gradient = malloc(sizeof(gradient_t));
1645 memset(gradient, 0, sizeof(gradient_t));
1646 gradient->gradient = parseGradient(text);
1647 gradient->radial = radial;
1648 gradient->rotate = rotate;
1650 dictionary_put2(&gradients, name, gradient);
1653 void s_gradientglow(char*name, char*gradient, float blurx, float blury,
1654 float angle, float distance, float strength, char innershadow,
1655 char knockout, char composite, char ontop, int passes)
1657 if(dictionary_lookup(&filters, name))
1658 syntaxerror("filter %s defined twice", name);
1660 gradient_t* g = dictionary_lookup(&gradients, gradient);
1665 syntaxerror("unknown gradient %s", gradient);
1666 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1667 filter->type = FILTERTYPE_GRADIENTGLOW;
1668 filter->gradient = &g->gradient;
1669 filter->blurx = blurx;
1670 filter->blury = blury;
1671 filter->strength = strength;
1672 filter->angle = angle;
1673 filter->distance = distance;
1674 filter->innershadow = innershadow;
1675 filter->knockout = knockout;
1676 filter->composite = composite;
1677 filter->ontop = ontop;
1678 filter->passes = passes;
1680 dictionary_put2(&filters, name, filter);
1683 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)
1685 if(dictionary_lookup(&filters, name))
1686 syntaxerror("filter %s defined twice", name);
1689 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1690 filter->type = FILTERTYPE_DROPSHADOW;
1691 filter->color= color;
1692 filter->blurx = blurx;
1693 filter->blury = blury;
1694 filter->strength = strength;
1695 filter->angle = angle;
1696 filter->distance = distance;
1697 filter->innershadow = innershadow;
1698 filter->knockout = knockout;
1699 filter->composite = composite;
1700 filter->passes = passes;
1702 dictionary_put2(&filters, name, filter);
1705 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)
1707 if(dictionary_lookup(&filters, name))
1708 syntaxerror("filter %s defined twice", name);
1711 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1712 filter->type = FILTERTYPE_BEVEL;
1713 filter->shadow = shadow;
1714 filter->highlight = highlight;
1715 filter->blurx = blurx;
1716 filter->blury = blury;
1717 filter->strength = strength;
1718 filter->angle = angle;
1719 filter->distance = distance;
1720 filter->innershadow = innershadow;
1721 filter->knockout = knockout;
1722 filter->composite = composite;
1723 filter->ontop = ontop;
1724 filter->passes = passes;
1726 dictionary_put2(&filters, name, filter);
1729 void s_blur(char*name, double blurx, double blury, int passes)
1731 if(dictionary_lookup(&filters, name))
1732 syntaxerror("filter %s defined twice", name);
1734 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1735 filter->type = FILTERTYPE_BLUR;
1736 filter->blurx = blurx;
1737 filter->blury = blury;
1738 filter->passes = passes;
1740 dictionary_put2(&filters, name, filter);
1743 void s_action(const char*text)
1746 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1750 syntaxerror("Couldn't compile ActionScript");
1753 tag = swf_InsertTag(tag, ST_DOACTION);
1755 swf_ActionSet(tag, a);
1760 void s_initaction(const char*character, const char*text)
1764 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1768 syntaxerror("Couldn't compile ActionScript");
1771 c = (character_t*)dictionary_lookup(&characters, character);
1773 tag = swf_InsertTag(tag, ST_DOINITACTION);
1774 swf_SetU16(tag, c->id);
1775 swf_ActionSet(tag, a);
1780 int s_swf3action(char*name, char*action)
1783 instance_t* object = 0;
1785 object = (instance_t*)dictionary_lookup(&instances, name);
1786 if(!object && name && *name) {
1787 /* we have a name, but couldn't find it. Abort. */
1790 a = action_SetTarget(0, name);
1791 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1792 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1793 else if(!strcmp(action, "stop")) a = action_Stop(a);
1794 else if(!strcmp(action, "play")) a = action_Play(a);
1795 a = action_SetTarget(a, "");
1798 tag = swf_InsertTag(tag, ST_DOACTION);
1799 swf_ActionSet(tag, a);
1804 void s_outline(char*name, char*format, char*source)
1806 if(dictionary_lookup(&outlines, name))
1807 syntaxerror("outline %s defined twice", name);
1816 //swf_Shape10DrawerInit(&draw, 0);
1817 swf_Shape11DrawerInit(&draw, 0);
1819 draw_string(&draw, source);
1821 shape = swf_ShapeDrawerToShape(&draw);
1822 bounds = swf_ShapeDrawerGetBBox(&draw);
1823 draw.dealloc(&draw);
1825 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1826 outline->shape = shape;
1827 outline->bbox = bounds;
1829 dictionary_put2(&outlines, name, outline);
1832 int s_playsound(char*name, int loops, int nomultiple, int stop)
1838 sound = dictionary_lookup(&sounds, name);
1842 tag = swf_InsertTag(tag, ST_STARTSOUND);
1843 swf_SetU16(tag, sound->id); //id
1844 memset(&info, 0, sizeof(info));
1847 info.nomultiple = nomultiple;
1848 swf_SetSoundInfo(tag, &info);
1852 void s_includeswf(char*name, char*filename)
1860 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1861 f = open(filename,O_RDONLY|O_BINARY);
1863 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1864 s_box(name, 0, 0, black, 20, 0);
1867 if (swf_ReadSWF(f,&swf)<0) {
1868 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1869 s_box(name, 0, 0, black, 20, 0);
1874 /* FIXME: The following sets the bounding Box for the character.
1875 It is wrong for two reasons:
1876 a) It may be too small (in case objects in the movie clip at the borders)
1877 b) it may be too big (because the poor movie never got autocropped)
1881 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1882 swf_SetU16(tag, id);
1883 swf_SetU16(tag, swf.frameCount);
1885 swf_Relocate(&swf, idmap);
1887 ftag = swf.firstTag;
1891 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1892 if(cutout[t] == ftag->id) {
1896 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1898 if(ftag->id == ST_END)
1903 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
1904 /* We simply dump all tags right after the sprite
1905 header, relying on the fact that swf_OptimizeTagOrder() will
1906 sort things out for us later.
1907 We also rely on the fact that the imported SWF is well-formed.
1909 tag = swf_InsertTag(tag, ftag->id);
1910 swf_SetBlock(tag, ftag->data, ftag->len);
1916 syntaxerror("Included file %s contains errors", filename);
1917 tag = swf_InsertTag(tag, ST_END);
1921 s_addcharacter(name, id, tag, r);
1924 SRECT s_getCharBBox(char*name)
1926 character_t* c = dictionary_lookup(&characters, name);
1927 if(!c) syntaxerror("character '%s' unknown(2)", name);
1930 SRECT s_getInstanceBBox(char*name)
1932 instance_t * i = dictionary_lookup(&instances, name);
1934 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1936 if(!c) syntaxerror("internal error(5)");
1939 parameters_t s_getParameters(char*name)
1941 instance_t * i = dictionary_lookup(&instances, name);
1942 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1943 return i->parameters;
1945 void s_startclip(char*instance, char*character, parameters_t p)
1947 character_t* c = dictionary_lookup(&characters, character);
1951 syntaxerror("character %s not known", character);
1953 i = s_addinstance(instance, c, currentdepth);
1955 m = s_instancepos(i->character->size, &p);
1957 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1958 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1959 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1961 i->lastFrame= currentframe;
1963 stack[stackpos].tag = tag;
1964 stack[stackpos].type = 2;
1973 swf_SetTagPos(stack[stackpos].tag, 0);
1974 swf_GetPlaceObject(stack[stackpos].tag, &p);
1975 p.clipdepth = currentdepth;
1977 swf_ClearTag(stack[stackpos].tag);
1978 swf_SetPlaceObject(stack[stackpos].tag, &p);
1982 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
1984 history_begin(i->history, "x", currentframe, tag, p->x);
1985 history_begin(i->history, "y", currentframe, tag, p->y);
1986 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
1987 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
1988 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
1989 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
1990 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
1991 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
1992 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
1993 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
1994 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
1995 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
1996 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
1997 history_begin(i->history, "shear", currentframe, tag, p->shear);
1998 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
1999 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2000 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2001 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2002 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2003 history_beginFilter(i->history, currentframe, tag, p->filter);
2006 void s_put(char*instance, char*character, parameters_t p)
2008 character_t* c = dictionary_lookup(&characters, character);
2012 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2014 i = s_addinstance(instance, c, currentdepth);
2016 m = s_instancepos(i->character->size, &p);
2018 if(p.blendmode || p.filter)
2020 if(stack[0].swf->fileVersion < 8)
2023 warning("blendmodes only supported for flash version>=8");
2025 warning("filters only supported for flash version>=8");
2027 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2030 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2031 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2032 setStartparameters(i, &p, tag);
2034 i->lastFrame = currentframe;
2038 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2041 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2043 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2044 if (p.set & SF_SCALEX)
2045 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2046 if (p.set & SF_SCALEY)
2047 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2048 if (p.set & SF_CX_R)
2050 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2051 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2053 if (p.set & SF_CX_G)
2055 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2056 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2058 if (p.set & SF_CX_B)
2060 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2061 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2063 if (p.set & SF_CX_A)
2065 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2066 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2068 if (p.set & SF_ROTATE)
2069 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2070 if (p.set & SF_SHEAR)
2071 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2072 if (p.set & SF_PIVOT)
2074 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2075 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2079 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2080 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2082 if (p.set & SF_BLEND)
2083 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2084 if (p.set & SF_FILTER)
2085 history_rememberFilter(history, currentframe, changeFunction, p.filter, inter);
2088 void s_jump(char* instance, parameters_t p)
2090 instance_t* i = dictionary_lookup(&instances, instance);
2092 syntaxerror("instance %s not known", instance);
2093 recordChanges(i->history, p, CF_JUMP, 0);
2096 void s_change(char*instance, parameters_t p2, interpolation_t* inter)
2098 instance_t* i = dictionary_lookup(&instances, instance);
2100 syntaxerror("instance %s not known", instance);
2101 recordChanges(i->history, p2, CF_CHANGE, inter);
2104 void s_delinstance(char*instance)
2106 instance_t* i = dictionary_lookup(&instances, instance);
2108 syntaxerror("instance %s not known", instance);
2109 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2110 swf_SetU16(tag, i->depth);
2111 dictionary_del(&instances, instance);
2114 void s_qchange(char*instance, parameters_t p)
2116 instance_t* i = dictionary_lookup(&instances, instance);
2118 syntaxerror("instance %s not known", instance);
2119 recordChanges(i->history, p, CF_QCHANGE, 0);
2125 syntaxerror(".end unexpected");
2126 switch (stack[stackpos-1].type)
2141 syntaxerror("internal error 1");
2145 // ------------------------------------------------------------------------
2147 typedef int command_func_t(map_t*args);
2149 SRECT parseBox(char*str)
2151 SRECT r = {0,0,0,0};
2152 float xmin, xmax, ymin, ymax;
2153 char*x = strchr(str, 'x');
2155 if(!strcmp(str, "autocrop")) {
2156 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2160 d1 = strchr(x+1, ':');
2162 d2 = strchr(d1+1, ':');
2164 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2168 else if(d1 && !d2) {
2169 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2175 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2180 r.xmin = (SCOORD)(xmin*20);
2181 r.ymin = (SCOORD)(ymin*20);
2182 r.xmax = (SCOORD)(xmax*20);
2183 r.ymax = (SCOORD)(ymax*20);
2186 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2189 float parseFloat(char*str)
2193 int parseInt(char*str)
2198 if(str[0]=='+' || str[0]=='-')
2202 if(str[t]<'0' || str[t]>'9')
2203 syntaxerror("Not an Integer: \"%s\"", str);
2206 int parseTwip(char*str)
2210 if(str[0]=='+' || str[0]=='-') {
2215 dot = strchr(str, '.');
2219 return sign*parseInt(str)*20;
2221 char* old = strdup(str);
2222 int l=strlen(dot+1);
2225 for(s=str;s<dot-1;s++)
2226 if(*s<'0' || *s>'9')
2229 syntaxerror("Not a coordinate: \"%s\"", str);
2232 if(*s<'0' || *s>'9')
2235 syntaxerror("Not a coordinate: \"%s\"", str);
2237 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2238 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2241 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2245 return sign*atoi(str)*20;
2247 return sign*atoi(str)*20+atoi(dot)*2;
2249 return sign*atoi(str)*20+atoi(dot)/5;
2254 int isPoint(char*str)
2256 if(strchr(str, '('))
2262 SPOINT parsePoint(char*str)
2266 int l = strlen(str);
2267 char*comma = strchr(str, ',');
2268 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2269 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2270 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2271 p.x = parseTwip(tmp);
2272 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2273 p.y = parseTwip(tmp);
2277 int parseColor2(char*str, RGBA*color)
2279 int l = strlen(str);
2283 struct {unsigned char r,g,b;char*name;} colors[] =
2284 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2285 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2286 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2287 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2288 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2289 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2290 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2291 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2292 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2293 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2294 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2295 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2299 if(str[0]=='#' && (l==7 || l==9)) {
2300 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2302 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2304 color->r = r; color->g = g; color->b = b; color->a = a;
2307 int len=strlen(str);
2309 if(strchr(str, '/')) {
2310 len = strchr(str, '/')-str;
2311 sscanf(str+len+1,"%02x", &alpha);
2313 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2314 if(!strncmp(str, colors[t].name, len)) {
2319 color->r = r; color->g = g; color->b = b; color->a = a;
2325 RGBA parseColor(char*str)
2328 if(!parseColor2(str, &c))
2329 syntaxerror("Expression '%s' is not a color", str);
2333 typedef struct _muladd {
2338 MULADD parseMulAdd(char*str)
2341 char* str2 = (char*)malloc(strlen(str)+5);
2348 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2349 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2350 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2351 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2352 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2353 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2354 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2355 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2356 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2357 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2359 syntaxerror("'%s' is not a valid color transform expression", str);
2361 m.add = (int)(add*256);
2362 m.mul = (int)(mul*256);
2367 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2369 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2370 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2372 if(a<-32768) a=-32768;
2373 if(a>32767) a=32767;
2374 if(m<-32768) m=-32768;
2375 if(m>32767) m=32767;
2381 float parsePxOrPercent(char*fontname, char*str)
2383 int l = strlen(str);
2384 if(strchr(str, '%'))
2385 return parsePercent(str);
2386 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2387 float p = atof(str);
2388 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2390 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2394 float parsePercent(char*str)
2396 int l = strlen(str);
2400 return atoi(str)/100.0;
2402 syntaxerror("Expression '%s' is not a percentage", str);
2405 int isPercent(char*str)
2407 return str[strlen(str)-1]=='%';
2409 int parseNewSize(char*str, int size)
2412 return parsePercent(str)*size;
2414 return (int)(atof(str)*20);
2417 int isColor(char*str)
2420 return parseColor2(str, &c);
2423 static char* lu(map_t* args, char*name)
2425 char* value = map_lookup(args, name);
2427 map_dump(args, stdout, "");
2428 syntaxerror("internal error 2: value %s should be set", name);
2433 static int c_flash(map_t*args)
2435 char* filename = map_lookup(args, "filename");
2436 char* compressstr = lu(args, "compress");
2437 SRECT bbox = parseBox(lu(args, "bbox"));
2438 int version = parseInt(lu(args, "version"));
2439 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2441 RGBA color = parseColor(lu(args, "background"));
2443 if(!filename || !*filename) {
2444 /* for compatibility */
2445 filename = map_lookup(args, "name");
2446 if(!filename || !*filename) {
2449 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2450 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2454 if(!filename || override_outputname)
2455 filename = outputname;
2457 if(!strcmp(compressstr, "default"))
2458 compress = version>=6;
2459 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2461 else if(!strcmp(compressstr, "no"))
2463 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2465 s_swf(filename, bbox, version, fps, compress, color);
2468 int isRelative(char*str)
2470 return !strncmp(str, "<plus>", 6) ||
2471 !strncmp(str, "<minus>", 7);
2473 char* getOffset(char*str)
2475 if(!strncmp(str, "<plus>", 6))
2477 if(!strncmp(str, "<minus>", 7))
2479 syntaxerror("internal error (347)");
2482 int getSign(char*str)
2484 if(!strncmp(str, "<plus>", 6))
2486 if(!strncmp(str, "<minus>", 7))
2488 syntaxerror("internal error (348)");
2491 static dictionary_t points;
2492 static mem_t mpoints;
2493 int points_initialized = 0;
2495 static int c_interpolation(map_t *args)
2498 char* name = lu(args, "name");
2499 if (dictionary_lookup(&interpolations, name))
2500 syntaxerror("interpolation %s defined twice", name);
2502 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2503 char* functionstr = lu(args, "function");
2504 inter->function = 0;
2505 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2506 if (!strcmp(functionstr,interpolationFunctions[i]))
2508 inter->function = i + 1;
2511 if (!inter->function)
2512 syntaxerror("unkown interpolation function %s", functionstr);
2513 inter->speed = parseFloat(lu(args, "speed"));
2514 inter->amplitude = parseFloat(lu(args, "amplitude"));
2515 inter->growth = parseFloat(lu(args, "growth"));
2516 inter->bounces = parseInt(lu(args, "bounces"));
2517 inter->damping = parseInt(lu(args, "damping"));
2519 dictionary_put2(&interpolations, name, inter);
2523 SPOINT getPoint(SRECT r, char*name)
2526 if(!strcmp(name, "center")) {
2528 p.x = (r.xmin + r.xmax)/2;
2529 p.y = (r.ymin + r.ymax)/2;
2533 if(points_initialized)
2534 l = (int)dictionary_lookup(&points, name);
2536 syntaxerror("Invalid point: \"%s\".", name);
2539 return *(SPOINT*)&mpoints.buffer[l];
2542 static int texture2(char*name, char*object, map_t*args, int errors)
2545 char*xstr = map_lookup(args, "x");
2546 char*ystr = map_lookup(args, "y");
2547 char*widthstr = map_lookup(args, "width");
2548 char*heightstr = map_lookup(args, "height");
2549 char*scalestr = map_lookup(args, "scale");
2550 char*scalexstr = map_lookup(args, "scalex");
2551 char*scaleystr = map_lookup(args, "scaley");
2552 char*rotatestr = map_lookup(args, "rotate");
2553 char* shearstr = map_lookup(args, "shear");
2554 char* radiusstr = map_lookup(args, "r");
2556 float scalex = 1.0, scaley = 1.0;
2557 float rotate=0, shear=0;
2559 if(!*xstr && !*ystr) {
2561 syntaxerror("x and y must be set");
2564 if(*scalestr && (*scalexstr || *scaleystr)) {
2565 syntaxerror("scale and scalex/scaley can't both be set");
2568 if((*widthstr || *heightstr) && *radiusstr) {
2569 syntaxerror("width/height and radius can't both be set");
2572 widthstr = radiusstr;
2573 heightstr = radiusstr;
2575 if(!*xstr) xstr="0";
2576 if(!*ystr) ystr="0";
2577 if(!*rotatestr) rotatestr="0";
2578 if(!*shearstr) shearstr="0";
2581 scalex = scaley = parsePercent(scalestr);
2582 } else if(*scalexstr || *scaleystr) {
2583 if(scalexstr) scalex = parsePercent(scalexstr);
2584 if(scaleystr) scaley = parsePercent(scaleystr);
2585 } else if(*widthstr || *heightstr) {
2588 s_getBitmapSize(object, &width, &height);
2590 scalex = (float)parseTwip(widthstr)/(float)width;
2592 scaley = (float)parseTwip(heightstr)/(float)height;
2594 x = parseTwip(xstr);
2595 y = parseTwip(ystr);
2596 rotate = parseFloat(rotatestr);
2597 shear = parseFloat(shearstr);
2599 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2604 static int c_texture(map_t*args)
2606 char*name = lu(args, "instance");
2607 char*object = lu(args, "character");
2608 return texture2(name, object, args, 1);
2611 static int c_gradient(map_t*args)
2613 char*name = lu(args, "name");
2614 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2615 int rotate = parseInt(lu(args, "rotate"));
2619 syntaxerror("colon (:) expected");
2621 if(dictionary_lookup(&gradients, name))
2622 syntaxerror("gradient %s defined twice", name);
2624 s_gradient(name, text, radial, rotate);
2626 /* check whether we also have placement information,
2627 which would make this a positioned gradient.
2628 If there is placement information, texture2() will
2629 add a texture, which has priority over the gradient.
2631 texture2(name, name, args, 0);
2635 static int c_blur(map_t*args)
2637 char*name = lu(args, "name");
2638 char*blurstr = lu(args, "blur");
2639 char*blurxstr = lu(args, "blurx");
2640 char*blurystr = lu(args, "blury");
2641 float blurx=1.0, blury=1.0;
2643 blurx = parseFloat(blurstr);
2644 blury = parseFloat(blurstr);
2647 blurx = parseFloat(blurxstr);
2649 blury = parseFloat(blurystr);
2650 int passes = parseInt(lu(args, "passes"));
2651 s_blur(name, blurx, blury, passes);
2655 static int c_gradientglow(map_t*args)
2657 char*name = lu(args, "name");
2658 char*gradient = lu(args, "gradient");
2659 char*blurstr = lu(args, "blur");
2660 char*blurxstr = lu(args, "blurx");
2661 char*blurystr = lu(args, "blury");
2662 float blurx=1.0, blury=1.0;
2664 blurx = parseFloat(blurstr);
2665 blury = parseFloat(blurstr);
2668 blurx = parseFloat(blurxstr);
2670 blury = parseFloat(blurystr);
2672 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2673 float distance = parseFloat(lu(args, "distance"));
2674 float strength = parseFloat(lu(args, "strength"));
2675 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2676 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2677 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2678 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2679 int passes = parseInt(lu(args, "passes"));
2681 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2685 static int c_dropshadow(map_t*args)
2687 char*name = lu(args, "name");
2688 RGBA color = parseColor(lu(args, "color"));
2689 char*blurstr = lu(args, "blur");
2690 char*blurxstr = lu(args, "blurx");
2691 char*blurystr = lu(args, "blury");
2692 float blurx=1.0, blury=1.0;
2694 blurx = parseFloat(blurstr);
2695 blury = parseFloat(blurstr);
2698 blurx = parseFloat(blurxstr);
2700 blury = parseFloat(blurystr);
2702 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2703 float distance = parseFloat(lu(args, "distance"));
2704 float strength = parseFloat(lu(args, "strength"));
2705 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2706 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2707 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2708 int passes = parseInt(lu(args, "passes"));
2710 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
2714 static int c_bevel(map_t*args)
2716 char*name = lu(args, "name");
2717 RGBA shadow = parseColor(lu(args, "shadow"));
2718 RGBA highlight = parseColor(lu(args, "highlight"));
2719 char*blurstr = lu(args, "blur");
2720 char*blurxstr = lu(args, "blurx");
2721 char*blurystr = lu(args, "blury");
2722 float blurx=1.0, blury=1.0;
2724 blurx = parseFloat(blurstr);
2725 blury = parseFloat(blurstr);
2728 blurx = parseFloat(blurxstr);
2730 blury = parseFloat(blurystr);
2732 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2733 float distance = parseFloat(lu(args, "distance"));
2734 float strength = parseFloat(lu(args, "strength"));
2735 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2736 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2737 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2738 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2739 int passes = parseInt(lu(args, "passes"));
2741 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2745 static int c_point(map_t*args)
2747 char*name = lu(args, "name");
2751 if(!points_initialized) {
2752 dictionary_init(&points);
2754 points_initialized = 1;
2756 p.x = parseTwip(lu(args, "x"));
2757 p.y = parseTwip(lu(args, "y"));
2758 pos = mem_put(&mpoints, &p, sizeof(p));
2759 string_set(&s1, name);
2761 dictionary_put(&points, s1, (void*)pos);
2764 static int c_play(map_t*args)
2766 char*name = lu(args, "name");
2767 char*loop = lu(args, "loop");
2768 char*nomultiple = lu(args, "nomultiple");
2770 if(!strcmp(nomultiple, "nomultiple"))
2773 nm = parseInt(nomultiple);
2775 if(s_playsound(name, parseInt(loop), nm, 0)) {
2777 } else if(s_swf3action(name, "play")) {
2783 static int c_stop(map_t*args)
2785 char*name = map_lookup(args, "name");
2787 if(s_playsound(name, 0,0,1))
2789 else if(s_swf3action(name, "stop"))
2791 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
2795 static int c_nextframe(map_t*args)
2797 char*name = lu(args, "name");
2799 if(s_swf3action(name, "nextframe")) {
2802 syntaxerror("I don't know anything about movie \"%s\"", name);
2806 static int c_previousframe(map_t*args)
2808 char*name = lu(args, "name");
2810 if(s_swf3action(name, "previousframe")) {
2813 syntaxerror("I don't know anything about movie \"%s\"", name);
2817 static int c_placement(map_t*args, int type)
2819 char*instance = lu(args, (type==0||type==4)?"instance":"name");
2822 char* luminancestr = lu(args, "luminance");
2823 char* scalestr = lu(args, "scale");
2824 char* scalexstr = lu(args, "scalex");
2825 char* scaleystr = lu(args, "scaley");
2826 char* rotatestr = lu(args, "rotate");
2827 char* shearstr = lu(args, "shear");
2828 char* xstr="", *pivotstr="";
2829 char* ystr="", *anglestr="";
2830 char*above = lu(args, "above"); /*FIXME*/
2831 char*below = lu(args, "below");
2832 char* rstr = lu(args, "red");
2833 char* gstr = lu(args, "green");
2834 char* bstr = lu(args, "blue");
2835 char* astr = lu(args, "alpha");
2836 char* pinstr = lu(args, "pin");
2837 char* as = map_lookup(args, "as");
2838 char* blendmode = lu(args, "blend");
2839 char* filterstr = lu(args, "filter");
2847 U32 set = 0x00000000;
2850 { // (?) .rotate or .arcchange
2851 pivotstr = lu(args, "pivot");
2852 anglestr = lu(args, "angle");
2856 xstr = lu(args, "x");
2857 ystr = lu(args, "y");
2861 luminance = parseMulAdd(luminancestr);
2865 luminance.mul = 256;
2870 if(scalexstr[0]||scaleystr[0])
2871 syntaxerror("scalex/scaley and scale cannot both be set");
2872 scalexstr = scaleystr = scalestr;
2875 if(type == 0 || type == 4) {
2877 character = lu(args, "character");
2878 parameters_clear(&p);
2879 } else if (type == 5) {
2880 character = lu(args, "name");
2881 parameters_clear(&p);
2884 p = s_getParameters(instance);
2890 if(isRelative(xstr))
2892 if(type == 0 || type == 4)
2893 syntaxerror("relative x values not allowed for initial put or startclip");
2894 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2898 p.x = parseTwip(xstr);
2904 if(isRelative(ystr))
2906 if(type == 0 || type == 4)
2907 syntaxerror("relative y values not allowed for initial put or startclip");
2908 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2912 p.y = parseTwip(ystr);
2917 /* scale, scalex, scaley */
2919 oldbbox = s_getCharBBox(character);
2921 oldbbox = s_getInstanceBBox(instance);
2922 oldwidth = oldbbox.xmax - oldbbox.xmin;
2923 oldheight = oldbbox.ymax - oldbbox.ymin;
2930 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2931 set = set | SF_SCALEX;
2939 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2940 set = set | SF_SCALEY;
2946 if(isRelative(rotatestr))
2947 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2949 p.rotate = parseFloat(rotatestr);
2950 set = set | SF_ROTATE;
2956 if(isRelative(shearstr))
2957 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2959 p.shear = parseFloat(shearstr);
2960 set = set | SF_SHEAR;
2965 if(isPoint(pivotstr))
2966 p.pivot = parsePoint(pivotstr);
2968 p.pivot = getPoint(oldbbox, pivotstr);
2969 set = set | SF_PIVOT;
2975 p.pin = parsePoint(pinstr);
2977 p.pin = getPoint(oldbbox, pinstr);
2981 /* color transform */
2983 if(rstr[0] || luminancestr[0])
2987 r = parseMulAdd(rstr);
2990 r.add = p.cxform.r0;
2991 r.mul = p.cxform.r1;
2993 r = mergeMulAdd(r, luminance);
2994 p.cxform.r0 = r.mul;
2995 p.cxform.r1 = r.add;
2996 set = set | SF_CX_R;
2998 if(gstr[0] || luminancestr[0])
3002 g = parseMulAdd(gstr);
3005 g.add = p.cxform.g0;
3006 g.mul = p.cxform.g1;
3008 g = mergeMulAdd(g, luminance);
3009 p.cxform.g0 = g.mul;
3010 p.cxform.g1 = g.add;
3011 set = set | SF_CX_G;
3013 if(bstr[0] || luminancestr[0])
3017 b = parseMulAdd(bstr);
3020 b.add = p.cxform.b0;
3021 b.mul = p.cxform.b1;
3023 b = mergeMulAdd(b, luminance);
3024 p.cxform.b0 = b.mul;
3025 p.cxform.b1 = b.add;
3026 set = set | SF_CX_B;
3030 MULADD a = parseMulAdd(astr);
3031 p.cxform.a0 = a.mul;
3032 p.cxform.a1 = a.add;
3033 set = set | SF_CX_A;
3040 for(t = 0; blendModeNames[t]; t++)
3042 if(!strcmp(blendModeNames[t], blendmode))
3050 syntaxerror("unknown blend mode: '%s'", blendmode);
3052 p.blendmode = blend;
3053 set = set | SF_BLEND;
3058 FILTER*f = dictionary_lookup(&filters, filterstr);
3060 syntaxerror("Unknown filter %s", filterstr);
3062 set = set | SF_FILTER;
3070 s_put(instance, character, p);
3074 char* interstr = lu(args, "interpolation");
3075 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3077 syntaxerror("unkown interpolation %s", interstr);
3078 s_change(instance, p, inter);
3082 s_qchange(instance, p);
3085 s_jump(instance, p);
3088 s_startclip(instance, character, p);
3092 s_buttonput(character, as, p);
3094 s_buttonput(character, "shape", p);
3100 static int c_put(map_t*args)
3102 c_placement(args, 0);
3105 static int c_change(map_t*args)
3107 if (currentframe == 0)
3108 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3109 c_placement(args, 1);
3112 static int c_qchange(map_t*args)
3114 c_placement(args, 2);
3117 static int c_arcchange(map_t*args)
3119 c_placement(args, 2);
3122 static int c_jump(map_t*args)
3124 c_placement(args, 3);
3127 static int c_startclip(map_t*args)
3129 c_placement(args, 4);
3132 static int c_show(map_t*args)
3134 c_placement(args, 5);
3137 static int c_del(map_t*args)
3139 char*instance = lu(args, "name");
3140 s_delinstance(instance);
3143 static int c_end(map_t*args)
3148 static int c_sprite(map_t*args)
3150 char* name = lu(args, "name");
3154 static int c_frame(map_t*args)
3156 char*framestr = lu(args, "n");
3157 char*cutstr = lu(args, "cut");
3159 char*name = lu(args, "name");
3160 char*anchor = lu(args, "anchor");
3163 if(!strcmp(anchor, "anchor") && !*name)
3168 if(strcmp(cutstr, "no"))
3170 if(isRelative(framestr)) {
3171 frame = s_getframe();
3172 if(getSign(framestr)<0)
3173 syntaxerror("relative frame expressions must be positive");
3174 frame += parseInt(getOffset(framestr));
3177 frame = parseInt(framestr);
3178 if(s_getframe() >= frame
3179 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3180 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3182 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3185 static int c_primitive(map_t*args)
3187 char*name = lu(args, "name");
3188 char*command = lu(args, "commandname");
3189 int width=0, height=0, r=0;
3190 int linewidth = parseTwip(lu(args, "line"));
3191 char*colorstr = lu(args, "color");
3192 RGBA color = parseColor(colorstr);
3193 char*fillstr = lu(args, "fill");
3200 if(!strcmp(command, "circle"))
3202 else if(!strcmp(command, "filled"))
3206 width = parseTwip(lu(args, "width"));
3207 height = parseTwip(lu(args, "height"));
3208 } else if (type==1) {
3209 r = parseTwip(lu(args, "r"));
3210 } else if (type==2) {
3211 outline = lu(args, "outline");
3214 if(!strcmp(fillstr, "fill"))
3216 if(!strcmp(fillstr, "none"))
3218 if(width<0 || height<0 || linewidth<0 || r<0)
3219 syntaxerror("values width, height, line, r must be positive");
3221 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3222 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3223 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3227 static int c_textshape(map_t*args)
3229 char*name = lu(args, "name");
3230 char*text = lu(args, "text");
3231 char*font = lu(args, "font");
3232 float size = parsePxOrPercent(font, lu(args, "size"));
3234 s_textshape(name, font, size, text);
3238 static int c_swf(map_t*args)
3240 char*name = lu(args, "name");
3241 char*filename = lu(args, "filename");
3242 char*command = lu(args, "commandname");
3243 if(!strcmp(command, "shape"))
3244 warning("Please use .swf instead of .shape");
3245 s_includeswf(name, filename);
3249 static int c_font(map_t*args)
3251 char*name = lu(args, "name");
3252 char*filename = lu(args, "filename");
3253 s_font(name, filename);
3257 static int c_sound(map_t*args)
3259 char*name = lu(args, "name");
3260 char*filename = lu(args, "filename");
3261 s_sound(name, filename);
3265 static int c_text(map_t*args)
3267 char*name = lu(args, "name");
3268 char*text = lu(args, "text");
3269 char*font = lu(args, "font");
3270 float size = parsePxOrPercent(font, lu(args, "size"));
3271 RGBA color = parseColor(lu(args, "color"));
3272 s_text(name, font, text, (int)(size*100), color);
3276 static int c_soundtrack(map_t*args)
3281 static int c_quicktime(map_t*args)
3283 char*name = lu(args, "name");
3284 char*url = lu(args, "url");
3285 s_quicktime(name, url);
3289 static int c_image(map_t*args)
3291 char*command = lu(args, "commandname");
3292 char*name = lu(args, "name");
3293 char*filename = lu(args, "filename");
3294 if(!strcmp(command,"jpeg")) {
3295 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3296 s_image(name, "jpeg", filename, quality);
3298 s_image(name, "png", filename, 0);
3303 static int c_outline(map_t*args)
3305 char*name = lu(args, "name");
3306 char*format = lu(args, "format");
3310 syntaxerror("colon (:) expected");
3312 s_outline(name, format, text);
3316 int fakechar(map_t*args)
3318 char*name = lu(args, "name");
3319 s_box(name, 0, 0, black, 20, 0);
3323 static int c_egon(map_t*args) {return fakechar(args);}
3324 static int c_button(map_t*args) {
3325 char*name = lu(args, "name");
3329 static int current_button_flags = 0;
3330 static int c_on_press(map_t*args)
3332 char*position = lu(args, "position");
3334 if(!strcmp(position, "inside")) {
3335 current_button_flags |= BC_OVERUP_OVERDOWN;
3336 } else if(!strcmp(position, "outside")) {
3337 //current_button_flags |= BC_IDLE_OUTDOWN;
3338 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3339 } else if(!strcmp(position, "anywhere")) {
3340 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3343 if(type == RAWDATA) {
3345 s_buttonaction(current_button_flags, action);
3346 current_button_flags = 0;
3352 static int c_on_release(map_t*args)
3354 char*position = lu(args, "position");
3356 if(!strcmp(position, "inside")) {
3357 current_button_flags |= BC_OVERDOWN_OVERUP;
3358 } else if(!strcmp(position, "outside")) {
3359 current_button_flags |= BC_OUTDOWN_IDLE;
3360 } else if(!strcmp(position, "anywhere")) {
3361 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3364 if(type == RAWDATA) {
3366 s_buttonaction(current_button_flags, action);
3367 current_button_flags = 0;
3373 static int c_on_move_in(map_t*args)
3375 char*position = lu(args, "state");
3377 if(!strcmp(position, "pressed")) {
3378 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3379 } else if(!strcmp(position, "not_pressed")) {
3380 current_button_flags |= BC_IDLE_OVERUP;
3381 } else if(!strcmp(position, "any")) {
3382 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3385 if(type == RAWDATA) {
3387 s_buttonaction(current_button_flags, action);
3388 current_button_flags = 0;
3394 static int c_on_move_out(map_t*args)
3396 char*position = lu(args, "state");
3398 if(!strcmp(position, "pressed")) {
3399 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3400 } else if(!strcmp(position, "not_pressed")) {
3401 current_button_flags |= BC_OVERUP_IDLE;
3402 } else if(!strcmp(position, "any")) {
3403 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3406 if(type == RAWDATA) {
3408 s_buttonaction(current_button_flags, action);
3409 current_button_flags = 0;
3415 static int c_on_key(map_t*args)
3417 char*key = lu(args, "key");
3419 if(strlen(key)==1) {
3422 current_button_flags |= 0x4000 + (key[0]*0x200);
3424 syntaxerror("invalid character: %c"+key[0]);
3429 <ctrl-x> = 0x200*(x-'a')
3433 syntaxerror("invalid key: %s",key);
3436 if(type == RAWDATA) {
3438 s_buttonaction(current_button_flags, action);
3439 current_button_flags = 0;
3446 static int c_edittext(map_t*args)
3448 //"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"},
3449 char*name = lu(args, "name");
3450 char*font = lu(args, "font");
3451 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3452 int width = parseTwip(lu(args, "width"));
3453 int height = parseTwip(lu(args, "height"));
3454 char*text = lu(args, "text");
3455 RGBA color = parseColor(lu(args, "color"));
3456 int maxlength = parseInt(lu(args, "maxlength"));
3457 char*variable = lu(args, "variable");
3458 char*passwordstr = lu(args, "password");
3459 char*wordwrapstr = lu(args, "wordwrap");
3460 char*multilinestr = lu(args, "multiline");
3461 char*htmlstr = lu(args, "html");
3462 char*noselectstr = lu(args, "noselect");
3463 char*readonlystr = lu(args, "readonly");
3464 char*borderstr = lu(args, "border");
3465 char*autosizestr = lu(args, "autosize");
3466 char*alignstr = lu(args, "align");
3470 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3471 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3472 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3473 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3474 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3475 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3476 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3477 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3478 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3479 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
3480 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
3481 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
3482 else syntaxerror("Unknown alignment: %s", alignstr);
3484 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
3488 static int c_morphshape(map_t*args) {return fakechar(args);}
3489 static int c_movie(map_t*args) {return fakechar(args);}
3491 static char* readfile(const char*filename)
3493 FILE*fi = fopen(filename, "rb");
3497 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
3498 fseek(fi, 0, SEEK_END);
3500 fseek(fi, 0, SEEK_SET);
3501 text = rfx_alloc(l+1);
3502 fread(text, l, 1, fi);
3508 static int c_action(map_t*args)
3510 char* filename = map_lookup(args, "filename");
3511 if(!filename ||!*filename) {
3513 if(type != RAWDATA) {
3514 syntaxerror("colon (:) expected");
3518 s_action(readfile(filename));
3524 static int c_initaction(map_t*args)
3526 char* character = lu(args, "name");
3527 char* filename = map_lookup(args, "filename");
3528 if(!filename ||!*filename) {
3530 if(type != RAWDATA) {
3531 syntaxerror("colon (:) expected");
3533 s_initaction(character, text);
3535 s_initaction(character, readfile(filename));
3543 command_func_t* func;
3546 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default"},
3547 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
3548 // "import" type stuff
3549 {"swf", c_swf, "name filename"},
3550 {"shape", c_swf, "name filename"},
3551 {"jpeg", c_image, "name filename quality=80%"},
3552 {"png", c_image, "name filename"},
3553 {"movie", c_movie, "name filename"},
3554 {"sound", c_sound, "name filename"},
3555 {"font", c_font, "name filename"},
3556 {"soundtrack", c_soundtrack, "filename"},
3557 {"quicktime", c_quicktime, "url"},
3559 // generators of primitives
3561 {"point", c_point, "name x=0 y=0"},
3562 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
3563 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5, damping=2"},
3564 {"outline", c_outline, "name format=simple"},
3565 {"textshape", c_textshape, "name font size=100% text"},
3568 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
3569 {"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"},
3570 {"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"},
3571 {"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"},
3573 // character generators
3574 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
3575 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
3576 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
3578 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
3579 {"text", c_text, "name text font size=100% color=white"},
3580 {"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="},
3581 {"morphshape", c_morphshape, "name start end"},
3582 {"button", c_button, "name"},
3583 {"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="},
3584 {"on_press", c_on_press, "position=inside"},
3585 {"on_release", c_on_release, "position=anywhere"},
3586 {"on_move_in", c_on_move_in, "state=not_pressed"},
3587 {"on_move_out", c_on_move_out, "state=not_pressed"},
3588 {"on_key", c_on_key, "key=any"},
3591 {"play", c_play, "name loop=0 @nomultiple=0"},
3592 {"stop", c_stop, "name= "},
3593 {"nextframe", c_nextframe, "name"},
3594 {"previousframe", c_previousframe, "name"},
3596 // object placement tags
3597 {"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="},
3598 {"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="},
3599 {"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"},
3600 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3601 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3602 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3603 {"del", c_del, "name"},
3604 // virtual object placement
3605 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
3607 // commands which start a block
3608 //startclip (see above)
3609 {"sprite", c_sprite, "name"},
3610 {"action", c_action, "filename="},
3611 {"initaction", c_initaction, "name filename="},
3617 static map_t parseArguments(char*command, char*pattern)
3633 string_set(&t1, "commandname");
3634 string_set(&t2, command);
3635 map_put(&result, t1, t2);
3637 if(!pattern || !*pattern)
3644 if(!strncmp("<i> ", x, 3)) {
3646 if(type == COMMAND || type == RAWDATA) {
3648 syntaxerror("character name expected");
3650 name[pos].str = "instance";
3652 value[pos].str = text;
3653 value[pos].len = strlen(text);
3657 if(type == ASSIGNMENT)
3660 name[pos].str = "character";
3662 value[pos].str = text;
3663 value[pos].len = strlen(text);
3671 isboolean[pos] = (x[0] =='@');
3684 name[pos].len = d-x;
3689 name[pos].len = e-x;
3690 value[pos].str = e+1;
3691 value[pos].len = d-e-1;
3699 /* for(t=0;t<len;t++) {
3700 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
3701 isboolean[t]?"(boolean)":"");
3706 if(type == RAWDATA || type == COMMAND) {
3711 // first, search for boolean arguments
3712 for(pos=0;pos<len;pos++)
3714 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
3716 if(type == ASSIGNMENT)
3718 value[pos].str = text;
3719 value[pos].len = strlen(text);
3720 /*printf("setting boolean parameter %s (to %s)\n",
3721 strdup_n(name[pos], namelen[pos]),
3722 strdup_n(value[pos], valuelen[pos]));*/
3727 // second, search for normal arguments
3729 for(pos=0;pos<len;pos++)
3731 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
3732 (type != ASSIGNMENT && !set[pos])) {
3734 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
3736 if(type == ASSIGNMENT)
3739 value[pos].str = text;
3740 value[pos].len = strlen(text);
3742 printf("setting parameter %s (to %s)\n",
3743 strdup_n(name[pos].str, name[pos].len),
3744 strdup_n(value[pos].str, value[pos].len));
3750 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
3754 for(t=0;t<len;t++) {
3755 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
3758 for(t=0;t<len;t++) {
3759 if(value[t].str && value[t].str[0] == '*') {
3760 //relative default- take value from some other parameter
3762 for(s=0;s<len;s++) {
3763 if(value[s].len == value[t].len-1 &&
3764 !strncmp(&value[t].str[1], value[s].str, value[s].len))
3765 value[t].str = value[s].str;
3768 if(value[t].str == 0) {
3770 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
3774 /* ok, now construct the dictionary from the parameters */
3778 map_put(&result, name[t], value[t]);
3782 static void parseArgumentsForCommand(char*command)
3787 msg("<verbose> parse Command: %s (line %d)", command, line);
3789 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
3790 if(!strcmp(arguments[t].command, command)) {
3792 /* ugly hack- will be removed soon (once documentation and .sc generating
3793 utilities have been changed) */
3794 if(!strcmp(command, "swf") && !stackpos) {
3795 warning("Please use .flash instead of .swf- this will be mandatory soon");
3800 args = parseArguments(command, arguments[t].arguments);
3806 syntaxerror("command %s not known", command);
3808 // catch missing .flash directives at the beginning of a file
3809 if(strcmp(command, "flash") && !stackpos)
3811 syntaxerror("No movie defined- use .flash first");
3815 printf(".%s\n", command);fflush(stdout);
3816 map_dump(&args, stdout, "\t");fflush(stdout);
3819 (*arguments[nr].func)(&args);
3821 /*if(!strcmp(command, "button") ||
3822 !strcmp(command, "action")) {
3825 if(type == COMMAND) {
3826 if(!strcmp(text, "end"))
3840 int main (int argc,char ** argv)
3843 processargs(argc, argv);
3844 initLog(0,-1,0,0,-1,verbose);
3847 args_callback_usage(argv[0]);
3851 file = generateTokens(filename);
3853 fprintf(stderr, "parser returned error.\n");
3859 while(!noMoreTokens()) {
3862 syntaxerror("command expected");
3863 parseArgumentsForCommand(text);