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 "../lib/interpolation.h"
40 #include "../lib/history.h"
43 static char * outputname = "output.swf";
44 static int verbose = 2;
45 static int optimize = 0;
46 static int override_outputname = 0;
47 static int do_cgi = 0;
49 static struct options_t options[] = {
58 int args_callback_option(char*name,char*val)
60 if(!strcmp(name, "V")) {
61 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
64 else if(!strcmp(name, "o")) {
66 override_outputname = 1;
69 else if(!strcmp(name, "O")) {
73 else if(!strcmp(name, "C")) {
77 else if(!strcmp(name, "v")) {
82 printf("Unknown option: -%s\n", name);
87 int args_callback_longoption(char*name,char*val)
89 return args_long2shortoption(options, name, val);
91 void args_callback_usage(char *name)
94 printf("Usage: %s [-o file.swf] file.sc\n", name);
96 printf("-h , --help Print short help message and exit\n");
97 printf("-V , --version Print version info and exit\n");
98 printf("-C , --cgi Output to stdout (for use in CGI environments)\n");
99 printf("-v , --verbose Increase verbosity. \n");
100 printf("-o , --output <filename> Set output file to <filename>.\n");
103 int args_callback_command(char*name,char*val)
106 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
113 static struct token_t* file;
120 static void readToken()
122 type = file[pos].type;
124 syntaxerror("unexpected end of file");
126 text = file[pos].text;
127 textlen = strlen(text);
128 line = file[pos].line;
129 column = file[pos].column;
131 //printf("---> %d(%s) %s\n", type, type_names[type], text);
134 static void pushBack()
137 if(!pos) syntaxerror("internal error 3");
142 textlen = strlen(text);
145 column = file[p].column;
148 static int noMoreTokens()
150 if(file[pos].type == END)
155 // ------------------------------ swf routines ----------------------------
159 int type; //0=swf, 1=sprite, 2=clip, 3=button
165 /* for sprites (1): */
171 dictionary_t oldinstances;
176 static int stackpos = 0;
178 static dictionary_t characters;
179 static dictionary_t images;
180 static dictionary_t textures;
181 static dictionary_t outlines;
182 static dictionary_t gradients;
183 static dictionary_t filters;
184 static dictionary_t interpolations;
185 static char idmap[65536];
186 static TAG*tag = 0; //current tag
188 static int id; //current character id
189 static int currentframe; //current frame in current level
190 static SRECT currentrect; //current bounding box in current level
191 static U16 currentdepth;
192 static dictionary_t instances;
193 static dictionary_t fonts;
194 static dictionary_t sounds;
195 static dictionary_t fontUsage;
197 typedef struct _parameters {
199 float scalex, scaley;
205 U8 blendmode; //not interpolated
207 U16 set; // bits indicating wether a parameter was set in the c_placement function
210 typedef struct _character {
216 typedef struct _instance {
217 character_t*character;
219 parameters_t parameters;
220 TAG* lastTag; //last tag which set the object
221 U16 lastFrame; //frame lastTag is in
225 typedef struct _outline {
230 typedef struct _gradient {
236 typedef struct _filter {
240 typedef struct _texture {
244 char* interpolationFunctions[] = {"linear", \
245 "quadIn", "quadOut", "quadInOut", \
246 "cubicIn", "cubicOut", "cubicInOut", \
247 "quartIn", "quartOut", "quartInOut", \
248 "quintIn", "quintOut", "quintInOut", \
249 "circleIn", "circleOut", "circleInOut", \
250 "exponentialIn", "exponentialOut", "exponentialInOut", \
251 "sineIn", "sineOut", "sineInOut", \
252 "elasticIn", "elasticOut", "elasticInOut", \
253 "backIn", "backOut", "backInOut", \
254 "bounceIn", "bounceOut", "bounceInOut", \
255 "fastBounceIn", "fastBounceOut", "fastBounceInOut"};
257 typedef struct _fontData {
259 int notUsed, needsAll;
262 void addFontData(char *name)
265 newFont = (fontData *)malloc(sizeof(fontData));
266 memset(newFont, 0, sizeof(fontData));
267 newFont->notUsed = 1;
268 dictionary_put2(&fontUsage, name, newFont);
271 void freeFontData(fontData* font)
277 fontData *getFontData(char *name)
279 return (fontData *)dictionary_lookup(&fontUsage, name);
282 static void character_init(character_t*c)
284 memset(c, 0, sizeof(character_t));
287 static character_t* character_new()
290 c = (character_t*)malloc(sizeof(character_t));
295 static void instance_init(instance_t*i)
297 memset(i, 0, sizeof(instance_t));
298 i->history = history_new();
301 static void instance_free(instance_t* i)
303 history_free(i->history);
307 static instance_t* instance_new()
310 c = (instance_t*)malloc(sizeof(instance_t));
315 static void free_instance(void* i)
317 instance_free((instance_t*)i);
320 static void free_font(void* f)
322 swf_FontFree((SWFFONT*)f);
325 static void free_fontData(void* fd)
327 freeFontData((fontData*)fd);
330 static void gradient_free(GRADIENT* grad)
337 static void free_gradient(void* grad)
339 gradient_free((GRADIENT*) grad);
342 static void outline_free(outline_t* o)
344 free(o->shape->data);
349 static void free_outline(void* o)
351 outline_free((outline_t*)o);
354 static void freeDictionaries()
356 dictionary_free_all(&instances, free_instance);
357 dictionary_free_all(&characters, free);
358 dictionary_free_all(&images, free);
359 dictionary_free_all(&textures, free);
360 dictionary_free_all(&outlines, free_outline);
361 dictionary_free_all(&gradients, free_gradient);
362 dictionary_free_all(&filters, free);
363 dictionary_free_all(&fonts, free_font);
364 dictionary_free_all(&sounds, free);
365 dictionary_free_all(&fontUsage, free_fontData);
366 dictionary_free_all(&interpolations, free);
369 static void incrementid()
373 syntaxerror("Out of character ids.");
378 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
380 if(dictionary_lookup(&characters, name))
381 syntaxerror("character %s defined twice", name);
382 character_t* c = character_new();
384 c->definingTag = ctag;
387 dictionary_put2(&characters, name, c);
389 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
391 swf_SetString(tag, name);
392 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
395 swf_SetString(tag, name);
397 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
399 if(dictionary_lookup(&images, name))
400 syntaxerror("image %s defined twice", name);
402 character_t* c = character_new();
403 c->definingTag = ctag;
406 dictionary_put2(&images, name, c);
408 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
410 if(dictionary_lookup(&instances, name))
411 syntaxerror("object %s defined twice", name);
412 instance_t* i = instance_new();
415 //swf_GetMatrix(0, &i->matrix);
416 dictionary_put2(&instances, name, i);
420 static void parameters_clear(parameters_t*p)
423 p->scalex = 1.0; p->scaley = 1.0;
426 p->pivot.x = 0; p->pivot.y = 0;
431 swf_GetCXForm(0, &p->cxform, 1);
434 static void makeMatrix(MATRIX*m, parameters_t*p)
443 sx = p->scalex*cos(p->rotate/360*2*PI);
444 r1 = -p->scalex*sin(p->rotate/360*2*PI)+sx*p->shear;
445 r0 = p->scaley*sin(p->rotate/360*2*PI);
446 sy = p->scaley*cos(p->rotate/360*2*PI)+r0*p->shear;
448 m->sx = (int)(sx*65536+0.5);
449 m->r1 = (int)(r1*65536+0.5);
450 m->r0 = (int)(r0*65536+0.5);
451 m->sy = (int)(sy*65536+0.5);
455 h = swf_TurnPoint(p->pin, m);
460 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
465 r = swf_TurnRect(rect, &m);
466 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
467 currentrect.xmax == 0 && currentrect.ymax == 0)
470 swf_ExpandRect2(¤trect, &r);
474 void builtInInterpolations()
476 interpolation_t* new;
477 new = (interpolation_t*)malloc(sizeof(interpolation_t));
478 new->function = IF_LINEAR;
479 dictionary_put2(&interpolations, "linear", new);
481 new = (interpolation_t*)malloc(sizeof(interpolation_t));
482 new->function = IF_QUAD_IN;
483 dictionary_put2(&interpolations, "quadIn", new);
484 new = (interpolation_t*)malloc(sizeof(interpolation_t));
485 new->function = IF_QUAD_OUT;
486 dictionary_put2(&interpolations, "quadOut", new);
487 new = (interpolation_t*)malloc(sizeof(interpolation_t));
488 new->function = IF_QUAD_IN_OUT;
489 dictionary_put2(&interpolations, "quadInOut", new);
491 new = (interpolation_t*)malloc(sizeof(interpolation_t));
492 new->function = IF_CUBIC_IN;
493 dictionary_put2(&interpolations, "cubicIn", new);
494 new = (interpolation_t*)malloc(sizeof(interpolation_t));
495 new->function = IF_CUBIC_OUT;
496 dictionary_put2(&interpolations, "cubicOut", new);
497 new = (interpolation_t*)malloc(sizeof(interpolation_t));
498 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;
503 dictionary_put2(&interpolations, "quartIn", new);
504 new = (interpolation_t*)malloc(sizeof(interpolation_t));
505 new->function = IF_QUART_OUT;
506 dictionary_put2(&interpolations, "quartOut", new);
507 new = (interpolation_t*)malloc(sizeof(interpolation_t));
508 new->function = IF_QUART_IN_OUT;
509 dictionary_put2(&interpolations, "quartInOut", new);
511 new = (interpolation_t*)malloc(sizeof(interpolation_t));
512 new->function = IF_QUINT_IN;
513 dictionary_put2(&interpolations, "quintIn", new);
514 new = (interpolation_t*)malloc(sizeof(interpolation_t));
515 new->function = IF_QUINT_OUT;
516 dictionary_put2(&interpolations, "quintOut", new);
517 new = (interpolation_t*)malloc(sizeof(interpolation_t));
518 new->function = IF_QUINT_IN_OUT;
519 dictionary_put2(&interpolations, "quintInOut", new);
521 new = (interpolation_t*)malloc(sizeof(interpolation_t));
522 new->function = IF_CIRCLE_IN;
523 dictionary_put2(&interpolations, "circleIn", new);
524 new = (interpolation_t*)malloc(sizeof(interpolation_t));
525 new->function = IF_CIRCLE_OUT;
526 dictionary_put2(&interpolations, "circleOut", new);
527 new = (interpolation_t*)malloc(sizeof(interpolation_t));
528 new->function = IF_CIRCLE_IN_OUT;
529 dictionary_put2(&interpolations, "circleInOut", new);
531 new = (interpolation_t*)malloc(sizeof(interpolation_t));
532 new->function = IF_EXPONENTIAL_IN;
533 dictionary_put2(&interpolations, "exponentialIn", new);
534 new = (interpolation_t*)malloc(sizeof(interpolation_t));
535 new->function = IF_EXPONENTIAL_OUT;
536 dictionary_put2(&interpolations, "exponentialOut", new);
537 new = (interpolation_t*)malloc(sizeof(interpolation_t));
538 new->function = IF_EXPONENTIAL_IN_OUT;
539 dictionary_put2(&interpolations, "exponentialInOut", new);
541 new = (interpolation_t*)malloc(sizeof(interpolation_t));
542 new->function = IF_SINE_IN;
543 dictionary_put2(&interpolations, "sineIn", new);
544 new = (interpolation_t*)malloc(sizeof(interpolation_t));
545 new->function = IF_SINE_OUT;
546 dictionary_put2(&interpolations, "sineOut", new);
547 new = (interpolation_t*)malloc(sizeof(interpolation_t));
548 new->function = IF_SINE_IN_OUT;
549 dictionary_put2(&interpolations, "sineInOut", new);
552 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
555 syntaxerror(".swf blocks can't be nested");
556 if(stackpos==sizeof(stack)/sizeof(stack[0]))
557 syntaxerror("too many levels of recursion");
559 SWF*swf = (SWF*)malloc(sizeof(SWF));
561 memset(swf, 0, sizeof(swf));
562 swf->fileVersion = version;
564 swf->frameRate = fps;
565 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
566 swf->compressed = compress;
567 swf_SetRGB(tag,&background);
569 dictionary_init(&characters);
570 dictionary_init(&images);
571 dictionary_init(&textures);
572 dictionary_init(&outlines);
573 dictionary_init(&gradients);
574 dictionary_init(&filters);
575 dictionary_init(&instances);
576 dictionary_init(&fonts);
577 dictionary_init(&sounds);
578 dictionary_init(&interpolations);
579 builtInInterpolations();
580 cleanUp = &freeDictionaries;
582 memset(&stack[stackpos], 0, sizeof(stack[0]));
583 stack[stackpos].type = 0;
584 stack[stackpos].filename = strdup(name);
585 stack[stackpos].swf = swf;
586 stack[stackpos].oldframe = -1;
591 memset(¤trect, 0, sizeof(currentrect));
594 memset(idmap, 0, sizeof(idmap));
598 void s_sprite(char*name)
600 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
601 swf_SetU16(tag, id); //id
602 swf_SetU16(tag, 0); //frames
604 memset(&stack[stackpos], 0, sizeof(stack[0]));
605 stack[stackpos].type = 1;
606 stack[stackpos].oldframe = currentframe;
607 stack[stackpos].olddepth = currentdepth;
608 stack[stackpos].oldrect = currentrect;
609 stack[stackpos].oldinstances = instances;
610 stack[stackpos].tag = tag;
611 stack[stackpos].id = id;
612 stack[stackpos].name = strdup(name);
614 /* FIXME: those four fields should be bundled together */
615 dictionary_init(&instances);
618 memset(¤trect, 0, sizeof(currentrect));
624 typedef struct _buttonrecord
632 typedef struct _button
636 buttonrecord_t records[4];
639 static button_t mybutton;
641 void s_button(char*name)
643 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
644 swf_SetU16(tag, id); //id
645 swf_ButtonSetFlags(tag, 0); //menu=no
647 memset(&mybutton, 0, sizeof(mybutton));
649 memset(&stack[stackpos], 0, sizeof(stack[0]));
650 stack[stackpos].type = 3;
651 stack[stackpos].tag = tag;
652 stack[stackpos].id = id;
653 stack[stackpos].name = strdup(name);
654 stack[stackpos].oldrect = currentrect;
655 memset(¤trect, 0, sizeof(currentrect));
660 void s_buttonput(char*character, char*as, parameters_t p)
662 character_t* c = dictionary_lookup(&characters, character);
667 if(!stackpos || (stack[stackpos-1].type != 3)) {
668 syntaxerror(".show may only appear in .button");
671 syntaxerror("character %s not known (in .shape %s)", character, character);
673 if(mybutton.endofshapes) {
674 syntaxerror("a .do may not precede a .show", character, character);
677 m = s_instancepos(c->size, &p);
685 if(*s==',' || *s==0) {
686 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
687 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
688 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
689 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
690 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
691 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
698 static void setbuttonrecords(TAG*tag)
700 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
701 if(!mybutton.endofshapes) {
704 if(!mybutton.records[3].set) {
705 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
709 if(mybutton.records[t].set) {
710 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
713 swf_SetU8(tag,0); // end of button records
714 mybutton.endofshapes = 1;
718 void s_buttonaction(int flags, char*action)
724 setbuttonrecords(stack[stackpos-1].tag);
726 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
728 syntaxerror("Couldn't compile ActionScript");
731 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
732 swf_ActionSet(stack[stackpos-1].tag, a);
733 mybutton.nr_actions++;
738 static void setactionend(TAG*tag)
740 if(!mybutton.nr_actions) {
741 /* no actions means we didn't have an actionoffset,
742 which means we can't signal the end of the
743 buttonaction records, so, *sigh*, we have
744 to insert a dummy record */
745 swf_SetU16(tag, 0); //offset
746 swf_SetU16(tag, 0); //condition
747 swf_SetU8(tag, 0); //action
751 static void s_endButton()
754 setbuttonrecords(stack[stackpos-1].tag);
755 setactionend(stack[stackpos-1].tag);
758 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
762 tag = stack[stackpos].tag;
763 currentrect = stack[stackpos].oldrect;
765 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
766 free(stack[stackpos].name);
769 TAG* removeFromTo(TAG*from, TAG*to)
771 TAG*save = from->prev;
773 TAG*next = from->next;
781 static void readParameters(history_t* history, parameters_t* p, int frame)
783 p->x = history_value(history, frame, "x");
784 p->y = history_value(history, frame, "y");
785 p->scalex = history_value(history, frame, "scalex");
786 p->scaley = history_value(history, frame, "scaley");
787 p->cxform.r0 = history_value(history, frame, "cxform.r0");
788 p->cxform.g0 = history_value(history, frame, "cxform.g0");
789 p->cxform.b0 = history_value(history, frame, "cxform.b0");
790 p->cxform.a0 = history_value(history, frame, "cxform.a0");
791 p->cxform.r1 = history_value(history, frame, "cxform.r1");
792 p->cxform.g1 = history_value(history, frame, "cxform.g1");
793 p->cxform.b1 = history_value(history, frame, "cxform.b1");
794 p->cxform.a1 = history_value(history, frame, "cxform.a1");
795 p->rotate = history_value(history, frame, "rotate");
796 p->shear = history_value(history, frame, "shear");
797 p->pivot.x = history_value(history, frame, "pivot.x");
798 p->pivot.y = history_value(history, frame, "pivot.y");
799 p->pin.x = history_value(history, frame, "pin.x");
800 p->pin.y = history_value(history, frame, "pin.y");
801 p->blendmode = history_value(history, frame, "blendmode");
802 p->filter = history_valueFilter(history, frame);
805 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move)
809 swf_GetPlaceObject(NULL, &po);
813 po.cxform = p->cxform;
819 po.blendmode = p->blendmode;
823 flist.filter[0] = p->filter;
826 swf_SetPlaceObject(tag, &po);
829 static void writeInstance(instance_t* i)
833 int frame = i->history->firstFrame;
834 TAG* tag = i->history->firstTag;
835 while (frame < currentframe)
838 readParameters(i->history, &p, frame);
839 while (tag->id != ST_SHOWFRAME)
841 m = s_instancepos(i->character->size, &p);
843 if(p.blendmode || p.filter)
844 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
846 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
847 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
853 void dumpSWF(SWF*swf)
855 TAG* tag = swf->firstTag;
856 printf("vvvvvvvvvvvvvvvvvvvvv\n");
858 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
861 printf("^^^^^^^^^^^^^^^^^^^^^\n");
864 static void s_endSprite()
866 SRECT r = currentrect;
868 if(stack[stackpos].cut)
869 tag = removeFromTo(stack[stackpos].cut, tag);
873 stringarray_t* index =dictionary_index(&instances);
875 char* name = stringarray_at(index, num);
878 i = dictionary_lookup(&instances, name);
881 name = stringarray_at(index, num);
884 tag = swf_InsertTag(tag, ST_SHOWFRAME);
885 tag = swf_InsertTag(tag, ST_END);
887 tag = stack[stackpos].tag;
890 syntaxerror("internal error(7)");
891 /* TODO: before clearing, prepend "<spritename>." to names and
892 copy into old instances dict */
893 dictionary_free_all(&instances, free_instance);
895 currentframe = stack[stackpos].oldframe;
896 currentrect = stack[stackpos].oldrect;
897 currentdepth = stack[stackpos].olddepth;
898 instances = stack[stackpos].oldinstances;
900 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
901 free(stack[stackpos].name);
904 static void s_endSWF()
911 stringarray_t* index =dictionary_index(&instances);
913 char* name = stringarray_at(index, num);
916 i = dictionary_lookup(&instances, name);
919 name = stringarray_at(index, num);
922 if(stack[stackpos].cut)
923 tag = removeFromTo(stack[stackpos].cut, tag);
927 swf = stack[stackpos].swf;
928 filename = stack[stackpos].filename;
930 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
931 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
932 tag = swf_InsertTag(tag, ST_SHOWFRAME);
934 tag = swf_InsertTag(tag, ST_END);
936 swf_OptimizeTagOrder(swf);
942 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
943 swf->movieSize = currentrect; /* "autocrop" */
946 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
947 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
948 swf->movieSize.ymax += 20;
949 warning("Empty bounding box for movie");
952 if(do_cgi || !strcmp(filename, "-"))
955 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
957 syntaxerror("couldn't create output file %s", filename);
960 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
961 else if(swf->compressed)
962 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
964 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
978 if(stack[stackpos-1].type == 0)
979 syntaxerror("End of file encountered in .flash block");
980 if(stack[stackpos-1].type == 1)
981 syntaxerror("End of file encountered in .sprite block");
982 if(stack[stackpos-1].type == 2)
983 syntaxerror("End of file encountered in .clip block");
989 return currentframe+1;
992 void s_frame(int nr, int cut, char*name, char anchor)
998 syntaxerror("Illegal frame number");
999 nr--; // internally, frame 1 is frame 0
1001 for(t=currentframe;t<nr;t++) {
1002 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1003 if(t==nr-1 && name && *name) {
1004 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1005 swf_SetString(tag, name);
1007 swf_SetU8(tag, 1); //make this an anchor
1010 if(nr == 0 && currentframe == 0 && name && *name) {
1011 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1012 swf_SetString(tag, name);
1014 swf_SetU8(tag, 1); //make this an anchor
1019 syntaxerror("Can't cut, frame empty");
1021 stack[stackpos].cut = tag;
1027 int parseColor2(char*str, RGBA*color);
1029 int addFillStyle(SHAPE*s, SRECT*r, char*name)
1033 gradient_t*gradient;
1035 if(name[0] == '#') {
1036 parseColor2(name, &color);
1037 return swf_ShapeAddSolidFillStyle(s, &color);
1038 } else if ((texture = dictionary_lookup(&textures, name))) {
1039 return swf_ShapeAddFillStyle2(s, &texture->fs);
1040 } else if((image = dictionary_lookup(&images, name))) {
1042 swf_GetMatrix(0, &m);
1043 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1044 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1047 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1048 } else if ((gradient = dictionary_lookup(&gradients, name))) {
1052 swf_GetMatrix(0, &rot);
1053 ccos = cos(-gradient->rotate*2*PI/360);
1054 csin = sin(-gradient->rotate*2*PI/360);
1055 rot.sx = ccos*65536;
1056 rot.r1 = -csin*65536;
1057 rot.r0 = csin*65536;
1058 rot.sy = ccos*65536;
1059 r2 = swf_TurnRect(*r, &rot);
1060 swf_GetMatrix(0, &m);
1061 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1062 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1063 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1064 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1065 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1066 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1067 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1068 } else if (parseColor2(name, &color)) {
1069 return swf_ShapeAddSolidFillStyle(s, &color);
1071 syntaxerror("not a color/fillstyle: %s", name);
1076 RGBA black={r:0,g:0,b:0,a:0};
1077 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
1086 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1089 linewidth = linewidth>=20?linewidth-20:0;
1090 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1093 fs1 = addFillStyle(s, &r2, texture);
1096 r.xmin = r2.xmin-linewidth/2;
1097 r.ymin = r2.ymin-linewidth/2;
1098 r.xmax = r2.xmax+linewidth/2;
1099 r.ymax = r2.ymax+linewidth/2;
1100 swf_SetRect(tag,&r);
1101 swf_SetShapeHeader(tag,s);
1102 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1103 swf_ShapeSetLine(tag,s,width,0);
1104 swf_ShapeSetLine(tag,s,0,height);
1105 swf_ShapeSetLine(tag,s,-width,0);
1106 swf_ShapeSetLine(tag,s,0,-height);
1107 swf_ShapeSetEnd(tag);
1110 s_addcharacter(name, id, tag, r);
1114 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
1120 outline = dictionary_lookup(&outlines, outlinename);
1122 syntaxerror("outline %s not defined", outlinename);
1126 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1129 linewidth = linewidth>=20?linewidth-20:0;
1130 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1133 fs1 = addFillStyle(s, &r2, texture);
1136 rect.xmin = r2.xmin-linewidth/2;
1137 rect.ymin = r2.ymin-linewidth/2;
1138 rect.xmax = r2.xmax+linewidth/2;
1139 rect.ymax = r2.ymax+linewidth/2;
1141 swf_SetRect(tag,&rect);
1142 swf_SetShapeStyles(tag, s);
1143 swf_ShapeCountBits(s,0,0);
1144 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1145 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1146 swf_SetShapeBits(tag, s);
1147 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1150 s_addcharacter(name, id, tag, rect);
1154 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
1159 r2.xmin = r2.ymin = 0;
1163 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1166 linewidth = linewidth>=20?linewidth-20:0;
1167 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1170 fs1 = addFillStyle(s, &r2, texture);
1172 rect.xmin = r2.xmin-linewidth/2;
1173 rect.ymin = r2.ymin-linewidth/2;
1174 rect.xmax = r2.xmax+linewidth/2;
1175 rect.ymax = r2.ymax+linewidth/2;
1177 swf_SetRect(tag,&rect);
1178 swf_SetShapeHeader(tag,s);
1179 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1180 swf_ShapeSetCircle(tag, s, r,r,r,r);
1181 swf_ShapeSetEnd(tag);
1184 s_addcharacter(name, id, tag, rect);
1188 void s_textshape(char*name, char*fontname, float size, char*_text)
1191 U8*text = (U8*)_text;
1195 font = dictionary_lookup(&fonts, fontname);
1197 syntaxerror("font \"%s\" not known!", fontname);
1199 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1200 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1201 s_box(name, 0, 0, black, 20, 0);
1204 g = font->ascii2glyph[text[0]];
1206 outline = malloc(sizeof(outline_t));
1207 memset(outline, 0, sizeof(outline_t));
1208 outline->shape = font->glyph[g].shape;
1209 outline->bbox = font->layout->bounds[g];
1213 swf_Shape11DrawerInit(&draw, 0);
1214 swf_DrawText(&draw, font, (int)(size*100), _text);
1216 outline->shape = swf_ShapeDrawerToShape(&draw);
1217 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1218 draw.dealloc(&draw);
1221 if(dictionary_lookup(&outlines, name))
1222 syntaxerror("outline %s defined twice", name);
1223 dictionary_put2(&outlines, name, outline);
1226 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
1231 font = dictionary_lookup(&fonts, fontname);
1233 syntaxerror("font \"%s\" not known!", fontname);
1235 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1236 swf_SetU16(tag, id);
1237 if(!font->numchars) {
1238 s_box(name, 0, 0, black, 20, 0);
1241 r = swf_SetDefineText(tag, font, &color, text, size);
1243 if(stack[0].swf->fileVersion >= 8) {
1244 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1245 swf_SetU16(tag, id);
1246 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1247 swf_SetU32(tag, 0);//thickness
1248 swf_SetU32(tag, 0);//sharpness
1249 swf_SetU8(tag, 0);//reserved
1252 s_addcharacter(name, id, tag, r);
1256 void s_quicktime(char*name, char*url)
1261 memset(&r, 0, sizeof(r));
1263 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1264 swf_SetU16(tag, id);
1265 swf_SetString(tag, url);
1267 s_addcharacter(name, id, tag, r);
1271 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)
1274 EditTextLayout layout;
1277 if(fontname && *fontname) {
1278 flags |= ET_USEOUTLINES;
1279 font = dictionary_lookup(&fonts, fontname);
1281 syntaxerror("font \"%s\" not known!", fontname);
1283 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1284 swf_SetU16(tag, id);
1285 layout.align = align;
1286 layout.leftmargin = 0;
1287 layout.rightmargin = 0;
1295 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
1297 s_addcharacter(name, id, tag, r);
1301 /* type: either "jpeg" or "png"
1303 void s_image(char*name, char*type, char*filename, int quality)
1305 /* an image is actually two folded: 1st bitmap, 2nd character.
1306 Both of them can be used separately */
1308 /* step 1: the bitmap */
1312 if(!strcmp(type,"jpeg")) {
1313 #ifndef HAVE_JPEGLIB
1314 warning("no jpeg support compiled in");
1315 s_box(name, 0, 0, black, 20, 0);
1318 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1319 swf_SetU16(tag, imageID);
1321 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1322 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1325 swf_GetJPEGSize(filename, &width, &height);
1332 s_addimage(name, id, tag, r);
1335 } else if(!strcmp(type,"png")) {
1337 swf_SetU16(tag, imageID);
1339 getPNG(filename, &width, &height, (unsigned char**)&data);
1342 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1345 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1346 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1347 swf_SetU16(tag, imageID);
1348 swf_SetLosslessImage(tag, data, width, height);
1355 s_addimage(name, id, tag, r);
1358 warning("image type \"%s\" not supported yet!", type);
1359 s_box(name, 0, 0, black, 20, 0);
1363 /* step 2: the character */
1364 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1365 swf_SetU16(tag, id);
1366 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1368 s_addcharacter(name, id, tag, r);
1372 void s_getBitmapSize(char*name, int*width, int*height)
1374 character_t* image = dictionary_lookup(&images, name);
1375 gradient_t* gradient = dictionary_lookup(&gradients,name);
1377 *width = image->size.xmax;
1378 *height = image->size.ymax;
1382 /* internal SWF gradient size */
1383 if(gradient->radial) {
1392 syntaxerror("No such bitmap/gradient: %s", name);
1395 void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1397 if(dictionary_lookup(&textures, name))
1398 syntaxerror("texture %s defined twice", name);
1399 gradient_t* gradient = dictionary_lookup(&gradients, object);
1400 character_t* bitmap = dictionary_lookup(&images, object);
1401 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1403 FILLSTYLE*fs = &texture->fs;
1405 memset(&p, 0, sizeof(parameters_t));
1408 fs->type = FILL_TILED;
1409 fs->id_bitmap = bitmap->id;
1410 } else if(gradient) {
1411 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1412 fs->gradient = gradient->gradient;
1414 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1415 makeMatrix(&fs->m, &p);
1416 if(gradient && !gradient->radial) {
1423 p2 = swf_TurnPoint(p1, &m);
1432 dictionary_put2(&textures, name, texture);
1435 void s_font(char*name, char*filename, char *glyphs)
1437 if(dictionary_lookup(&fonts, name))
1438 syntaxerror("font %s defined twice", name);
1441 font = swf_LoadFont(filename, glyphs);
1444 warning("Couldn't open font file \"%s\"", filename);
1445 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1446 memset(font, 0, sizeof(SWFFONT));
1447 dictionary_put2(&fonts, name, font);
1453 /* fix the layout. Only needed for old fonts */
1455 for(t=0;t<font->numchars;t++) {
1456 font->glyph[t].advance = 0;
1459 swf_FontCreateLayout(font);
1461 /* just in case this thing is used in .edittext later on */
1462 swf_FontPrepareForEditText(font);
1465 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1466 swf_FontSetDefine2(tag, font);
1467 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1469 swf_SetU16(tag, id);
1470 swf_SetString(tag, name);
1473 dictionary_put2(&fonts, name, font);
1478 typedef struct _sound_t
1484 void s_sound(char*name, char*filename)
1486 struct WAV wav, wav2;
1490 unsigned numsamples = 1;
1491 unsigned blocksize = 1152;
1494 if(dictionary_lookup(&sounds, name))
1495 syntaxerror("sound %s defined twice", name);
1497 if(wav_read(&wav, filename))
1500 wav_convert2mono(&wav, &wav2, 44100);
1501 samples = (U16*)wav2.data;
1502 numsamples = wav2.size/2;
1504 #ifdef WORDS_BIGENDIAN
1506 for(t=0;t<numsamples;t++)
1507 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1511 if(mp3_read(&mp3, filename))
1513 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1519 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1524 if(numsamples%blocksize != 0)
1526 // apply padding, so that block is a multiple of blocksize
1527 int numblocks = (numsamples+blocksize-1)/blocksize;
1530 numsamples2 = numblocks * blocksize;
1531 samples2 = malloc(sizeof(U16)*numsamples2);
1532 memcpy(samples2, samples, numsamples*sizeof(U16));
1533 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1534 numsamples = numsamples2;
1539 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1540 swf_SetU16(tag, id); //id
1543 swf_SetSoundDefineMP3(
1544 tag, mp3.data, mp3.size,
1551 swf_SetSoundDefine(tag, samples, numsamples);
1553 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1554 swf_SetU16(tag, id);
1555 swf_SetString(tag, name);
1556 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1558 swf_SetU16(tag, id);
1559 swf_SetString(tag, name);
1561 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1565 dictionary_put2(&sounds, name, sound);
1573 static char* gradient_getToken(const char**p)
1577 while(**p && strchr(" \t\n\r", **p)) {
1581 while(**p && !strchr(" \t\n\r", **p)) {
1584 result = malloc((*p)-start+1);
1585 memcpy(result,start,(*p)-start+1);
1586 result[(*p)-start] = 0;
1590 float parsePercent(char*str);
1591 RGBA parseColor(char*str);
1593 GRADIENT parseGradient(const char*str)
1597 const char* p = str;
1598 memset(&gradient, 0, sizeof(GRADIENT));
1599 gradient.ratios = rfx_calloc(16*sizeof(U8));
1600 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1604 char*posstr,*colorstr;
1607 posstr = gradient_getToken(&p);
1613 pos = (int)(parsePercent(posstr)*255.0);
1618 rfx_free(gradient.ratios);
1619 rfx_free(gradient.rgba);
1621 syntaxerror("Error in shape data: Color expected after %s", posstr);
1623 colorstr = gradient_getToken(&p);
1624 color = parseColor(colorstr);
1625 if(gradient.num == 16)
1627 warning("gradient record too big- max size is 16, rest ignored");
1630 gradient.ratios[gradient.num] = pos;
1631 gradient.rgba[gradient.num] = color;
1640 void s_gradient(char*name, const char*text, int radial, int rotate)
1642 gradient_t* gradient;
1643 gradient = malloc(sizeof(gradient_t));
1644 memset(gradient, 0, sizeof(gradient_t));
1645 gradient->gradient = parseGradient(text);
1646 gradient->radial = radial;
1647 gradient->rotate = rotate;
1649 dictionary_put2(&gradients, name, gradient);
1652 void s_gradientglow(char*name, char*gradient, float blurx, float blury,
1653 float angle, float distance, float strength, char innershadow,
1654 char knockout, char composite, char ontop, int passes)
1656 if(dictionary_lookup(&filters, name))
1657 syntaxerror("filter %s defined twice", name);
1659 gradient_t* g = dictionary_lookup(&gradients, gradient);
1664 syntaxerror("unknown gradient %s", gradient);
1665 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1666 filter->type = FILTERTYPE_GRADIENTGLOW;
1667 filter->gradient = &g->gradient;
1668 filter->blurx = blurx;
1669 filter->blury = blury;
1670 filter->strength = strength;
1671 filter->angle = angle;
1672 filter->distance = distance;
1673 filter->innershadow = innershadow;
1674 filter->knockout = knockout;
1675 filter->composite = composite;
1676 filter->ontop = ontop;
1677 filter->passes = passes;
1679 dictionary_put2(&filters, name, filter);
1682 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)
1684 if(dictionary_lookup(&filters, name))
1685 syntaxerror("filter %s defined twice", name);
1688 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1689 filter->type = FILTERTYPE_DROPSHADOW;
1690 filter->color= color;
1691 filter->blurx = blurx;
1692 filter->blury = blury;
1693 filter->strength = strength;
1694 filter->angle = angle;
1695 filter->distance = distance;
1696 filter->innershadow = innershadow;
1697 filter->knockout = knockout;
1698 filter->composite = composite;
1699 filter->passes = passes;
1701 dictionary_put2(&filters, name, filter);
1704 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)
1706 if(dictionary_lookup(&filters, name))
1707 syntaxerror("filter %s defined twice", name);
1710 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1711 filter->type = FILTERTYPE_BEVEL;
1712 filter->shadow = shadow;
1713 filter->highlight = highlight;
1714 filter->blurx = blurx;
1715 filter->blury = blury;
1716 filter->strength = strength;
1717 filter->angle = angle;
1718 filter->distance = distance;
1719 filter->innershadow = innershadow;
1720 filter->knockout = knockout;
1721 filter->composite = composite;
1722 filter->ontop = ontop;
1723 filter->passes = passes;
1725 dictionary_put2(&filters, name, filter);
1728 void s_blur(char*name, double blurx, double blury, int passes)
1730 if(dictionary_lookup(&filters, name))
1731 syntaxerror("filter %s defined twice", name);
1733 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1734 filter->type = FILTERTYPE_BLUR;
1735 filter->blurx = blurx;
1736 filter->blury = blury;
1737 filter->passes = passes;
1739 dictionary_put2(&filters, name, filter);
1742 void s_action(const char*text)
1745 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1749 syntaxerror("Couldn't compile ActionScript");
1752 tag = swf_InsertTag(tag, ST_DOACTION);
1754 swf_ActionSet(tag, a);
1759 void s_initaction(const char*character, const char*text)
1763 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1767 syntaxerror("Couldn't compile ActionScript");
1770 c = (character_t*)dictionary_lookup(&characters, character);
1772 tag = swf_InsertTag(tag, ST_DOINITACTION);
1773 swf_SetU16(tag, c->id);
1774 swf_ActionSet(tag, a);
1779 int s_swf3action(char*name, char*action)
1782 instance_t* object = 0;
1784 object = (instance_t*)dictionary_lookup(&instances, name);
1785 if(!object && name && *name) {
1786 /* we have a name, but couldn't find it. Abort. */
1789 a = action_SetTarget(0, name);
1790 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1791 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1792 else if(!strcmp(action, "stop")) a = action_Stop(a);
1793 else if(!strcmp(action, "play")) a = action_Play(a);
1794 a = action_SetTarget(a, "");
1797 tag = swf_InsertTag(tag, ST_DOACTION);
1798 swf_ActionSet(tag, a);
1803 void s_outline(char*name, char*format, char*source)
1805 if(dictionary_lookup(&outlines, name))
1806 syntaxerror("outline %s defined twice", name);
1815 //swf_Shape10DrawerInit(&draw, 0);
1816 swf_Shape11DrawerInit(&draw, 0);
1818 draw_string(&draw, source);
1820 shape = swf_ShapeDrawerToShape(&draw);
1821 bounds = swf_ShapeDrawerGetBBox(&draw);
1822 draw.dealloc(&draw);
1824 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1825 outline->shape = shape;
1826 outline->bbox = bounds;
1828 dictionary_put2(&outlines, name, outline);
1831 int s_playsound(char*name, int loops, int nomultiple, int stop)
1837 sound = dictionary_lookup(&sounds, name);
1841 tag = swf_InsertTag(tag, ST_STARTSOUND);
1842 swf_SetU16(tag, sound->id); //id
1843 memset(&info, 0, sizeof(info));
1846 info.nomultiple = nomultiple;
1847 swf_SetSoundInfo(tag, &info);
1851 void s_includeswf(char*name, char*filename)
1859 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1860 f = open(filename,O_RDONLY|O_BINARY);
1862 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1863 s_box(name, 0, 0, black, 20, 0);
1866 if (swf_ReadSWF(f,&swf)<0) {
1867 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1868 s_box(name, 0, 0, black, 20, 0);
1873 /* FIXME: The following sets the bounding Box for the character.
1874 It is wrong for two reasons:
1875 a) It may be too small (in case objects in the movie clip at the borders)
1876 b) it may be too big (because the poor movie never got autocropped)
1880 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1881 swf_SetU16(tag, id);
1882 swf_SetU16(tag, swf.frameCount);
1884 swf_Relocate(&swf, idmap);
1886 ftag = swf.firstTag;
1890 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1891 if(cutout[t] == ftag->id) {
1895 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1897 if(ftag->id == ST_END)
1902 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
1903 /* We simply dump all tags right after the sprite
1904 header, relying on the fact that swf_OptimizeTagOrder() will
1905 sort things out for us later.
1906 We also rely on the fact that the imported SWF is well-formed.
1908 tag = swf_InsertTag(tag, ftag->id);
1909 swf_SetBlock(tag, ftag->data, ftag->len);
1915 syntaxerror("Included file %s contains errors", filename);
1916 tag = swf_InsertTag(tag, ST_END);
1920 s_addcharacter(name, id, tag, r);
1923 SRECT s_getCharBBox(char*name)
1925 character_t* c = dictionary_lookup(&characters, name);
1926 if(!c) syntaxerror("character '%s' unknown(2)", name);
1929 SRECT s_getInstanceBBox(char*name)
1931 instance_t * i = dictionary_lookup(&instances, name);
1933 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1935 if(!c) syntaxerror("internal error(5)");
1938 parameters_t s_getParameters(char*name)
1940 instance_t * i = dictionary_lookup(&instances, name);
1941 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1942 return i->parameters;
1944 void s_startclip(char*instance, char*character, parameters_t p)
1946 character_t* c = dictionary_lookup(&characters, character);
1950 syntaxerror("character %s not known", character);
1952 i = s_addinstance(instance, c, currentdepth);
1954 m = s_instancepos(i->character->size, &p);
1956 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1957 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1958 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1960 i->lastFrame= currentframe;
1962 stack[stackpos].tag = tag;
1963 stack[stackpos].type = 2;
1972 swf_SetTagPos(stack[stackpos].tag, 0);
1973 swf_GetPlaceObject(stack[stackpos].tag, &p);
1974 p.clipdepth = currentdepth;
1976 swf_ClearTag(stack[stackpos].tag);
1977 swf_SetPlaceObject(stack[stackpos].tag, &p);
1981 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
1983 history_begin(i->history, "x", currentframe, tag, p->x);
1984 history_begin(i->history, "y", currentframe, tag, p->y);
1985 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
1986 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
1987 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
1988 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
1989 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
1990 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
1991 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
1992 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
1993 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
1994 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
1995 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
1996 history_begin(i->history, "shear", currentframe, tag, p->shear);
1997 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
1998 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
1999 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2000 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2001 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2002 history_beginFilter(i->history, currentframe, tag, p->filter);
2005 void s_put(char*instance, char*character, parameters_t p)
2007 character_t* c = dictionary_lookup(&characters, character);
2011 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2013 i = s_addinstance(instance, c, currentdepth);
2015 m = s_instancepos(i->character->size, &p);
2017 if(p.blendmode || p.filter)
2019 if(stack[0].swf->fileVersion < 8)
2022 warning("blendmodes only supported for flash version>=8");
2024 warning("filters only supported for flash version>=8");
2026 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2029 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2030 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2031 setStartparameters(i, &p, tag);
2033 i->lastFrame = currentframe;
2037 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2040 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2042 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2043 if (p.set & SF_SCALEX)
2044 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2045 if (p.set & SF_SCALEY)
2046 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2047 if (p.set & SF_CX_R)
2049 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2050 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2052 if (p.set & SF_CX_G)
2054 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2055 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2057 if (p.set & SF_CX_B)
2059 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2060 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2062 if (p.set & SF_CX_A)
2064 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2065 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2067 if (p.set & SF_ROTATE)
2068 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2069 if (p.set & SF_SHEAR)
2070 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2071 if (p.set & SF_PIVOT)
2073 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2074 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2078 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2079 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2081 if (p.set & SF_BLEND)
2082 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2083 if (p.set & SF_FILTER)
2084 history_rememberFilter(history, currentframe, changeFunction, p.filter, inter);
2087 void s_jump(char* instance, parameters_t p)
2089 instance_t* i = dictionary_lookup(&instances, instance);
2091 syntaxerror("instance %s not known", instance);
2092 recordChanges(i->history, p, CF_JUMP, 0);
2095 void s_change(char*instance, parameters_t p2, interpolation_t* inter)
2097 instance_t* i = dictionary_lookup(&instances, instance);
2099 syntaxerror("instance %s not known", instance);
2100 recordChanges(i->history, p2, CF_CHANGE, inter);
2103 void s_delinstance(char*instance)
2105 instance_t* i = dictionary_lookup(&instances, instance);
2107 syntaxerror("instance %s not known", instance);
2108 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2109 swf_SetU16(tag, i->depth);
2110 dictionary_del(&instances, instance);
2113 void s_qchange(char*instance, parameters_t p)
2115 instance_t* i = dictionary_lookup(&instances, instance);
2117 syntaxerror("instance %s not known", instance);
2118 recordChanges(i->history, p, CF_QCHANGE, 0);
2124 syntaxerror(".end unexpected");
2125 switch (stack[stackpos-1].type)
2140 syntaxerror("internal error 1");
2144 // ------------------------------------------------------------------------
2146 typedef int command_func_t(map_t*args);
2148 SRECT parseBox(char*str)
2150 SRECT r = {0,0,0,0};
2151 float xmin, xmax, ymin, ymax;
2152 char*x = strchr(str, 'x');
2154 if(!strcmp(str, "autocrop")) {
2155 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2159 d1 = strchr(x+1, ':');
2161 d2 = strchr(d1+1, ':');
2163 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2167 else if(d1 && !d2) {
2168 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2174 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2179 r.xmin = (SCOORD)(xmin*20);
2180 r.ymin = (SCOORD)(ymin*20);
2181 r.xmax = (SCOORD)(xmax*20);
2182 r.ymax = (SCOORD)(ymax*20);
2185 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2188 float parseFloat(char*str)
2192 int parseInt(char*str)
2197 if(str[0]=='+' || str[0]=='-')
2201 if(str[t]<'0' || str[t]>'9')
2202 syntaxerror("Not an Integer: \"%s\"", str);
2205 int parseTwip(char*str)
2209 if(str[0]=='+' || str[0]=='-') {
2214 dot = strchr(str, '.');
2218 return sign*parseInt(str)*20;
2220 char* old = strdup(str);
2221 int l=strlen(dot+1);
2224 for(s=str;s<dot-1;s++)
2225 if(*s<'0' || *s>'9')
2228 syntaxerror("Not a coordinate: \"%s\"", str);
2231 if(*s<'0' || *s>'9')
2234 syntaxerror("Not a coordinate: \"%s\"", str);
2236 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2237 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2240 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2244 return sign*atoi(str)*20;
2246 return sign*atoi(str)*20+atoi(dot)*2;
2248 return sign*atoi(str)*20+atoi(dot)/5;
2253 int isPoint(char*str)
2255 if(strchr(str, '('))
2261 SPOINT parsePoint(char*str)
2265 int l = strlen(str);
2266 char*comma = strchr(str, ',');
2267 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2268 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2269 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2270 p.x = parseTwip(tmp);
2271 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2272 p.y = parseTwip(tmp);
2276 int parseColor2(char*str, RGBA*color)
2278 int l = strlen(str);
2282 struct {unsigned char r,g,b;char*name;} colors[] =
2283 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2284 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2285 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2286 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2287 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2288 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2289 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2290 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2291 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2292 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2293 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2294 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2298 if(str[0]=='#' && (l==7 || l==9)) {
2299 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2301 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2303 color->r = r; color->g = g; color->b = b; color->a = a;
2306 int len=strlen(str);
2308 if(strchr(str, '/')) {
2309 len = strchr(str, '/')-str;
2310 sscanf(str+len+1,"%02x", &alpha);
2312 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2313 if(!strncmp(str, colors[t].name, len)) {
2318 color->r = r; color->g = g; color->b = b; color->a = a;
2324 RGBA parseColor(char*str)
2327 if(!parseColor2(str, &c))
2328 syntaxerror("Expression '%s' is not a color", str);
2332 typedef struct _muladd {
2337 MULADD parseMulAdd(char*str)
2340 char* str2 = (char*)malloc(strlen(str)+5);
2347 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2348 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2349 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2350 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2351 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2352 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2353 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2354 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2355 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2356 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2358 syntaxerror("'%s' is not a valid color transform expression", str);
2360 m.add = (int)(add*256);
2361 m.mul = (int)(mul*256);
2366 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2368 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2369 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2371 if(a<-32768) a=-32768;
2372 if(a>32767) a=32767;
2373 if(m<-32768) m=-32768;
2374 if(m>32767) m=32767;
2380 float parsePxOrPercent(char*fontname, char*str)
2382 int l = strlen(str);
2383 if(strchr(str, '%'))
2384 return parsePercent(str);
2385 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2386 float p = atof(str);
2387 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2389 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2393 float parsePercent(char*str)
2395 int l = strlen(str);
2399 return atoi(str)/100.0;
2401 syntaxerror("Expression '%s' is not a percentage", str);
2404 int isPercent(char*str)
2406 return str[strlen(str)-1]=='%';
2408 int parseNewSize(char*str, int size)
2411 return parsePercent(str)*size;
2413 return (int)(atof(str)*20);
2416 int isColor(char*str)
2419 return parseColor2(str, &c);
2422 static char* lu(map_t* args, char*name)
2424 char* value = map_lookup(args, name);
2426 map_dump(args, stdout, "");
2427 syntaxerror("internal error 2: value %s should be set", name);
2432 static int c_flash(map_t*args)
2434 char* filename = map_lookup(args, "filename");
2435 char* compressstr = lu(args, "compress");
2436 SRECT bbox = parseBox(lu(args, "bbox"));
2437 int version = parseInt(lu(args, "version"));
2438 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2440 RGBA color = parseColor(lu(args, "background"));
2442 if(!filename || !*filename) {
2443 /* for compatibility */
2444 filename = map_lookup(args, "name");
2445 if(!filename || !*filename) {
2448 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2449 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2453 if(!filename || override_outputname)
2454 filename = outputname;
2456 if(!strcmp(compressstr, "default"))
2457 compress = version>=6;
2458 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2460 else if(!strcmp(compressstr, "no"))
2462 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2464 s_swf(filename, bbox, version, fps, compress, color);
2467 int isRelative(char*str)
2469 return !strncmp(str, "<plus>", 6) ||
2470 !strncmp(str, "<minus>", 7);
2472 char* getOffset(char*str)
2474 if(!strncmp(str, "<plus>", 6))
2476 if(!strncmp(str, "<minus>", 7))
2478 syntaxerror("internal error (347)");
2481 int getSign(char*str)
2483 if(!strncmp(str, "<plus>", 6))
2485 if(!strncmp(str, "<minus>", 7))
2487 syntaxerror("internal error (348)");
2490 static dictionary_t points;
2491 static mem_t mpoints;
2492 int points_initialized = 0;
2494 static int c_interpolation(map_t *args)
2497 char* name = lu(args, "name");
2498 if (dictionary_lookup(&interpolations, name))
2499 syntaxerror("interpolation %s defined twice", name);
2501 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2502 char* functionstr = lu(args, "function");
2503 inter->function = 0;
2504 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2505 if (!strcmp(functionstr,interpolationFunctions[i]))
2507 inter->function = i + 1;
2510 if (!inter->function)
2511 syntaxerror("unkown interpolation function %s", functionstr);
2512 inter->speed = parseFloat(lu(args, "speed"));
2513 inter->amplitude = parseFloat(lu(args, "amplitude"));
2514 inter->growth = parseFloat(lu(args, "growth"));
2515 inter->bounces = parseInt(lu(args, "bounces"));
2516 inter->damping = parseInt(lu(args, "damping"));
2518 dictionary_put2(&interpolations, name, inter);
2522 SPOINT getPoint(SRECT r, char*name)
2525 if(!strcmp(name, "center")) {
2527 p.x = (r.xmin + r.xmax)/2;
2528 p.y = (r.ymin + r.ymax)/2;
2532 if(points_initialized)
2533 l = (int)dictionary_lookup(&points, name);
2535 syntaxerror("Invalid point: \"%s\".", name);
2538 return *(SPOINT*)&mpoints.buffer[l];
2541 static int texture2(char*name, char*object, map_t*args, int errors)
2544 char*xstr = map_lookup(args, "x");
2545 char*ystr = map_lookup(args, "y");
2546 char*widthstr = map_lookup(args, "width");
2547 char*heightstr = map_lookup(args, "height");
2548 char*scalestr = map_lookup(args, "scale");
2549 char*scalexstr = map_lookup(args, "scalex");
2550 char*scaleystr = map_lookup(args, "scaley");
2551 char*rotatestr = map_lookup(args, "rotate");
2552 char* shearstr = map_lookup(args, "shear");
2553 char* radiusstr = map_lookup(args, "r");
2555 float scalex = 1.0, scaley = 1.0;
2556 float rotate=0, shear=0;
2558 if(!*xstr && !*ystr) {
2560 syntaxerror("x and y must be set");
2563 if(*scalestr && (*scalexstr || *scaleystr)) {
2564 syntaxerror("scale and scalex/scaley can't both be set");
2567 if((*widthstr || *heightstr) && *radiusstr) {
2568 syntaxerror("width/height and radius can't both be set");
2571 widthstr = radiusstr;
2572 heightstr = radiusstr;
2574 if(!*xstr) xstr="0";
2575 if(!*ystr) ystr="0";
2576 if(!*rotatestr) rotatestr="0";
2577 if(!*shearstr) shearstr="0";
2580 scalex = scaley = parsePercent(scalestr);
2581 } else if(*scalexstr || *scaleystr) {
2582 if(scalexstr) scalex = parsePercent(scalexstr);
2583 if(scaleystr) scaley = parsePercent(scaleystr);
2584 } else if(*widthstr || *heightstr) {
2587 s_getBitmapSize(object, &width, &height);
2589 scalex = (float)parseTwip(widthstr)/(float)width;
2591 scaley = (float)parseTwip(heightstr)/(float)height;
2593 x = parseTwip(xstr);
2594 y = parseTwip(ystr);
2595 rotate = parseFloat(rotatestr);
2596 shear = parseFloat(shearstr);
2598 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2603 static int c_texture(map_t*args)
2605 char*name = lu(args, "instance");
2606 char*object = lu(args, "character");
2607 return texture2(name, object, args, 1);
2610 static int c_gradient(map_t*args)
2612 char*name = lu(args, "name");
2613 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2614 int rotate = parseInt(lu(args, "rotate"));
2618 syntaxerror("colon (:) expected");
2620 if(dictionary_lookup(&gradients, name))
2621 syntaxerror("gradient %s defined twice", name);
2623 s_gradient(name, text, radial, rotate);
2625 /* check whether we also have placement information,
2626 which would make this a positioned gradient.
2627 If there is placement information, texture2() will
2628 add a texture, which has priority over the gradient.
2630 texture2(name, name, args, 0);
2634 static int c_blur(map_t*args)
2636 char*name = lu(args, "name");
2637 char*blurstr = lu(args, "blur");
2638 char*blurxstr = lu(args, "blurx");
2639 char*blurystr = lu(args, "blury");
2640 float blurx=1.0, blury=1.0;
2642 blurx = parseFloat(blurstr);
2643 blury = parseFloat(blurstr);
2646 blurx = parseFloat(blurxstr);
2648 blury = parseFloat(blurystr);
2649 int passes = parseInt(lu(args, "passes"));
2650 s_blur(name, blurx, blury, passes);
2654 static int c_gradientglow(map_t*args)
2656 char*name = lu(args, "name");
2657 char*gradient = lu(args, "gradient");
2658 char*blurstr = lu(args, "blur");
2659 char*blurxstr = lu(args, "blurx");
2660 char*blurystr = lu(args, "blury");
2661 float blurx=1.0, blury=1.0;
2663 blurx = parseFloat(blurstr);
2664 blury = parseFloat(blurstr);
2667 blurx = parseFloat(blurxstr);
2669 blury = parseFloat(blurystr);
2671 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2672 float distance = parseFloat(lu(args, "distance"));
2673 float strength = parseFloat(lu(args, "strength"));
2674 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2675 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2676 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2677 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2678 int passes = parseInt(lu(args, "passes"));
2680 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2684 static int c_dropshadow(map_t*args)
2686 char*name = lu(args, "name");
2687 RGBA color = parseColor(lu(args, "color"));
2688 char*blurstr = lu(args, "blur");
2689 char*blurxstr = lu(args, "blurx");
2690 char*blurystr = lu(args, "blury");
2691 float blurx=1.0, blury=1.0;
2693 blurx = parseFloat(blurstr);
2694 blury = parseFloat(blurstr);
2697 blurx = parseFloat(blurxstr);
2699 blury = parseFloat(blurystr);
2701 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2702 float distance = parseFloat(lu(args, "distance"));
2703 float strength = parseFloat(lu(args, "strength"));
2704 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2705 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2706 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2707 int passes = parseInt(lu(args, "passes"));
2709 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
2713 static int c_bevel(map_t*args)
2715 char*name = lu(args, "name");
2716 RGBA shadow = parseColor(lu(args, "shadow"));
2717 RGBA highlight = parseColor(lu(args, "highlight"));
2718 char*blurstr = lu(args, "blur");
2719 char*blurxstr = lu(args, "blurx");
2720 char*blurystr = lu(args, "blury");
2721 float blurx=1.0, blury=1.0;
2723 blurx = parseFloat(blurstr);
2724 blury = parseFloat(blurstr);
2727 blurx = parseFloat(blurxstr);
2729 blury = parseFloat(blurystr);
2731 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2732 float distance = parseFloat(lu(args, "distance"));
2733 float strength = parseFloat(lu(args, "strength"));
2734 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2735 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2736 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2737 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2738 int passes = parseInt(lu(args, "passes"));
2740 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2744 static int c_point(map_t*args)
2746 char*name = lu(args, "name");
2750 if(!points_initialized) {
2751 dictionary_init(&points);
2753 points_initialized = 1;
2755 p.x = parseTwip(lu(args, "x"));
2756 p.y = parseTwip(lu(args, "y"));
2757 pos = mem_put(&mpoints, &p, sizeof(p));
2758 string_set(&s1, name);
2760 dictionary_put(&points, s1, (void*)pos);
2763 static int c_play(map_t*args)
2765 char*name = lu(args, "name");
2766 char*loop = lu(args, "loop");
2767 char*nomultiple = lu(args, "nomultiple");
2769 if(!strcmp(nomultiple, "nomultiple"))
2772 nm = parseInt(nomultiple);
2774 if(s_playsound(name, parseInt(loop), nm, 0)) {
2776 } else if(s_swf3action(name, "play")) {
2782 static int c_stop(map_t*args)
2784 char*name = map_lookup(args, "name");
2786 if(s_playsound(name, 0,0,1))
2788 else if(s_swf3action(name, "stop"))
2790 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
2794 static int c_nextframe(map_t*args)
2796 char*name = lu(args, "name");
2798 if(s_swf3action(name, "nextframe")) {
2801 syntaxerror("I don't know anything about movie \"%s\"", name);
2805 static int c_previousframe(map_t*args)
2807 char*name = lu(args, "name");
2809 if(s_swf3action(name, "previousframe")) {
2812 syntaxerror("I don't know anything about movie \"%s\"", name);
2816 static int c_placement(map_t*args, int type)
2818 char*instance = lu(args, (type==0||type==4)?"instance":"name");
2821 char* luminancestr = lu(args, "luminance");
2822 char* scalestr = lu(args, "scale");
2823 char* scalexstr = lu(args, "scalex");
2824 char* scaleystr = lu(args, "scaley");
2825 char* rotatestr = lu(args, "rotate");
2826 char* shearstr = lu(args, "shear");
2827 char* xstr="", *pivotstr="";
2828 char* ystr="", *anglestr="";
2829 char*above = lu(args, "above"); /*FIXME*/
2830 char*below = lu(args, "below");
2831 char* rstr = lu(args, "red");
2832 char* gstr = lu(args, "green");
2833 char* bstr = lu(args, "blue");
2834 char* astr = lu(args, "alpha");
2835 char* pinstr = lu(args, "pin");
2836 char* as = map_lookup(args, "as");
2837 char* blendmode = lu(args, "blend");
2838 char* filterstr = lu(args, "filter");
2846 U32 set = 0x00000000;
2849 { // (?) .rotate or .arcchange
2850 pivotstr = lu(args, "pivot");
2851 anglestr = lu(args, "angle");
2855 xstr = lu(args, "x");
2856 ystr = lu(args, "y");
2860 luminance = parseMulAdd(luminancestr);
2864 luminance.mul = 256;
2869 if(scalexstr[0]||scaleystr[0])
2870 syntaxerror("scalex/scaley and scale cannot both be set");
2871 scalexstr = scaleystr = scalestr;
2874 if(type == 0 || type == 4) {
2876 character = lu(args, "character");
2877 parameters_clear(&p);
2878 } else if (type == 5) {
2879 character = lu(args, "name");
2880 parameters_clear(&p);
2883 p = s_getParameters(instance);
2889 if(isRelative(xstr))
2891 if(type == 0 || type == 4)
2892 syntaxerror("relative x values not allowed for initial put or startclip");
2893 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2897 p.x = parseTwip(xstr);
2903 if(isRelative(ystr))
2905 if(type == 0 || type == 4)
2906 syntaxerror("relative y values not allowed for initial put or startclip");
2907 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2911 p.y = parseTwip(ystr);
2916 /* scale, scalex, scaley */
2918 oldbbox = s_getCharBBox(character);
2920 oldbbox = s_getInstanceBBox(instance);
2921 oldwidth = oldbbox.xmax - oldbbox.xmin;
2922 oldheight = oldbbox.ymax - oldbbox.ymin;
2929 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2930 set = set | SF_SCALEX;
2938 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2939 set = set | SF_SCALEY;
2945 if(isRelative(rotatestr))
2946 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2948 p.rotate = parseFloat(rotatestr);
2949 set = set | SF_ROTATE;
2955 if(isRelative(shearstr))
2956 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2958 p.shear = parseFloat(shearstr);
2959 set = set | SF_SHEAR;
2964 if(isPoint(pivotstr))
2965 p.pivot = parsePoint(pivotstr);
2967 p.pivot = getPoint(oldbbox, pivotstr);
2968 set = set | SF_PIVOT;
2974 p.pin = parsePoint(pinstr);
2976 p.pin = getPoint(oldbbox, pinstr);
2980 /* color transform */
2982 if(rstr[0] || luminancestr[0])
2986 r = parseMulAdd(rstr);
2989 r.add = p.cxform.r0;
2990 r.mul = p.cxform.r1;
2992 r = mergeMulAdd(r, luminance);
2993 p.cxform.r0 = r.mul;
2994 p.cxform.r1 = r.add;
2995 set = set | SF_CX_R;
2997 if(gstr[0] || luminancestr[0])
3001 g = parseMulAdd(gstr);
3004 g.add = p.cxform.g0;
3005 g.mul = p.cxform.g1;
3007 g = mergeMulAdd(g, luminance);
3008 p.cxform.g0 = g.mul;
3009 p.cxform.g1 = g.add;
3010 set = set | SF_CX_G;
3012 if(bstr[0] || luminancestr[0])
3016 b = parseMulAdd(bstr);
3019 b.add = p.cxform.b0;
3020 b.mul = p.cxform.b1;
3022 b = mergeMulAdd(b, luminance);
3023 p.cxform.b0 = b.mul;
3024 p.cxform.b1 = b.add;
3025 set = set | SF_CX_B;
3029 MULADD a = parseMulAdd(astr);
3030 p.cxform.a0 = a.mul;
3031 p.cxform.a1 = a.add;
3032 set = set | SF_CX_A;
3039 for(t = 0; blendModeNames[t]; t++)
3041 if(!strcmp(blendModeNames[t], blendmode))
3049 syntaxerror("unknown blend mode: '%s'", blendmode);
3051 p.blendmode = blend;
3052 set = set | SF_BLEND;
3057 FILTER*f = dictionary_lookup(&filters, filterstr);
3059 syntaxerror("Unknown filter %s", filterstr);
3061 set = set | SF_FILTER;
3069 s_put(instance, character, p);
3073 char* interstr = lu(args, "interpolation");
3074 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3076 syntaxerror("unkown interpolation %s", interstr);
3077 s_change(instance, p, inter);
3081 s_qchange(instance, p);
3084 s_jump(instance, p);
3087 s_startclip(instance, character, p);
3091 s_buttonput(character, as, p);
3093 s_buttonput(character, "shape", p);
3099 static int c_put(map_t*args)
3101 c_placement(args, 0);
3104 static int c_change(map_t*args)
3106 if (currentframe == 0)
3107 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3108 c_placement(args, 1);
3111 static int c_qchange(map_t*args)
3113 c_placement(args, 2);
3116 static int c_arcchange(map_t*args)
3118 c_placement(args, 2);
3121 static int c_jump(map_t*args)
3123 c_placement(args, 3);
3126 static int c_startclip(map_t*args)
3128 c_placement(args, 4);
3131 static int c_show(map_t*args)
3133 c_placement(args, 5);
3136 static int c_del(map_t*args)
3138 char*instance = lu(args, "name");
3139 s_delinstance(instance);
3142 static int c_end(map_t*args)
3147 static int c_sprite(map_t*args)
3149 char* name = lu(args, "name");
3153 static int c_frame(map_t*args)
3155 char*framestr = lu(args, "n");
3156 char*cutstr = lu(args, "cut");
3158 char*name = lu(args, "name");
3159 char*anchor = lu(args, "anchor");
3162 if(!strcmp(anchor, "anchor") && !*name)
3167 if(strcmp(cutstr, "no"))
3169 if(isRelative(framestr)) {
3170 frame = s_getframe();
3171 if(getSign(framestr)<0)
3172 syntaxerror("relative frame expressions must be positive");
3173 frame += parseInt(getOffset(framestr));
3176 frame = parseInt(framestr);
3177 if(s_getframe() >= frame
3178 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3179 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3181 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3184 static int c_primitive(map_t*args)
3186 char*name = lu(args, "name");
3187 char*command = lu(args, "commandname");
3188 int width=0, height=0, r=0;
3189 int linewidth = parseTwip(lu(args, "line"));
3190 char*colorstr = lu(args, "color");
3191 RGBA color = parseColor(colorstr);
3192 char*fillstr = lu(args, "fill");
3199 if(!strcmp(command, "circle"))
3201 else if(!strcmp(command, "filled"))
3205 width = parseTwip(lu(args, "width"));
3206 height = parseTwip(lu(args, "height"));
3207 } else if (type==1) {
3208 r = parseTwip(lu(args, "r"));
3209 } else if (type==2) {
3210 outline = lu(args, "outline");
3213 if(!strcmp(fillstr, "fill"))
3215 if(!strcmp(fillstr, "none"))
3217 if(width<0 || height<0 || linewidth<0 || r<0)
3218 syntaxerror("values width, height, line, r must be positive");
3220 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3221 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3222 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3226 static int c_textshape(map_t*args)
3228 char*name = lu(args, "name");
3229 char*text = lu(args, "text");
3230 char*font = lu(args, "font");
3231 float size = parsePxOrPercent(font, lu(args, "size"));
3233 s_textshape(name, font, size, text);
3237 static int c_swf(map_t*args)
3239 char*name = lu(args, "name");
3240 char*filename = lu(args, "filename");
3241 char*command = lu(args, "commandname");
3242 if(!strcmp(command, "shape"))
3243 warning("Please use .swf instead of .shape");
3244 s_includeswf(name, filename);
3248 static int c_font(map_t*args)
3250 char*name = lu(args, "name");
3251 char*filename = lu(args, "filename");
3252 fontData* usage = getFontData(name);
3253 char* glyphs = usage->glyphs;
3254 if (usage->needsAll)
3259 printf("font %s was defined but not used\n", name);
3262 s_font(name, filename, glyphs);
3266 static int c_sound(map_t*args)
3268 char*name = lu(args, "name");
3269 char*filename = lu(args, "filename");
3270 s_sound(name, filename);
3274 static int c_text(map_t*args)
3276 char*name = lu(args, "name");
3277 char*text = lu(args, "text");
3278 char*font = lu(args, "font");
3279 float size = parsePxOrPercent(font, lu(args, "size"));
3280 RGBA color = parseColor(lu(args, "color"));
3281 s_text(name, font, text, (int)(size*100), color);
3285 static int c_soundtrack(map_t*args)
3290 static int c_quicktime(map_t*args)
3292 char*name = lu(args, "name");
3293 char*url = lu(args, "url");
3294 s_quicktime(name, url);
3298 static int c_image(map_t*args)
3300 char*command = lu(args, "commandname");
3301 char*name = lu(args, "name");
3302 char*filename = lu(args, "filename");
3303 if(!strcmp(command,"jpeg")) {
3304 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3305 s_image(name, "jpeg", filename, quality);
3307 s_image(name, "png", filename, 0);
3312 static int c_outline(map_t*args)
3314 char*name = lu(args, "name");
3315 char*format = lu(args, "format");
3319 syntaxerror("colon (:) expected");
3321 s_outline(name, format, text);
3325 int fakechar(map_t*args)
3327 char*name = lu(args, "name");
3328 s_box(name, 0, 0, black, 20, 0);
3332 static int c_egon(map_t*args) {return fakechar(args);}
3333 static int c_button(map_t*args) {
3334 char*name = lu(args, "name");
3338 static int current_button_flags = 0;
3339 static int c_on_press(map_t*args)
3341 char*position = lu(args, "position");
3343 if(!strcmp(position, "inside")) {
3344 current_button_flags |= BC_OVERUP_OVERDOWN;
3345 } else if(!strcmp(position, "outside")) {
3346 //current_button_flags |= BC_IDLE_OUTDOWN;
3347 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3348 } else if(!strcmp(position, "anywhere")) {
3349 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3352 if(type == RAWDATA) {
3354 s_buttonaction(current_button_flags, action);
3355 current_button_flags = 0;
3361 static int c_on_release(map_t*args)
3363 char*position = lu(args, "position");
3365 if(!strcmp(position, "inside")) {
3366 current_button_flags |= BC_OVERDOWN_OVERUP;
3367 } else if(!strcmp(position, "outside")) {
3368 current_button_flags |= BC_OUTDOWN_IDLE;
3369 } else if(!strcmp(position, "anywhere")) {
3370 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3373 if(type == RAWDATA) {
3375 s_buttonaction(current_button_flags, action);
3376 current_button_flags = 0;
3382 static int c_on_move_in(map_t*args)
3384 char*position = lu(args, "state");
3386 if(!strcmp(position, "pressed")) {
3387 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3388 } else if(!strcmp(position, "not_pressed")) {
3389 current_button_flags |= BC_IDLE_OVERUP;
3390 } else if(!strcmp(position, "any")) {
3391 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3394 if(type == RAWDATA) {
3396 s_buttonaction(current_button_flags, action);
3397 current_button_flags = 0;
3403 static int c_on_move_out(map_t*args)
3405 char*position = lu(args, "state");
3407 if(!strcmp(position, "pressed")) {
3408 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3409 } else if(!strcmp(position, "not_pressed")) {
3410 current_button_flags |= BC_OVERUP_IDLE;
3411 } else if(!strcmp(position, "any")) {
3412 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3415 if(type == RAWDATA) {
3417 s_buttonaction(current_button_flags, action);
3418 current_button_flags = 0;
3424 static int c_on_key(map_t*args)
3426 char*key = lu(args, "key");
3428 if(strlen(key)==1) {
3431 current_button_flags |= 0x4000 + (key[0]*0x200);
3433 syntaxerror("invalid character: %c"+key[0]);
3438 <ctrl-x> = 0x200*(x-'a')
3442 syntaxerror("invalid key: %s",key);
3445 if(type == RAWDATA) {
3447 s_buttonaction(current_button_flags, action);
3448 current_button_flags = 0;
3455 static int c_edittext(map_t*args)
3457 //"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"},
3458 char*name = lu(args, "name");
3459 char*font = lu(args, "font");
3460 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3461 int width = parseTwip(lu(args, "width"));
3462 int height = parseTwip(lu(args, "height"));
3463 char*text = lu(args, "text");
3464 RGBA color = parseColor(lu(args, "color"));
3465 int maxlength = parseInt(lu(args, "maxlength"));
3466 char*variable = lu(args, "variable");
3467 char*passwordstr = lu(args, "password");
3468 char*wordwrapstr = lu(args, "wordwrap");
3469 char*multilinestr = lu(args, "multiline");
3470 char*htmlstr = lu(args, "html");
3471 char*noselectstr = lu(args, "noselect");
3472 char*readonlystr = lu(args, "readonly");
3473 char*borderstr = lu(args, "border");
3474 char*autosizestr = lu(args, "autosize");
3475 char*alignstr = lu(args, "align");
3479 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3480 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3481 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3482 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3483 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3484 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3485 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3486 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3487 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3488 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
3489 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
3490 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
3491 else syntaxerror("Unknown alignment: %s", alignstr);
3493 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
3497 static int c_morphshape(map_t*args) {return fakechar(args);}
3498 static int c_movie(map_t*args) {return fakechar(args);}
3500 static char* readfile(const char*filename)
3502 FILE*fi = fopen(filename, "rb");
3506 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
3507 fseek(fi, 0, SEEK_END);
3509 fseek(fi, 0, SEEK_SET);
3510 text = rfx_alloc(l+1);
3511 fread(text, l, 1, fi);
3517 static int c_action(map_t*args)
3519 char* filename = map_lookup(args, "filename");
3520 if(!filename ||!*filename) {
3522 if(type != RAWDATA) {
3523 syntaxerror("colon (:) expected");
3527 s_action(readfile(filename));
3533 static int c_initaction(map_t*args)
3535 char* character = lu(args, "name");
3536 char* filename = map_lookup(args, "filename");
3537 if(!filename ||!*filename) {
3539 if(type != RAWDATA) {
3540 syntaxerror("colon (:) expected");
3542 s_initaction(character, text);
3544 s_initaction(character, readfile(filename));
3552 command_func_t* func;
3555 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default"},
3556 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
3557 // "import" type stuff
3558 {"swf", c_swf, "name filename"},
3559 {"shape", c_swf, "name filename"},
3560 {"jpeg", c_image, "name filename quality=80%"},
3561 {"png", c_image, "name filename"},
3562 {"movie", c_movie, "name filename"},
3563 {"sound", c_sound, "name filename"},
3564 {"font", c_font, "name filename"},
3565 {"soundtrack", c_soundtrack, "filename"},
3566 {"quicktime", c_quicktime, "url"},
3568 // generators of primitives
3570 {"point", c_point, "name x=0 y=0"},
3571 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
3572 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5, damping=2"},
3573 {"outline", c_outline, "name format=simple"},
3574 {"textshape", c_textshape, "name font size=100% text"},
3577 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
3578 {"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"},
3579 {"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"},
3580 {"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"},
3582 // character generators
3583 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
3584 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
3585 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
3587 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
3588 {"text", c_text, "name text font size=100% color=white"},
3589 {"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="},
3590 {"morphshape", c_morphshape, "name start end"},
3591 {"button", c_button, "name"},
3592 {"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="},
3593 {"on_press", c_on_press, "position=inside"},
3594 {"on_release", c_on_release, "position=anywhere"},
3595 {"on_move_in", c_on_move_in, "state=not_pressed"},
3596 {"on_move_out", c_on_move_out, "state=not_pressed"},
3597 {"on_key", c_on_key, "key=any"},
3600 {"play", c_play, "name loop=0 @nomultiple=0"},
3601 {"stop", c_stop, "name= "},
3602 {"nextframe", c_nextframe, "name"},
3603 {"previousframe", c_previousframe, "name"},
3605 // object placement tags
3606 {"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="},
3607 {"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="},
3608 {"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"},
3609 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3610 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3611 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3612 {"del", c_del, "name"},
3613 // virtual object placement
3614 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
3616 // commands which start a block
3617 //startclip (see above)
3618 {"sprite", c_sprite, "name"},
3619 {"action", c_action, "filename="},
3620 {"initaction", c_initaction, "name filename="},
3626 static map_t parseArguments(char*command, char*pattern)
3642 string_set(&t1, "commandname");
3643 string_set(&t2, command);
3644 map_put(&result, t1, t2);
3646 if(!pattern || !*pattern)
3653 if(!strncmp("<i> ", x, 3)) {
3655 if(type == COMMAND || type == RAWDATA) {
3657 syntaxerror("character name expected");
3659 name[pos].str = "instance";
3661 value[pos].str = text;
3662 value[pos].len = strlen(text);
3666 if(type == ASSIGNMENT)
3669 name[pos].str = "character";
3671 value[pos].str = text;
3672 value[pos].len = strlen(text);
3680 isboolean[pos] = (x[0] =='@');
3693 name[pos].len = d-x;
3698 name[pos].len = e-x;
3699 value[pos].str = e+1;
3700 value[pos].len = d-e-1;
3708 /* for(t=0;t<len;t++) {
3709 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
3710 isboolean[t]?"(boolean)":"");
3715 if(type == RAWDATA || type == COMMAND) {
3720 // first, search for boolean arguments
3721 for(pos=0;pos<len;pos++)
3723 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
3725 if(type == ASSIGNMENT)
3727 value[pos].str = text;
3728 value[pos].len = strlen(text);
3729 /*printf("setting boolean parameter %s (to %s)\n",
3730 strdup_n(name[pos], namelen[pos]),
3731 strdup_n(value[pos], valuelen[pos]));*/
3736 // second, search for normal arguments
3738 for(pos=0;pos<len;pos++)
3740 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
3741 (type != ASSIGNMENT && !set[pos])) {
3743 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
3745 if(type == ASSIGNMENT)
3748 value[pos].str = text;
3749 value[pos].len = strlen(text);
3751 printf("setting parameter %s (to %s)\n",
3752 strdup_n(name[pos].str, name[pos].len),
3753 strdup_n(value[pos].str, value[pos].len));
3759 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
3763 for(t=0;t<len;t++) {
3764 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
3767 for(t=0;t<len;t++) {
3768 if(value[t].str && value[t].str[0] == '*') {
3769 //relative default- take value from some other parameter
3771 for(s=0;s<len;s++) {
3772 if(value[s].len == value[t].len-1 &&
3773 !strncmp(&value[t].str[1], value[s].str, value[s].len))
3774 value[t].str = value[s].str;
3777 if(value[t].str == 0) {
3779 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
3783 /* ok, now construct the dictionary from the parameters */
3787 map_put(&result, name[t], value[t]);
3791 static void parseArgumentsForCommand(char*command)
3796 msg("<verbose> parse Command: %s (line %d)", command, line);
3798 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
3799 if(!strcmp(arguments[t].command, command)) {
3801 /* ugly hack- will be removed soon (once documentation and .sc generating
3802 utilities have been changed) */
3803 if(!strcmp(command, "swf") && !stackpos) {
3804 warning("Please use .flash instead of .swf- this will be mandatory soon");
3809 args = parseArguments(command, arguments[t].arguments);
3815 syntaxerror("command %s not known", command);
3817 // catch missing .flash directives at the beginning of a file
3818 if(strcmp(command, "flash") && !stackpos)
3820 syntaxerror("No movie defined- use .flash first");
3824 printf(".%s\n", command);fflush(stdout);
3825 map_dump(&args, stdout, "\t");fflush(stdout);
3828 (*arguments[nr].func)(&args);
3830 /*if(!strcmp(command, "button") ||
3831 !strcmp(command, "action")) {
3834 if(type == COMMAND) {
3835 if(!strcmp(text, "end"))
3849 int main (int argc,char ** argv)
3852 processargs(argc, argv);
3853 initLog(0,-1,0,0,-1,verbose);
3856 args_callback_usage(argv[0]);
3860 file = generateTokens(filename);
3862 fprintf(stderr, "parser returned error.\n");
3868 while(!noMoreTokens()) {
3871 syntaxerror("command expected");
3872 parseArgumentsForCommand(text);