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 static void character_init(character_t*c)
260 memset(c, 0, sizeof(character_t));
263 static character_t* character_new()
266 c = (character_t*)malloc(sizeof(character_t));
271 static void instance_init(instance_t*i)
273 memset(i, 0, sizeof(instance_t));
274 i->history = history_new();
277 static void instance_free(instance_t* i)
279 history_free(i->history);
283 static instance_t* instance_new()
286 c = (instance_t*)malloc(sizeof(instance_t));
291 static void free_instance(void* i)
293 instance_free((instance_t*)i);
296 static void free_font(void* f)
298 swf_FontFree((SWFFONT*)f);
301 static void gradient_free(GRADIENT* grad)
308 static void free_gradient(void* grad)
310 gradient_free((GRADIENT*) grad);
313 static void outline_free(outline_t* o)
315 free(o->shape->data);
320 static void free_outline(void* o)
322 outline_free((outline_t*)o);
325 static void freeDictionaries()
327 dictionary_free_all(&instances, free_instance);
328 dictionary_free_all(&characters, free);
329 dictionary_free_all(&images, free);
330 dictionary_free_all(&textures, free);
331 dictionary_free_all(&outlines, free_outline);
332 dictionary_free_all(&gradients, free_gradient);
333 dictionary_free_all(&filters, free);
334 dictionary_free_all(&fonts, free_font);
335 dictionary_free_all(&sounds, free);
336 dictionary_free_all(&interpolations, free);
339 static void freeFontDictionary()
341 dictionary_free_all(&fonts, free_font);
344 static void incrementid()
348 syntaxerror("Out of character ids.");
353 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
355 if(dictionary_lookup(&characters, name))
356 syntaxerror("character %s defined twice", name);
357 character_t* c = character_new();
359 c->definingTag = ctag;
362 dictionary_put2(&characters, name, c);
364 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
366 swf_SetString(tag, name);
367 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
370 swf_SetString(tag, name);
372 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
374 if(dictionary_lookup(&images, name))
375 syntaxerror("image %s defined twice", name);
377 character_t* c = character_new();
378 c->definingTag = ctag;
381 dictionary_put2(&images, name, c);
383 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
385 if(dictionary_lookup(&instances, name))
386 syntaxerror("object %s defined twice", name);
387 instance_t* i = instance_new();
390 //swf_GetMatrix(0, &i->matrix);
391 dictionary_put2(&instances, name, i);
395 static void parameters_clear(parameters_t*p)
398 p->scalex = 1.0; p->scaley = 1.0;
401 p->pivot.x = 0; p->pivot.y = 0;
406 swf_GetCXForm(0, &p->cxform, 1);
409 static void makeMatrix(MATRIX*m, parameters_t*p)
418 sx = p->scalex*cos(p->rotate/360*2*PI);
419 r1 = -p->scalex*sin(p->rotate/360*2*PI)+sx*p->shear;
420 r0 = p->scaley*sin(p->rotate/360*2*PI);
421 sy = p->scaley*cos(p->rotate/360*2*PI)+r0*p->shear;
423 m->sx = (int)(sx*65536+0.5);
424 m->r1 = (int)(r1*65536+0.5);
425 m->r0 = (int)(r0*65536+0.5);
426 m->sy = (int)(sy*65536+0.5);
430 h = swf_TurnPoint(p->pin, m);
435 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
440 r = swf_TurnRect(rect, &m);
441 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
442 currentrect.xmax == 0 && currentrect.ymax == 0)
445 swf_ExpandRect2(¤trect, &r);
449 void builtInInterpolations()
451 interpolation_t* new;
452 new = (interpolation_t*)malloc(sizeof(interpolation_t));
453 new->function = IF_LINEAR;
454 dictionary_put2(&interpolations, "linear", new);
456 new = (interpolation_t*)malloc(sizeof(interpolation_t));
457 new->function = IF_QUAD_IN;
458 dictionary_put2(&interpolations, "quadIn", new);
459 new = (interpolation_t*)malloc(sizeof(interpolation_t));
460 new->function = IF_QUAD_OUT;
461 dictionary_put2(&interpolations, "quadOut", new);
462 new = (interpolation_t*)malloc(sizeof(interpolation_t));
463 new->function = IF_QUAD_IN_OUT;
464 dictionary_put2(&interpolations, "quadInOut", new);
466 new = (interpolation_t*)malloc(sizeof(interpolation_t));
467 new->function = IF_CUBIC_IN;
468 dictionary_put2(&interpolations, "cubicIn", new);
469 new = (interpolation_t*)malloc(sizeof(interpolation_t));
470 new->function = IF_CUBIC_OUT;
471 dictionary_put2(&interpolations, "cubicOut", new);
472 new = (interpolation_t*)malloc(sizeof(interpolation_t));
473 new->function = IF_CUBIC_IN_OUT;
474 dictionary_put2(&interpolations, "cubicInOut", new);
476 new = (interpolation_t*)malloc(sizeof(interpolation_t));
477 new->function = IF_QUART_IN;
478 dictionary_put2(&interpolations, "quartIn", new);
479 new = (interpolation_t*)malloc(sizeof(interpolation_t));
480 new->function = IF_QUART_OUT;
481 dictionary_put2(&interpolations, "quartOut", new);
482 new = (interpolation_t*)malloc(sizeof(interpolation_t));
483 new->function = IF_QUART_IN_OUT;
484 dictionary_put2(&interpolations, "quartInOut", new);
486 new = (interpolation_t*)malloc(sizeof(interpolation_t));
487 new->function = IF_QUINT_IN;
488 dictionary_put2(&interpolations, "quintIn", new);
489 new = (interpolation_t*)malloc(sizeof(interpolation_t));
490 new->function = IF_QUINT_OUT;
491 dictionary_put2(&interpolations, "quintOut", new);
492 new = (interpolation_t*)malloc(sizeof(interpolation_t));
493 new->function = IF_QUINT_IN_OUT;
494 dictionary_put2(&interpolations, "quintInOut", new);
496 new = (interpolation_t*)malloc(sizeof(interpolation_t));
497 new->function = IF_CIRCLE_IN;
498 dictionary_put2(&interpolations, "circleIn", new);
499 new = (interpolation_t*)malloc(sizeof(interpolation_t));
500 new->function = IF_CIRCLE_OUT;
501 dictionary_put2(&interpolations, "circleOut", new);
502 new = (interpolation_t*)malloc(sizeof(interpolation_t));
503 new->function = IF_CIRCLE_IN_OUT;
504 dictionary_put2(&interpolations, "circleInOut", new);
506 new = (interpolation_t*)malloc(sizeof(interpolation_t));
507 new->function = IF_EXPONENTIAL_IN;
508 dictionary_put2(&interpolations, "exponentialIn", new);
509 new = (interpolation_t*)malloc(sizeof(interpolation_t));
510 new->function = IF_EXPONENTIAL_OUT;
511 dictionary_put2(&interpolations, "exponentialOut", new);
512 new = (interpolation_t*)malloc(sizeof(interpolation_t));
513 new->function = IF_EXPONENTIAL_IN_OUT;
514 dictionary_put2(&interpolations, "exponentialInOut", new);
516 new = (interpolation_t*)malloc(sizeof(interpolation_t));
517 new->function = IF_SINE_IN;
518 dictionary_put2(&interpolations, "sineIn", new);
519 new = (interpolation_t*)malloc(sizeof(interpolation_t));
520 new->function = IF_SINE_OUT;
521 dictionary_put2(&interpolations, "sineOut", new);
522 new = (interpolation_t*)malloc(sizeof(interpolation_t));
523 new->function = IF_SINE_IN_OUT;
524 dictionary_put2(&interpolations, "sineInOut", new);
527 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
530 syntaxerror(".swf blocks can't be nested");
531 if(stackpos==sizeof(stack)/sizeof(stack[0]))
532 syntaxerror("too many levels of recursion");
534 SWF*swf = (SWF*)malloc(sizeof(SWF));
536 memset(swf, 0, sizeof(swf));
537 swf->fileVersion = version;
539 swf->frameRate = fps;
540 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
541 swf->compressed = compress;
542 swf_SetRGB(tag,&background);
544 dictionary_init(&characters);
545 dictionary_init(&images);
546 dictionary_init(&textures);
547 dictionary_init(&outlines);
548 dictionary_init(&gradients);
549 dictionary_init(&filters);
550 dictionary_init(&instances);
551 dictionary_init(&sounds);
552 dictionary_init(&interpolations);
553 builtInInterpolations();
554 cleanUp = &freeDictionaries;
556 memset(&stack[stackpos], 0, sizeof(stack[0]));
557 stack[stackpos].type = 0;
558 stack[stackpos].filename = strdup(name);
559 stack[stackpos].swf = swf;
560 stack[stackpos].oldframe = -1;
564 memset(¤trect, 0, sizeof(currentrect));
567 memset(idmap, 0, sizeof(idmap));
571 void s_sprite(char*name)
573 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
574 swf_SetU16(tag, id); //id
575 swf_SetU16(tag, 0); //frames
577 memset(&stack[stackpos], 0, sizeof(stack[0]));
578 stack[stackpos].type = 1;
579 stack[stackpos].oldframe = currentframe;
580 stack[stackpos].olddepth = currentdepth;
581 stack[stackpos].oldrect = currentrect;
582 stack[stackpos].oldinstances = instances;
583 stack[stackpos].tag = tag;
584 stack[stackpos].id = id;
585 stack[stackpos].name = strdup(name);
587 /* FIXME: those four fields should be bundled together */
588 dictionary_init(&instances);
591 memset(¤trect, 0, sizeof(currentrect));
597 typedef struct _buttonrecord
605 typedef struct _button
609 buttonrecord_t records[4];
612 static button_t mybutton;
614 void s_button(char*name)
616 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
617 swf_SetU16(tag, id); //id
618 swf_ButtonSetFlags(tag, 0); //menu=no
620 memset(&mybutton, 0, sizeof(mybutton));
622 memset(&stack[stackpos], 0, sizeof(stack[0]));
623 stack[stackpos].type = 3;
624 stack[stackpos].tag = tag;
625 stack[stackpos].id = id;
626 stack[stackpos].name = strdup(name);
627 stack[stackpos].oldrect = currentrect;
628 memset(¤trect, 0, sizeof(currentrect));
633 void s_buttonput(char*character, char*as, parameters_t p)
635 character_t* c = dictionary_lookup(&characters, character);
640 if(!stackpos || (stack[stackpos-1].type != 3)) {
641 syntaxerror(".show may only appear in .button");
644 syntaxerror("character %s not known (in .shape %s)", character, character);
646 if(mybutton.endofshapes) {
647 syntaxerror("a .do may not precede a .show", character, character);
650 m = s_instancepos(c->size, &p);
658 if(*s==',' || *s==0) {
659 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
660 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
661 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
662 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
663 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
664 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
671 static void setbuttonrecords(TAG*tag)
673 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
674 if(!mybutton.endofshapes) {
677 if(!mybutton.records[3].set) {
678 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
682 if(mybutton.records[t].set) {
683 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
686 swf_SetU8(tag,0); // end of button records
687 mybutton.endofshapes = 1;
691 void s_buttonaction(int flags, char*action)
697 setbuttonrecords(stack[stackpos-1].tag);
699 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
701 syntaxerror("Couldn't compile ActionScript");
704 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
705 swf_ActionSet(stack[stackpos-1].tag, a);
706 mybutton.nr_actions++;
711 static void setactionend(TAG*tag)
713 if(!mybutton.nr_actions) {
714 /* no actions means we didn't have an actionoffset,
715 which means we can't signal the end of the
716 buttonaction records, so, *sigh*, we have
717 to insert a dummy record */
718 swf_SetU16(tag, 0); //offset
719 swf_SetU16(tag, 0); //condition
720 swf_SetU8(tag, 0); //action
724 static void s_endButton()
727 setbuttonrecords(stack[stackpos-1].tag);
728 setactionend(stack[stackpos-1].tag);
731 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
735 tag = stack[stackpos].tag;
736 currentrect = stack[stackpos].oldrect;
738 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
739 free(stack[stackpos].name);
742 TAG* removeFromTo(TAG*from, TAG*to)
744 TAG*save = from->prev;
746 TAG*next = from->next;
754 static void readParameters(history_t* history, parameters_t* p, int frame)
756 p->x = history_value(history, frame, "x");
757 p->y = history_value(history, frame, "y");
758 p->scalex = history_value(history, frame, "scalex");
759 p->scaley = history_value(history, frame, "scaley");
760 p->cxform.r0 = history_value(history, frame, "cxform.r0");
761 p->cxform.g0 = history_value(history, frame, "cxform.g0");
762 p->cxform.b0 = history_value(history, frame, "cxform.b0");
763 p->cxform.a0 = history_value(history, frame, "cxform.a0");
764 p->cxform.r1 = history_value(history, frame, "cxform.r1");
765 p->cxform.g1 = history_value(history, frame, "cxform.g1");
766 p->cxform.b1 = history_value(history, frame, "cxform.b1");
767 p->cxform.a1 = history_value(history, frame, "cxform.a1");
768 p->rotate = history_value(history, frame, "rotate");
769 p->shear = history_value(history, frame, "shear");
770 p->pivot.x = history_value(history, frame, "pivot.x");
771 p->pivot.y = history_value(history, frame, "pivot.y");
772 p->pin.x = history_value(history, frame, "pin.x");
773 p->pin.y = history_value(history, frame, "pin.y");
774 p->blendmode = history_value(history, frame, "blendmode");
775 p->filter = history_valueFilter(history, frame);
778 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move)
782 swf_GetPlaceObject(NULL, &po);
786 po.cxform = p->cxform;
792 po.blendmode = p->blendmode;
796 flist.filter[0] = p->filter;
799 swf_SetPlaceObject(tag, &po);
802 static void writeInstance(instance_t* i)
806 int frame = i->history->firstFrame;
807 TAG* tag = i->history->firstTag;
808 while (frame < currentframe)
811 readParameters(i->history, &p, frame);
812 while (tag->id != ST_SHOWFRAME)
814 m = s_instancepos(i->character->size, &p);
816 if(p.blendmode || p.filter)
817 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
819 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
820 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
826 void dumpSWF(SWF*swf)
828 TAG* tag = swf->firstTag;
829 printf("vvvvvvvvvvvvvvvvvvvvv\n");
831 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
834 printf("^^^^^^^^^^^^^^^^^^^^^\n");
837 static void s_endSprite()
839 SRECT r = currentrect;
841 if(stack[stackpos].cut)
842 tag = removeFromTo(stack[stackpos].cut, tag);
846 stringarray_t* index =dictionary_index(&instances);
848 char* name = stringarray_at(index, num);
851 i = dictionary_lookup(&instances, name);
854 name = stringarray_at(index, num);
857 tag = swf_InsertTag(tag, ST_SHOWFRAME);
858 tag = swf_InsertTag(tag, ST_END);
860 tag = stack[stackpos].tag;
863 syntaxerror("internal error(7)");
864 /* TODO: before clearing, prepend "<spritename>." to names and
865 copy into old instances dict */
866 dictionary_free_all(&instances, free_instance);
868 currentframe = stack[stackpos].oldframe;
869 currentrect = stack[stackpos].oldrect;
870 currentdepth = stack[stackpos].olddepth;
871 instances = stack[stackpos].oldinstances;
873 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
874 free(stack[stackpos].name);
877 static void s_endSWF()
884 stringarray_t* index = dictionary_index(&instances);
886 char* name = stringarray_at(index, num);
889 i = dictionary_lookup(&instances, name);
892 name = stringarray_at(index, num);
895 if(stack[stackpos].cut)
896 tag = removeFromTo(stack[stackpos].cut, tag);
900 swf = stack[stackpos].swf;
901 filename = stack[stackpos].filename;
903 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
904 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
905 tag = swf_InsertTag(tag, ST_SHOWFRAME);
907 tag = swf_InsertTag(tag, ST_END);
909 swf_OptimizeTagOrder(swf);
915 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
916 swf->movieSize = currentrect; /* "autocrop" */
919 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
920 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
921 swf->movieSize.ymax += 20;
922 warning("Empty bounding box for movie");
925 if(do_cgi || !strcmp(filename, "-"))
928 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
930 syntaxerror("couldn't create output file %s", filename);
933 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
934 else if(swf->compressed)
935 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
937 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
951 if(stack[stackpos-1].type == 0)
952 syntaxerror("End of file encountered in .flash block");
953 if(stack[stackpos-1].type == 1)
954 syntaxerror("End of file encountered in .sprite block");
955 if(stack[stackpos-1].type == 2)
956 syntaxerror("End of file encountered in .clip block");
962 return currentframe+1;
965 void s_frame(int nr, int cut, char*name, char anchor)
971 syntaxerror("Illegal frame number");
972 nr--; // internally, frame 1 is frame 0
974 for(t=currentframe;t<nr;t++) {
975 tag = swf_InsertTag(tag, ST_SHOWFRAME);
976 if(t==nr-1 && name && *name) {
977 tag = swf_InsertTag(tag, ST_FRAMELABEL);
978 swf_SetString(tag, name);
980 swf_SetU8(tag, 1); //make this an anchor
983 if(nr == 0 && currentframe == 0 && name && *name) {
984 tag = swf_InsertTag(tag, ST_FRAMELABEL);
985 swf_SetString(tag, name);
987 swf_SetU8(tag, 1); //make this an anchor
992 syntaxerror("Can't cut, frame empty");
994 stack[stackpos].cut = tag;
1000 int parseColor2(char*str, RGBA*color);
1002 int addFillStyle(SHAPE*s, SRECT*r, char*name)
1006 gradient_t*gradient;
1008 if(name[0] == '#') {
1009 parseColor2(name, &color);
1010 return swf_ShapeAddSolidFillStyle(s, &color);
1011 } else if ((texture = dictionary_lookup(&textures, name))) {
1012 return swf_ShapeAddFillStyle2(s, &texture->fs);
1013 } else if((image = dictionary_lookup(&images, name))) {
1015 swf_GetMatrix(0, &m);
1016 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1017 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1020 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1021 } else if ((gradient = dictionary_lookup(&gradients, name))) {
1025 swf_GetMatrix(0, &rot);
1026 ccos = cos(-gradient->rotate*2*PI/360);
1027 csin = sin(-gradient->rotate*2*PI/360);
1028 rot.sx = ccos*65536;
1029 rot.r1 = -csin*65536;
1030 rot.r0 = csin*65536;
1031 rot.sy = ccos*65536;
1032 r2 = swf_TurnRect(*r, &rot);
1033 swf_GetMatrix(0, &m);
1034 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1035 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1036 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1037 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1038 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1039 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1040 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1041 } else if (parseColor2(name, &color)) {
1042 return swf_ShapeAddSolidFillStyle(s, &color);
1044 syntaxerror("not a color/fillstyle: %s", name);
1049 RGBA black={r:0,g:0,b:0,a:0};
1050 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
1059 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1062 linewidth = linewidth>=20?linewidth-20:0;
1063 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1066 fs1 = addFillStyle(s, &r2, texture);
1069 r.xmin = r2.xmin-linewidth/2;
1070 r.ymin = r2.ymin-linewidth/2;
1071 r.xmax = r2.xmax+linewidth/2;
1072 r.ymax = r2.ymax+linewidth/2;
1073 swf_SetRect(tag,&r);
1074 swf_SetShapeHeader(tag,s);
1075 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1076 swf_ShapeSetLine(tag,s,width,0);
1077 swf_ShapeSetLine(tag,s,0,height);
1078 swf_ShapeSetLine(tag,s,-width,0);
1079 swf_ShapeSetLine(tag,s,0,-height);
1080 swf_ShapeSetEnd(tag);
1083 s_addcharacter(name, id, tag, r);
1087 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
1093 outline = dictionary_lookup(&outlines, outlinename);
1095 syntaxerror("outline %s not defined", outlinename);
1099 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1102 linewidth = linewidth>=20?linewidth-20:0;
1103 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1106 fs1 = addFillStyle(s, &r2, texture);
1109 rect.xmin = r2.xmin-linewidth/2;
1110 rect.ymin = r2.ymin-linewidth/2;
1111 rect.xmax = r2.xmax+linewidth/2;
1112 rect.ymax = r2.ymax+linewidth/2;
1114 swf_SetRect(tag,&rect);
1115 swf_SetShapeStyles(tag, s);
1116 swf_ShapeCountBits(s,0,0);
1117 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1118 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1119 swf_SetShapeBits(tag, s);
1120 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1123 s_addcharacter(name, id, tag, rect);
1127 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
1132 r2.xmin = r2.ymin = 0;
1136 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1139 linewidth = linewidth>=20?linewidth-20:0;
1140 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1143 fs1 = addFillStyle(s, &r2, texture);
1145 rect.xmin = r2.xmin-linewidth/2;
1146 rect.ymin = r2.ymin-linewidth/2;
1147 rect.xmax = r2.xmax+linewidth/2;
1148 rect.ymax = r2.ymax+linewidth/2;
1150 swf_SetRect(tag,&rect);
1151 swf_SetShapeHeader(tag,s);
1152 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1153 swf_ShapeSetCircle(tag, s, r,r,r,r);
1154 swf_ShapeSetEnd(tag);
1157 s_addcharacter(name, id, tag, rect);
1161 void s_textshape(char*name, char*fontname, float size, char*_text)
1164 U8*text = (U8*)_text;
1168 font = dictionary_lookup(&fonts, fontname);
1170 syntaxerror("font \"%s\" not known!", fontname);
1172 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1173 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1174 s_box(name, 0, 0, black, 20, 0);
1177 g = font->ascii2glyph[text[0]];
1179 outline = malloc(sizeof(outline_t));
1180 memset(outline, 0, sizeof(outline_t));
1181 outline->shape = font->glyph[g].shape;
1182 outline->bbox = font->layout->bounds[g];
1186 swf_Shape11DrawerInit(&draw, 0);
1187 swf_DrawText(&draw, font, (int)(size*100), _text);
1189 outline->shape = swf_ShapeDrawerToShape(&draw);
1190 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1191 draw.dealloc(&draw);
1194 if(dictionary_lookup(&outlines, name))
1195 syntaxerror("outline %s defined twice", name);
1196 dictionary_put2(&outlines, name, outline);
1199 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
1204 font = dictionary_lookup(&fonts, fontname);
1206 syntaxerror("font \"%s\" not known!", fontname);
1208 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1209 swf_SetU16(tag, id);
1210 if(!font->numchars) {
1211 s_box(name, 0, 0, black, 20, 0);
1214 r = swf_SetDefineText(tag, font, &color, text, size);
1216 if(stack[0].swf->fileVersion >= 8) {
1217 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1218 swf_SetU16(tag, id);
1219 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1220 swf_SetU32(tag, 0);//thickness
1221 swf_SetU32(tag, 0);//sharpness
1222 swf_SetU8(tag, 0);//reserved
1225 s_addcharacter(name, id, tag, r);
1229 void s_quicktime(char*name, char*url)
1234 memset(&r, 0, sizeof(r));
1236 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1237 swf_SetU16(tag, id);
1238 swf_SetString(tag, url);
1240 s_addcharacter(name, id, tag, r);
1244 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)
1247 EditTextLayout layout;
1250 if(fontname && *fontname) {
1251 flags |= ET_USEOUTLINES;
1252 font = dictionary_lookup(&fonts, fontname);
1254 syntaxerror("font \"%s\" not known!", fontname);
1256 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1257 swf_SetU16(tag, id);
1258 layout.align = align;
1259 layout.leftmargin = 0;
1260 layout.rightmargin = 0;
1268 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
1270 s_addcharacter(name, id, tag, r);
1274 /* type: either "jpeg" or "png"
1276 void s_image(char*name, char*type, char*filename, int quality)
1278 /* an image is actually two folded: 1st bitmap, 2nd character.
1279 Both of them can be used separately */
1281 /* step 1: the bitmap */
1285 if(!strcmp(type,"jpeg")) {
1286 #ifndef HAVE_JPEGLIB
1287 warning("no jpeg support compiled in");
1288 s_box(name, 0, 0, black, 20, 0);
1291 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1292 swf_SetU16(tag, imageID);
1294 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1295 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1298 swf_GetJPEGSize(filename, &width, &height);
1305 s_addimage(name, id, tag, r);
1308 } else if(!strcmp(type,"png")) {
1310 swf_SetU16(tag, imageID);
1312 getPNG(filename, &width, &height, (unsigned char**)&data);
1315 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1318 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1319 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1320 swf_SetU16(tag, imageID);
1321 swf_SetLosslessImage(tag, data, width, height);
1328 s_addimage(name, id, tag, r);
1331 warning("image type \"%s\" not supported yet!", type);
1332 s_box(name, 0, 0, black, 20, 0);
1336 /* step 2: the character */
1337 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1338 swf_SetU16(tag, id);
1339 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1341 s_addcharacter(name, id, tag, r);
1345 void s_getBitmapSize(char*name, int*width, int*height)
1347 character_t* image = dictionary_lookup(&images, name);
1348 gradient_t* gradient = dictionary_lookup(&gradients,name);
1350 *width = image->size.xmax;
1351 *height = image->size.ymax;
1355 /* internal SWF gradient size */
1356 if(gradient->radial) {
1365 syntaxerror("No such bitmap/gradient: %s", name);
1368 void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1370 if(dictionary_lookup(&textures, name))
1371 syntaxerror("texture %s defined twice", name);
1372 gradient_t* gradient = dictionary_lookup(&gradients, object);
1373 character_t* bitmap = dictionary_lookup(&images, object);
1374 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1376 FILLSTYLE*fs = &texture->fs;
1378 memset(&p, 0, sizeof(parameters_t));
1381 fs->type = FILL_TILED;
1382 fs->id_bitmap = bitmap->id;
1383 } else if(gradient) {
1384 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1385 fs->gradient = gradient->gradient;
1387 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1388 makeMatrix(&fs->m, &p);
1389 if(gradient && !gradient->radial) {
1396 p2 = swf_TurnPoint(p1, &m);
1405 dictionary_put2(&textures, name, texture);
1408 void s_font(char*name, char*filename)
1411 font = dictionary_lookup(&fonts, name);
1414 /* fix the layout. Only needed for old fonts */
1416 for(t=0;t<font->numchars;t++) {
1417 font->glyph[t].advance = 0;
1420 swf_FontCreateLayout(font);
1423 swf_FontReduce_swfc(font);
1424 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1425 swf_FontSetDefine2(tag, font);
1426 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1428 swf_SetU16(tag, id);
1429 swf_SetString(tag, name);
1436 typedef struct _sound_t
1442 void s_sound(char*name, char*filename)
1444 struct WAV wav, wav2;
1448 unsigned numsamples = 1;
1449 unsigned blocksize = 1152;
1452 if(dictionary_lookup(&sounds, name))
1453 syntaxerror("sound %s defined twice", name);
1455 if(wav_read(&wav, filename))
1458 wav_convert2mono(&wav, &wav2, 44100);
1459 samples = (U16*)wav2.data;
1460 numsamples = wav2.size/2;
1462 #ifdef WORDS_BIGENDIAN
1464 for(t=0;t<numsamples;t++)
1465 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1469 if(mp3_read(&mp3, filename))
1471 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1477 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1482 if(numsamples%blocksize != 0)
1484 // apply padding, so that block is a multiple of blocksize
1485 int numblocks = (numsamples+blocksize-1)/blocksize;
1488 numsamples2 = numblocks * blocksize;
1489 samples2 = malloc(sizeof(U16)*numsamples2);
1490 memcpy(samples2, samples, numsamples*sizeof(U16));
1491 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1492 numsamples = numsamples2;
1497 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1498 swf_SetU16(tag, id); //id
1501 swf_SetSoundDefineMP3(
1502 tag, mp3.data, mp3.size,
1509 swf_SetSoundDefine(tag, samples, numsamples);
1511 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1512 swf_SetU16(tag, id);
1513 swf_SetString(tag, name);
1514 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1516 swf_SetU16(tag, id);
1517 swf_SetString(tag, name);
1519 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1523 dictionary_put2(&sounds, name, sound);
1531 static char* gradient_getToken(const char**p)
1535 while(**p && strchr(" \t\n\r", **p)) {
1539 while(**p && !strchr(" \t\n\r", **p)) {
1542 result = malloc((*p)-start+1);
1543 memcpy(result,start,(*p)-start+1);
1544 result[(*p)-start] = 0;
1548 float parsePercent(char*str);
1549 RGBA parseColor(char*str);
1551 GRADIENT parseGradient(const char*str)
1555 const char* p = str;
1556 memset(&gradient, 0, sizeof(GRADIENT));
1557 gradient.ratios = rfx_calloc(16*sizeof(U8));
1558 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1562 char*posstr,*colorstr;
1565 posstr = gradient_getToken(&p);
1571 pos = (int)(parsePercent(posstr)*255.0);
1576 rfx_free(gradient.ratios);
1577 rfx_free(gradient.rgba);
1579 syntaxerror("Error in shape data: Color expected after %s", posstr);
1581 colorstr = gradient_getToken(&p);
1582 color = parseColor(colorstr);
1583 if(gradient.num == 16)
1585 warning("gradient record too big- max size is 16, rest ignored");
1588 gradient.ratios[gradient.num] = pos;
1589 gradient.rgba[gradient.num] = color;
1598 void s_gradient(char*name, const char*text, int radial, int rotate)
1600 gradient_t* gradient;
1601 gradient = malloc(sizeof(gradient_t));
1602 memset(gradient, 0, sizeof(gradient_t));
1603 gradient->gradient = parseGradient(text);
1604 gradient->radial = radial;
1605 gradient->rotate = rotate;
1607 dictionary_put2(&gradients, name, gradient);
1610 void s_gradientglow(char*name, char*gradient, float blurx, float blury,
1611 float angle, float distance, float strength, char innershadow,
1612 char knockout, char composite, char ontop, int passes)
1614 if(dictionary_lookup(&filters, name))
1615 syntaxerror("filter %s defined twice", name);
1617 gradient_t* g = dictionary_lookup(&gradients, gradient);
1622 syntaxerror("unknown gradient %s", gradient);
1623 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1624 filter->type = FILTERTYPE_GRADIENTGLOW;
1625 filter->gradient = &g->gradient;
1626 filter->blurx = blurx;
1627 filter->blury = blury;
1628 filter->strength = strength;
1629 filter->angle = angle;
1630 filter->distance = distance;
1631 filter->innershadow = innershadow;
1632 filter->knockout = knockout;
1633 filter->composite = composite;
1634 filter->ontop = ontop;
1635 filter->passes = passes;
1637 dictionary_put2(&filters, name, filter);
1640 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)
1642 if(dictionary_lookup(&filters, name))
1643 syntaxerror("filter %s defined twice", name);
1646 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1647 filter->type = FILTERTYPE_DROPSHADOW;
1648 filter->color= color;
1649 filter->blurx = blurx;
1650 filter->blury = blury;
1651 filter->strength = strength;
1652 filter->angle = angle;
1653 filter->distance = distance;
1654 filter->innershadow = innershadow;
1655 filter->knockout = knockout;
1656 filter->composite = composite;
1657 filter->passes = passes;
1659 dictionary_put2(&filters, name, filter);
1662 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)
1664 if(dictionary_lookup(&filters, name))
1665 syntaxerror("filter %s defined twice", name);
1668 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1669 filter->type = FILTERTYPE_BEVEL;
1670 filter->shadow = shadow;
1671 filter->highlight = highlight;
1672 filter->blurx = blurx;
1673 filter->blury = blury;
1674 filter->strength = strength;
1675 filter->angle = angle;
1676 filter->distance = distance;
1677 filter->innershadow = innershadow;
1678 filter->knockout = knockout;
1679 filter->composite = composite;
1680 filter->ontop = ontop;
1681 filter->passes = passes;
1683 dictionary_put2(&filters, name, filter);
1686 void s_blur(char*name, double blurx, double blury, int passes)
1688 if(dictionary_lookup(&filters, name))
1689 syntaxerror("filter %s defined twice", name);
1691 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1692 filter->type = FILTERTYPE_BLUR;
1693 filter->blurx = blurx;
1694 filter->blury = blury;
1695 filter->passes = passes;
1697 dictionary_put2(&filters, name, filter);
1700 void s_action(const char*text)
1703 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1707 syntaxerror("Couldn't compile ActionScript");
1710 tag = swf_InsertTag(tag, ST_DOACTION);
1712 swf_ActionSet(tag, a);
1717 void s_initaction(const char*character, const char*text)
1721 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1725 syntaxerror("Couldn't compile ActionScript");
1728 c = (character_t*)dictionary_lookup(&characters, character);
1730 tag = swf_InsertTag(tag, ST_DOINITACTION);
1731 swf_SetU16(tag, c->id);
1732 swf_ActionSet(tag, a);
1737 int s_swf3action(char*name, char*action)
1740 instance_t* object = 0;
1742 object = (instance_t*)dictionary_lookup(&instances, name);
1743 if(!object && name && *name) {
1744 /* we have a name, but couldn't find it. Abort. */
1747 a = action_SetTarget(0, name);
1748 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1749 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1750 else if(!strcmp(action, "stop")) a = action_Stop(a);
1751 else if(!strcmp(action, "play")) a = action_Play(a);
1752 a = action_SetTarget(a, "");
1755 tag = swf_InsertTag(tag, ST_DOACTION);
1756 swf_ActionSet(tag, a);
1761 void s_outline(char*name, char*format, char*source)
1763 if(dictionary_lookup(&outlines, name))
1764 syntaxerror("outline %s defined twice", name);
1773 //swf_Shape10DrawerInit(&draw, 0);
1774 swf_Shape11DrawerInit(&draw, 0);
1776 draw_string(&draw, source);
1778 shape = swf_ShapeDrawerToShape(&draw);
1779 bounds = swf_ShapeDrawerGetBBox(&draw);
1780 draw.dealloc(&draw);
1782 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1783 outline->shape = shape;
1784 outline->bbox = bounds;
1786 dictionary_put2(&outlines, name, outline);
1789 int s_playsound(char*name, int loops, int nomultiple, int stop)
1795 sound = dictionary_lookup(&sounds, name);
1799 tag = swf_InsertTag(tag, ST_STARTSOUND);
1800 swf_SetU16(tag, sound->id); //id
1801 memset(&info, 0, sizeof(info));
1804 info.nomultiple = nomultiple;
1805 swf_SetSoundInfo(tag, &info);
1809 void s_includeswf(char*name, char*filename)
1817 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1818 f = open(filename,O_RDONLY|O_BINARY);
1820 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1821 s_box(name, 0, 0, black, 20, 0);
1824 if (swf_ReadSWF(f,&swf)<0) {
1825 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1826 s_box(name, 0, 0, black, 20, 0);
1831 /* FIXME: The following sets the bounding Box for the character.
1832 It is wrong for two reasons:
1833 a) It may be too small (in case objects in the movie clip at the borders)
1834 b) it may be too big (because the poor movie never got autocropped)
1838 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1839 swf_SetU16(tag, id);
1840 swf_SetU16(tag, swf.frameCount);
1842 swf_Relocate(&swf, idmap);
1844 ftag = swf.firstTag;
1848 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1849 if(cutout[t] == ftag->id) {
1853 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1855 if(ftag->id == ST_END)
1860 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
1861 /* We simply dump all tags right after the sprite
1862 header, relying on the fact that swf_OptimizeTagOrder() will
1863 sort things out for us later.
1864 We also rely on the fact that the imported SWF is well-formed.
1866 tag = swf_InsertTag(tag, ftag->id);
1867 swf_SetBlock(tag, ftag->data, ftag->len);
1873 syntaxerror("Included file %s contains errors", filename);
1874 tag = swf_InsertTag(tag, ST_END);
1878 s_addcharacter(name, id, tag, r);
1881 SRECT s_getCharBBox(char*name)
1883 character_t* c = dictionary_lookup(&characters, name);
1884 if(!c) syntaxerror("character '%s' unknown(2)", name);
1887 SRECT s_getInstanceBBox(char*name)
1889 instance_t * i = dictionary_lookup(&instances, name);
1891 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1893 if(!c) syntaxerror("internal error(5)");
1896 parameters_t s_getParameters(char*name)
1898 instance_t * i = dictionary_lookup(&instances, name);
1899 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1900 return i->parameters;
1902 void s_startclip(char*instance, char*character, parameters_t p)
1904 character_t* c = dictionary_lookup(&characters, character);
1908 syntaxerror("character %s not known", character);
1910 i = s_addinstance(instance, c, currentdepth);
1912 m = s_instancepos(i->character->size, &p);
1914 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1915 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1916 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1918 i->lastFrame= currentframe;
1920 stack[stackpos].tag = tag;
1921 stack[stackpos].type = 2;
1930 swf_SetTagPos(stack[stackpos].tag, 0);
1931 swf_GetPlaceObject(stack[stackpos].tag, &p);
1932 p.clipdepth = currentdepth;
1934 swf_ClearTag(stack[stackpos].tag);
1935 swf_SetPlaceObject(stack[stackpos].tag, &p);
1939 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
1941 history_begin(i->history, "x", currentframe, tag, p->x);
1942 history_begin(i->history, "y", currentframe, tag, p->y);
1943 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
1944 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
1945 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
1946 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
1947 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
1948 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
1949 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
1950 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
1951 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
1952 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
1953 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
1954 history_begin(i->history, "shear", currentframe, tag, p->shear);
1955 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
1956 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
1957 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
1958 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
1959 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
1960 history_beginFilter(i->history, currentframe, tag, p->filter);
1963 void s_put(char*instance, char*character, parameters_t p)
1965 character_t* c = dictionary_lookup(&characters, character);
1969 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1971 i = s_addinstance(instance, c, currentdepth);
1973 m = s_instancepos(i->character->size, &p);
1975 if(p.blendmode || p.filter)
1977 if(stack[0].swf->fileVersion < 8)
1980 warning("blendmodes only supported for flash version>=8");
1982 warning("filters only supported for flash version>=8");
1984 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
1987 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1988 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
1989 setStartparameters(i, &p, tag);
1991 i->lastFrame = currentframe;
1995 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
1998 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2000 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2001 if (p.set & SF_SCALEX)
2002 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2003 if (p.set & SF_SCALEY)
2004 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2005 if (p.set & SF_CX_R)
2007 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2008 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2010 if (p.set & SF_CX_G)
2012 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2013 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2015 if (p.set & SF_CX_B)
2017 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2018 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2020 if (p.set & SF_CX_A)
2022 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2023 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2025 if (p.set & SF_ROTATE)
2026 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2027 if (p.set & SF_SHEAR)
2028 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2029 if (p.set & SF_PIVOT)
2031 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2032 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2036 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2037 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2039 if (p.set & SF_BLEND)
2040 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2041 if (p.set & SF_FILTER)
2042 history_rememberFilter(history, currentframe, changeFunction, p.filter, inter);
2045 void s_jump(char* instance, parameters_t p)
2047 instance_t* i = dictionary_lookup(&instances, instance);
2049 syntaxerror("instance %s not known", instance);
2050 recordChanges(i->history, p, CF_JUMP, 0);
2053 void s_change(char*instance, parameters_t p2, interpolation_t* inter)
2055 instance_t* i = dictionary_lookup(&instances, instance);
2057 syntaxerror("instance %s not known", instance);
2058 recordChanges(i->history, p2, CF_CHANGE, inter);
2061 void s_delinstance(char*instance)
2063 instance_t* i = dictionary_lookup(&instances, instance);
2065 syntaxerror("instance %s not known", instance);
2066 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2067 swf_SetU16(tag, i->depth);
2068 dictionary_del(&instances, instance);
2071 void s_qchange(char*instance, parameters_t p)
2073 instance_t* i = dictionary_lookup(&instances, instance);
2075 syntaxerror("instance %s not known", instance);
2076 recordChanges(i->history, p, CF_QCHANGE, 0);
2082 syntaxerror(".end unexpected");
2083 switch (stack[stackpos-1].type)
2098 syntaxerror("internal error 1");
2102 // ------------------------------------------------------------------------
2104 typedef int command_func_t(map_t*args);
2106 SRECT parseBox(char*str)
2108 SRECT r = {0,0,0,0};
2109 float xmin, xmax, ymin, ymax;
2110 char*x = strchr(str, 'x');
2112 if(!strcmp(str, "autocrop")) {
2113 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2117 d1 = strchr(x+1, ':');
2119 d2 = strchr(d1+1, ':');
2121 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2125 else if(d1 && !d2) {
2126 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2132 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2137 r.xmin = (SCOORD)(xmin*20);
2138 r.ymin = (SCOORD)(ymin*20);
2139 r.xmax = (SCOORD)(xmax*20);
2140 r.ymax = (SCOORD)(ymax*20);
2143 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2146 float parseFloat(char*str)
2150 int parseInt(char*str)
2155 if(str[0]=='+' || str[0]=='-')
2159 if(str[t]<'0' || str[t]>'9')
2160 syntaxerror("Not an Integer: \"%s\"", str);
2163 int parseTwip(char*str)
2167 if(str[0]=='+' || str[0]=='-') {
2172 dot = strchr(str, '.');
2176 return sign*parseInt(str)*20;
2178 char* old = strdup(str);
2179 int l=strlen(dot+1);
2182 for(s=str;s<dot-1;s++)
2183 if(*s<'0' || *s>'9')
2186 syntaxerror("Not a coordinate: \"%s\"", str);
2189 if(*s<'0' || *s>'9')
2192 syntaxerror("Not a coordinate: \"%s\"", str);
2194 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2195 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2198 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2202 return sign*atoi(str)*20;
2204 return sign*atoi(str)*20+atoi(dot)*2;
2206 return sign*atoi(str)*20+atoi(dot)/5;
2211 int isPoint(char*str)
2213 if(strchr(str, '('))
2219 SPOINT parsePoint(char*str)
2223 int l = strlen(str);
2224 char*comma = strchr(str, ',');
2225 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2226 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2227 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2228 p.x = parseTwip(tmp);
2229 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2230 p.y = parseTwip(tmp);
2234 int parseColor2(char*str, RGBA*color)
2236 int l = strlen(str);
2240 struct {unsigned char r,g,b;char*name;} colors[] =
2241 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2242 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2243 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2244 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2245 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2246 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2247 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2248 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2249 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2250 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2251 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2252 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2256 if(str[0]=='#' && (l==7 || l==9)) {
2257 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2259 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2261 color->r = r; color->g = g; color->b = b; color->a = a;
2264 int len=strlen(str);
2266 if(strchr(str, '/')) {
2267 len = strchr(str, '/')-str;
2268 sscanf(str+len+1,"%02x", &alpha);
2270 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2271 if(!strncmp(str, colors[t].name, len)) {
2276 color->r = r; color->g = g; color->b = b; color->a = a;
2282 RGBA parseColor(char*str)
2285 if(!parseColor2(str, &c))
2286 syntaxerror("Expression '%s' is not a color", str);
2290 typedef struct _muladd {
2295 MULADD parseMulAdd(char*str)
2298 char* str2 = (char*)malloc(strlen(str)+5);
2305 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2306 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2307 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2308 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2309 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2310 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2311 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2312 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2313 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2314 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2316 syntaxerror("'%s' is not a valid color transform expression", str);
2318 m.add = (int)(add*256);
2319 m.mul = (int)(mul*256);
2324 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2326 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2327 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2329 if(a<-32768) a=-32768;
2330 if(a>32767) a=32767;
2331 if(m<-32768) m=-32768;
2332 if(m>32767) m=32767;
2338 float parsePxOrPercent(char*fontname, char*str)
2340 int l = strlen(str);
2341 if(strchr(str, '%'))
2342 return parsePercent(str);
2343 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2344 float p = atof(str);
2345 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2347 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2351 float parsePercent(char*str)
2353 int l = strlen(str);
2357 return atoi(str)/100.0;
2359 syntaxerror("Expression '%s' is not a percentage", str);
2362 int isPercent(char*str)
2364 return str[strlen(str)-1]=='%';
2366 int parseNewSize(char*str, int size)
2369 return parsePercent(str)*size;
2371 return (int)(atof(str)*20);
2374 int isColor(char*str)
2377 return parseColor2(str, &c);
2380 static char* lu(map_t* args, char*name)
2382 char* value = map_lookup(args, name);
2384 map_dump(args, stdout, "");
2385 syntaxerror("internal error 2: value %s should be set", name);
2390 static int c_flash(map_t*args)
2392 char* filename = map_lookup(args, "filename");
2393 char* compressstr = lu(args, "compress");
2394 SRECT bbox = parseBox(lu(args, "bbox"));
2395 int version = parseInt(lu(args, "version"));
2396 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2398 RGBA color = parseColor(lu(args, "background"));
2400 if(!filename || !*filename) {
2401 /* for compatibility */
2402 filename = map_lookup(args, "name");
2403 if(!filename || !*filename) {
2406 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2407 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2411 if(!filename || override_outputname)
2412 filename = outputname;
2414 if(!strcmp(compressstr, "default"))
2415 compress = version>=6;
2416 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2418 else if(!strcmp(compressstr, "no"))
2420 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2422 s_swf(filename, bbox, version, fps, compress, color);
2425 int isRelative(char*str)
2427 return !strncmp(str, "<plus>", 6) ||
2428 !strncmp(str, "<minus>", 7);
2430 char* getOffset(char*str)
2432 if(!strncmp(str, "<plus>", 6))
2434 if(!strncmp(str, "<minus>", 7))
2436 syntaxerror("internal error (347)");
2439 int getSign(char*str)
2441 if(!strncmp(str, "<plus>", 6))
2443 if(!strncmp(str, "<minus>", 7))
2445 syntaxerror("internal error (348)");
2448 static dictionary_t points;
2449 static mem_t mpoints;
2450 int points_initialized = 0;
2452 static int c_interpolation(map_t *args)
2455 char* name = lu(args, "name");
2456 if (dictionary_lookup(&interpolations, name))
2457 syntaxerror("interpolation %s defined twice", name);
2459 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2460 char* functionstr = lu(args, "function");
2461 inter->function = 0;
2462 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2463 if (!strcmp(functionstr,interpolationFunctions[i]))
2465 inter->function = i + 1;
2468 if (!inter->function)
2469 syntaxerror("unkown interpolation function %s", functionstr);
2470 inter->speed = parseFloat(lu(args, "speed"));
2471 inter->amplitude = parseFloat(lu(args, "amplitude"));
2472 inter->growth = parseFloat(lu(args, "growth"));
2473 inter->bounces = parseInt(lu(args, "bounces"));
2474 inter->damping = parseInt(lu(args, "damping"));
2476 dictionary_put2(&interpolations, name, inter);
2480 SPOINT getPoint(SRECT r, char*name)
2483 if(!strcmp(name, "center")) {
2485 p.x = (r.xmin + r.xmax)/2;
2486 p.y = (r.ymin + r.ymax)/2;
2490 if(points_initialized)
2491 l = (int)dictionary_lookup(&points, name);
2493 syntaxerror("Invalid point: \"%s\".", name);
2496 return *(SPOINT*)&mpoints.buffer[l];
2499 static int texture2(char*name, char*object, map_t*args, int errors)
2502 char*xstr = map_lookup(args, "x");
2503 char*ystr = map_lookup(args, "y");
2504 char*widthstr = map_lookup(args, "width");
2505 char*heightstr = map_lookup(args, "height");
2506 char*scalestr = map_lookup(args, "scale");
2507 char*scalexstr = map_lookup(args, "scalex");
2508 char*scaleystr = map_lookup(args, "scaley");
2509 char*rotatestr = map_lookup(args, "rotate");
2510 char* shearstr = map_lookup(args, "shear");
2511 char* radiusstr = map_lookup(args, "r");
2513 float scalex = 1.0, scaley = 1.0;
2514 float rotate=0, shear=0;
2516 if(!*xstr && !*ystr) {
2518 syntaxerror("x and y must be set");
2521 if(*scalestr && (*scalexstr || *scaleystr)) {
2522 syntaxerror("scale and scalex/scaley can't both be set");
2525 if((*widthstr || *heightstr) && *radiusstr) {
2526 syntaxerror("width/height and radius can't both be set");
2529 widthstr = radiusstr;
2530 heightstr = radiusstr;
2532 if(!*xstr) xstr="0";
2533 if(!*ystr) ystr="0";
2534 if(!*rotatestr) rotatestr="0";
2535 if(!*shearstr) shearstr="0";
2538 scalex = scaley = parsePercent(scalestr);
2539 } else if(*scalexstr || *scaleystr) {
2540 if(scalexstr) scalex = parsePercent(scalexstr);
2541 if(scaleystr) scaley = parsePercent(scaleystr);
2542 } else if(*widthstr || *heightstr) {
2545 s_getBitmapSize(object, &width, &height);
2547 scalex = (float)parseTwip(widthstr)/(float)width;
2549 scaley = (float)parseTwip(heightstr)/(float)height;
2551 x = parseTwip(xstr);
2552 y = parseTwip(ystr);
2553 rotate = parseFloat(rotatestr);
2554 shear = parseFloat(shearstr);
2556 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2561 static int c_texture(map_t*args)
2563 char*name = lu(args, "instance");
2564 char*object = lu(args, "character");
2565 return texture2(name, object, args, 1);
2568 static int c_gradient(map_t*args)
2570 char*name = lu(args, "name");
2571 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2572 int rotate = parseInt(lu(args, "rotate"));
2576 syntaxerror("colon (:) expected");
2578 if(dictionary_lookup(&gradients, name))
2579 syntaxerror("gradient %s defined twice", name);
2581 s_gradient(name, text, radial, rotate);
2583 /* check whether we also have placement information,
2584 which would make this a positioned gradient.
2585 If there is placement information, texture2() will
2586 add a texture, which has priority over the gradient.
2588 texture2(name, name, args, 0);
2592 static int c_blur(map_t*args)
2594 char*name = lu(args, "name");
2595 char*blurstr = lu(args, "blur");
2596 char*blurxstr = lu(args, "blurx");
2597 char*blurystr = lu(args, "blury");
2598 float blurx=1.0, blury=1.0;
2600 blurx = parseFloat(blurstr);
2601 blury = parseFloat(blurstr);
2604 blurx = parseFloat(blurxstr);
2606 blury = parseFloat(blurystr);
2607 int passes = parseInt(lu(args, "passes"));
2608 s_blur(name, blurx, blury, passes);
2612 static int c_gradientglow(map_t*args)
2614 char*name = lu(args, "name");
2615 char*gradient = lu(args, "gradient");
2616 char*blurstr = lu(args, "blur");
2617 char*blurxstr = lu(args, "blurx");
2618 char*blurystr = lu(args, "blury");
2619 float blurx=1.0, blury=1.0;
2621 blurx = parseFloat(blurstr);
2622 blury = parseFloat(blurstr);
2625 blurx = parseFloat(blurxstr);
2627 blury = parseFloat(blurystr);
2629 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2630 float distance = parseFloat(lu(args, "distance"));
2631 float strength = parseFloat(lu(args, "strength"));
2632 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2633 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2634 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2635 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2636 int passes = parseInt(lu(args, "passes"));
2638 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2642 static int c_dropshadow(map_t*args)
2644 char*name = lu(args, "name");
2645 RGBA color = parseColor(lu(args, "color"));
2646 char*blurstr = lu(args, "blur");
2647 char*blurxstr = lu(args, "blurx");
2648 char*blurystr = lu(args, "blury");
2649 float blurx=1.0, blury=1.0;
2651 blurx = parseFloat(blurstr);
2652 blury = parseFloat(blurstr);
2655 blurx = parseFloat(blurxstr);
2657 blury = parseFloat(blurystr);
2659 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2660 float distance = parseFloat(lu(args, "distance"));
2661 float strength = parseFloat(lu(args, "strength"));
2662 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2663 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2664 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2665 int passes = parseInt(lu(args, "passes"));
2667 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
2671 static int c_bevel(map_t*args)
2673 char*name = lu(args, "name");
2674 RGBA shadow = parseColor(lu(args, "shadow"));
2675 RGBA highlight = parseColor(lu(args, "highlight"));
2676 char*blurstr = lu(args, "blur");
2677 char*blurxstr = lu(args, "blurx");
2678 char*blurystr = lu(args, "blury");
2679 float blurx=1.0, blury=1.0;
2681 blurx = parseFloat(blurstr);
2682 blury = parseFloat(blurstr);
2685 blurx = parseFloat(blurxstr);
2687 blury = parseFloat(blurystr);
2689 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2690 float distance = parseFloat(lu(args, "distance"));
2691 float strength = parseFloat(lu(args, "strength"));
2692 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2693 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2694 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2695 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2696 int passes = parseInt(lu(args, "passes"));
2698 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2702 static int c_point(map_t*args)
2704 char*name = lu(args, "name");
2708 if(!points_initialized) {
2709 dictionary_init(&points);
2711 points_initialized = 1;
2713 p.x = parseTwip(lu(args, "x"));
2714 p.y = parseTwip(lu(args, "y"));
2715 pos = mem_put(&mpoints, &p, sizeof(p));
2716 string_set(&s1, name);
2718 dictionary_put(&points, s1, (void*)pos);
2721 static int c_play(map_t*args)
2723 char*name = lu(args, "name");
2724 char*loop = lu(args, "loop");
2725 char*nomultiple = lu(args, "nomultiple");
2727 if(!strcmp(nomultiple, "nomultiple"))
2730 nm = parseInt(nomultiple);
2732 if(s_playsound(name, parseInt(loop), nm, 0)) {
2734 } else if(s_swf3action(name, "play")) {
2740 static int c_stop(map_t*args)
2742 char*name = map_lookup(args, "name");
2744 if(s_playsound(name, 0,0,1))
2746 else if(s_swf3action(name, "stop"))
2748 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
2752 static int c_nextframe(map_t*args)
2754 char*name = lu(args, "name");
2756 if(s_swf3action(name, "nextframe")) {
2759 syntaxerror("I don't know anything about movie \"%s\"", name);
2763 static int c_previousframe(map_t*args)
2765 char*name = lu(args, "name");
2767 if(s_swf3action(name, "previousframe")) {
2770 syntaxerror("I don't know anything about movie \"%s\"", name);
2774 static int c_placement(map_t*args, int type)
2776 char*instance = lu(args, (type==0||type==4)?"instance":"name");
2779 char* luminancestr = lu(args, "luminance");
2780 char* scalestr = lu(args, "scale");
2781 char* scalexstr = lu(args, "scalex");
2782 char* scaleystr = lu(args, "scaley");
2783 char* rotatestr = lu(args, "rotate");
2784 char* shearstr = lu(args, "shear");
2785 char* xstr="", *pivotstr="";
2786 char* ystr="", *anglestr="";
2787 char*above = lu(args, "above"); /*FIXME*/
2788 char*below = lu(args, "below");
2789 char* rstr = lu(args, "red");
2790 char* gstr = lu(args, "green");
2791 char* bstr = lu(args, "blue");
2792 char* astr = lu(args, "alpha");
2793 char* pinstr = lu(args, "pin");
2794 char* as = map_lookup(args, "as");
2795 char* blendmode = lu(args, "blend");
2796 char* filterstr = lu(args, "filter");
2804 U32 set = 0x00000000;
2807 { // (?) .rotate or .arcchange
2808 pivotstr = lu(args, "pivot");
2809 anglestr = lu(args, "angle");
2813 xstr = lu(args, "x");
2814 ystr = lu(args, "y");
2818 luminance = parseMulAdd(luminancestr);
2822 luminance.mul = 256;
2827 if(scalexstr[0]||scaleystr[0])
2828 syntaxerror("scalex/scaley and scale cannot both be set");
2829 scalexstr = scaleystr = scalestr;
2832 if(type == 0 || type == 4) {
2834 character = lu(args, "character");
2835 parameters_clear(&p);
2836 } else if (type == 5) {
2837 character = lu(args, "name");
2838 parameters_clear(&p);
2841 p = s_getParameters(instance);
2847 if(isRelative(xstr))
2849 if(type == 0 || type == 4)
2850 syntaxerror("relative x values not allowed for initial put or startclip");
2851 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2855 p.x = parseTwip(xstr);
2861 if(isRelative(ystr))
2863 if(type == 0 || type == 4)
2864 syntaxerror("relative y values not allowed for initial put or startclip");
2865 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2869 p.y = parseTwip(ystr);
2874 /* scale, scalex, scaley */
2876 oldbbox = s_getCharBBox(character);
2878 oldbbox = s_getInstanceBBox(instance);
2879 oldwidth = oldbbox.xmax - oldbbox.xmin;
2880 oldheight = oldbbox.ymax - oldbbox.ymin;
2887 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2888 set = set | SF_SCALEX;
2896 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2897 set = set | SF_SCALEY;
2903 if(isRelative(rotatestr))
2904 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2906 p.rotate = parseFloat(rotatestr);
2907 set = set | SF_ROTATE;
2913 if(isRelative(shearstr))
2914 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2916 p.shear = parseFloat(shearstr);
2917 set = set | SF_SHEAR;
2922 if(isPoint(pivotstr))
2923 p.pivot = parsePoint(pivotstr);
2925 p.pivot = getPoint(oldbbox, pivotstr);
2926 set = set | SF_PIVOT;
2932 p.pin = parsePoint(pinstr);
2934 p.pin = getPoint(oldbbox, pinstr);
2938 /* color transform */
2940 if(rstr[0] || luminancestr[0])
2944 r = parseMulAdd(rstr);
2947 r.add = p.cxform.r0;
2948 r.mul = p.cxform.r1;
2950 r = mergeMulAdd(r, luminance);
2951 p.cxform.r0 = r.mul;
2952 p.cxform.r1 = r.add;
2953 set = set | SF_CX_R;
2955 if(gstr[0] || luminancestr[0])
2959 g = parseMulAdd(gstr);
2962 g.add = p.cxform.g0;
2963 g.mul = p.cxform.g1;
2965 g = mergeMulAdd(g, luminance);
2966 p.cxform.g0 = g.mul;
2967 p.cxform.g1 = g.add;
2968 set = set | SF_CX_G;
2970 if(bstr[0] || luminancestr[0])
2974 b = parseMulAdd(bstr);
2977 b.add = p.cxform.b0;
2978 b.mul = p.cxform.b1;
2980 b = mergeMulAdd(b, luminance);
2981 p.cxform.b0 = b.mul;
2982 p.cxform.b1 = b.add;
2983 set = set | SF_CX_B;
2987 MULADD a = parseMulAdd(astr);
2988 p.cxform.a0 = a.mul;
2989 p.cxform.a1 = a.add;
2990 set = set | SF_CX_A;
2997 for(t = 0; blendModeNames[t]; t++)
2999 if(!strcmp(blendModeNames[t], blendmode))
3007 syntaxerror("unknown blend mode: '%s'", blendmode);
3009 p.blendmode = blend;
3010 set = set | SF_BLEND;
3015 FILTER*f = dictionary_lookup(&filters, filterstr);
3017 syntaxerror("Unknown filter %s", filterstr);
3019 set = set | SF_FILTER;
3027 s_put(instance, character, p);
3031 char* interstr = lu(args, "interpolation");
3032 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3034 syntaxerror("unkown interpolation %s", interstr);
3035 s_change(instance, p, inter);
3039 s_qchange(instance, p);
3042 s_jump(instance, p);
3045 s_startclip(instance, character, p);
3049 s_buttonput(character, as, p);
3051 s_buttonput(character, "shape", p);
3057 static int c_put(map_t*args)
3059 c_placement(args, 0);
3062 static int c_change(map_t*args)
3064 if (currentframe == 0)
3065 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3066 c_placement(args, 1);
3069 static int c_qchange(map_t*args)
3071 c_placement(args, 2);
3074 static int c_arcchange(map_t*args)
3076 c_placement(args, 2);
3079 static int c_jump(map_t*args)
3081 c_placement(args, 3);
3084 static int c_startclip(map_t*args)
3086 c_placement(args, 4);
3089 static int c_show(map_t*args)
3091 c_placement(args, 5);
3094 static int c_del(map_t*args)
3096 char*instance = lu(args, "name");
3097 s_delinstance(instance);
3100 static int c_end(map_t*args)
3105 static int c_sprite(map_t*args)
3107 char* name = lu(args, "name");
3111 static int c_frame(map_t*args)
3113 char*framestr = lu(args, "n");
3114 char*cutstr = lu(args, "cut");
3116 char*name = lu(args, "name");
3117 char*anchor = lu(args, "anchor");
3120 if(!strcmp(anchor, "anchor") && !*name)
3125 if(strcmp(cutstr, "no"))
3127 if(isRelative(framestr)) {
3128 frame = s_getframe();
3129 if(getSign(framestr)<0)
3130 syntaxerror("relative frame expressions must be positive");
3131 frame += parseInt(getOffset(framestr));
3134 frame = parseInt(framestr);
3135 if(s_getframe() >= frame
3136 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3137 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3139 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3142 static int c_primitive(map_t*args)
3144 char*name = lu(args, "name");
3145 char*command = lu(args, "commandname");
3146 int width=0, height=0, r=0;
3147 int linewidth = parseTwip(lu(args, "line"));
3148 char*colorstr = lu(args, "color");
3149 RGBA color = parseColor(colorstr);
3150 char*fillstr = lu(args, "fill");
3157 if(!strcmp(command, "circle"))
3159 else if(!strcmp(command, "filled"))
3163 width = parseTwip(lu(args, "width"));
3164 height = parseTwip(lu(args, "height"));
3165 } else if (type==1) {
3166 r = parseTwip(lu(args, "r"));
3167 } else if (type==2) {
3168 outline = lu(args, "outline");
3171 if(!strcmp(fillstr, "fill"))
3173 if(!strcmp(fillstr, "none"))
3175 if(width<0 || height<0 || linewidth<0 || r<0)
3176 syntaxerror("values width, height, line, r must be positive");
3178 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3179 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3180 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3184 static int c_textshape(map_t*args)
3186 char*name = lu(args, "name");
3187 char*text = lu(args, "text");
3188 char*font = lu(args, "font");
3189 float size = parsePxOrPercent(font, lu(args, "size"));
3191 s_textshape(name, font, size, text);
3195 static int c_swf(map_t*args)
3197 char*name = lu(args, "name");
3198 char*filename = lu(args, "filename");
3199 char*command = lu(args, "commandname");
3200 if(!strcmp(command, "shape"))
3201 warning("Please use .swf instead of .shape");
3202 s_includeswf(name, filename);
3206 static int c_font(map_t*args)
3208 char*name = lu(args, "name");
3209 char*filename = lu(args, "filename");
3210 s_font(name, filename);
3214 static int c_sound(map_t*args)
3216 char*name = lu(args, "name");
3217 char*filename = lu(args, "filename");
3218 s_sound(name, filename);
3222 static int c_text(map_t*args)
3224 char*name = lu(args, "name");
3225 char*text = lu(args, "text");
3226 char*font = lu(args, "font");
3227 float size = parsePxOrPercent(font, lu(args, "size"));
3228 RGBA color = parseColor(lu(args, "color"));
3229 s_text(name, font, text, (int)(size*100), color);
3233 static int c_soundtrack(map_t*args)
3238 static int c_quicktime(map_t*args)
3240 char*name = lu(args, "name");
3241 char*url = lu(args, "url");
3242 s_quicktime(name, url);
3246 static int c_image(map_t*args)
3248 char*command = lu(args, "commandname");
3249 char*name = lu(args, "name");
3250 char*filename = lu(args, "filename");
3251 if(!strcmp(command,"jpeg")) {
3252 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3253 s_image(name, "jpeg", filename, quality);
3255 s_image(name, "png", filename, 0);
3260 static int c_outline(map_t*args)
3262 char*name = lu(args, "name");
3263 char*format = lu(args, "format");
3267 syntaxerror("colon (:) expected");
3269 s_outline(name, format, text);
3273 int fakechar(map_t*args)
3275 char*name = lu(args, "name");
3276 s_box(name, 0, 0, black, 20, 0);
3280 static int c_egon(map_t*args) {return fakechar(args);}
3281 static int c_button(map_t*args) {
3282 char*name = lu(args, "name");
3286 static int current_button_flags = 0;
3287 static int c_on_press(map_t*args)
3289 char*position = lu(args, "position");
3291 if(!strcmp(position, "inside")) {
3292 current_button_flags |= BC_OVERUP_OVERDOWN;
3293 } else if(!strcmp(position, "outside")) {
3294 //current_button_flags |= BC_IDLE_OUTDOWN;
3295 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3296 } else if(!strcmp(position, "anywhere")) {
3297 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3300 if(type == RAWDATA) {
3302 s_buttonaction(current_button_flags, action);
3303 current_button_flags = 0;
3309 static int c_on_release(map_t*args)
3311 char*position = lu(args, "position");
3313 if(!strcmp(position, "inside")) {
3314 current_button_flags |= BC_OVERDOWN_OVERUP;
3315 } else if(!strcmp(position, "outside")) {
3316 current_button_flags |= BC_OUTDOWN_IDLE;
3317 } else if(!strcmp(position, "anywhere")) {
3318 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3321 if(type == RAWDATA) {
3323 s_buttonaction(current_button_flags, action);
3324 current_button_flags = 0;
3330 static int c_on_move_in(map_t*args)
3332 char*position = lu(args, "state");
3334 if(!strcmp(position, "pressed")) {
3335 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3336 } else if(!strcmp(position, "not_pressed")) {
3337 current_button_flags |= BC_IDLE_OVERUP;
3338 } else if(!strcmp(position, "any")) {
3339 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3342 if(type == RAWDATA) {
3344 s_buttonaction(current_button_flags, action);
3345 current_button_flags = 0;
3351 static int c_on_move_out(map_t*args)
3353 char*position = lu(args, "state");
3355 if(!strcmp(position, "pressed")) {
3356 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3357 } else if(!strcmp(position, "not_pressed")) {
3358 current_button_flags |= BC_OVERUP_IDLE;
3359 } else if(!strcmp(position, "any")) {
3360 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3363 if(type == RAWDATA) {
3365 s_buttonaction(current_button_flags, action);
3366 current_button_flags = 0;
3372 static int c_on_key(map_t*args)
3374 char*key = lu(args, "key");
3376 if(strlen(key)==1) {
3379 current_button_flags |= 0x4000 + (key[0]*0x200);
3381 syntaxerror("invalid character: %c"+key[0]);
3386 <ctrl-x> = 0x200*(x-'a')
3390 syntaxerror("invalid key: %s",key);
3393 if(type == RAWDATA) {
3395 s_buttonaction(current_button_flags, action);
3396 current_button_flags = 0;
3403 static int c_edittext(map_t*args)
3405 //"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"},
3406 char*name = lu(args, "name");
3407 char*font = lu(args, "font");
3408 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3409 int width = parseTwip(lu(args, "width"));
3410 int height = parseTwip(lu(args, "height"));
3411 char*text = lu(args, "text");
3412 RGBA color = parseColor(lu(args, "color"));
3413 int maxlength = parseInt(lu(args, "maxlength"));
3414 char*variable = lu(args, "variable");
3415 char*passwordstr = lu(args, "password");
3416 char*wordwrapstr = lu(args, "wordwrap");
3417 char*multilinestr = lu(args, "multiline");
3418 char*htmlstr = lu(args, "html");
3419 char*noselectstr = lu(args, "noselect");
3420 char*readonlystr = lu(args, "readonly");
3421 char*borderstr = lu(args, "border");
3422 char*autosizestr = lu(args, "autosize");
3423 char*alignstr = lu(args, "align");
3427 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3428 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3429 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3430 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3431 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3432 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3433 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3434 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3435 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3436 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
3437 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
3438 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
3439 else syntaxerror("Unknown alignment: %s", alignstr);
3441 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
3445 static int c_morphshape(map_t*args) {return fakechar(args);}
3446 static int c_movie(map_t*args) {return fakechar(args);}
3448 static char* readfile(const char*filename)
3450 FILE*fi = fopen(filename, "rb");
3454 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
3455 fseek(fi, 0, SEEK_END);
3457 fseek(fi, 0, SEEK_SET);
3458 text = rfx_alloc(l+1);
3459 fread(text, l, 1, fi);
3465 static int c_action(map_t*args)
3467 char* filename = map_lookup(args, "filename");
3468 if(!filename ||!*filename) {
3470 if(type != RAWDATA) {
3471 syntaxerror("colon (:) expected");
3475 s_action(readfile(filename));
3481 static int c_initaction(map_t*args)
3483 char* character = lu(args, "name");
3484 char* filename = map_lookup(args, "filename");
3485 if(!filename ||!*filename) {
3487 if(type != RAWDATA) {
3488 syntaxerror("colon (:) expected");
3490 s_initaction(character, text);
3492 s_initaction(character, readfile(filename));
3500 command_func_t* func;
3503 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default"},
3504 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
3505 // "import" type stuff
3506 {"swf", c_swf, "name filename"},
3507 {"shape", c_swf, "name filename"},
3508 {"jpeg", c_image, "name filename quality=80%"},
3509 {"png", c_image, "name filename"},
3510 {"movie", c_movie, "name filename"},
3511 {"sound", c_sound, "name filename"},
3512 {"font", c_font, "name filename"},
3513 {"soundtrack", c_soundtrack, "filename"},
3514 {"quicktime", c_quicktime, "url"},
3516 // generators of primitives
3518 {"point", c_point, "name x=0 y=0"},
3519 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
3520 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5, damping=2"},
3521 {"outline", c_outline, "name format=simple"},
3522 {"textshape", c_textshape, "name font size=100% text"},
3525 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
3526 {"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"},
3527 {"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"},
3528 {"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"},
3530 // character generators
3531 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
3532 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
3533 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
3535 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
3536 {"text", c_text, "name text font size=100% color=white"},
3537 {"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="},
3538 {"morphshape", c_morphshape, "name start end"},
3539 {"button", c_button, "name"},
3540 {"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="},
3541 {"on_press", c_on_press, "position=inside"},
3542 {"on_release", c_on_release, "position=anywhere"},
3543 {"on_move_in", c_on_move_in, "state=not_pressed"},
3544 {"on_move_out", c_on_move_out, "state=not_pressed"},
3545 {"on_key", c_on_key, "key=any"},
3548 {"play", c_play, "name loop=0 @nomultiple=0"},
3549 {"stop", c_stop, "name= "},
3550 {"nextframe", c_nextframe, "name"},
3551 {"previousframe", c_previousframe, "name"},
3553 // object placement tags
3554 {"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="},
3555 {"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="},
3556 {"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"},
3557 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3558 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3559 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3560 {"del", c_del, "name"},
3561 // virtual object placement
3562 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
3564 // commands which start a block
3565 //startclip (see above)
3566 {"sprite", c_sprite, "name"},
3567 {"action", c_action, "filename="},
3568 {"initaction", c_initaction, "name filename="},
3574 static map_t parseArguments(char*command, char*pattern)
3590 string_set(&t1, "commandname");
3591 string_set(&t2, command);
3592 map_put(&result, t1, t2);
3594 if(!pattern || !*pattern)
3601 if(!strncmp("<i> ", x, 3)) {
3603 if(type == COMMAND || type == RAWDATA) {
3605 syntaxerror("character name expected");
3607 name[pos].str = "instance";
3609 value[pos].str = text;
3610 value[pos].len = strlen(text);
3614 if(type == ASSIGNMENT)
3617 name[pos].str = "character";
3619 value[pos].str = text;
3620 value[pos].len = strlen(text);
3628 isboolean[pos] = (x[0] =='@');
3641 name[pos].len = d-x;
3646 name[pos].len = e-x;
3647 value[pos].str = e+1;
3648 value[pos].len = d-e-1;
3656 /* for(t=0;t<len;t++) {
3657 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
3658 isboolean[t]?"(boolean)":"");
3663 if(type == RAWDATA || type == COMMAND) {
3668 // first, search for boolean arguments
3669 for(pos=0;pos<len;pos++)
3671 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
3673 if(type == ASSIGNMENT)
3675 value[pos].str = text;
3676 value[pos].len = strlen(text);
3677 /*printf("setting boolean parameter %s (to %s)\n",
3678 strdup_n(name[pos], namelen[pos]),
3679 strdup_n(value[pos], valuelen[pos]));*/
3684 // second, search for normal arguments
3686 for(pos=0;pos<len;pos++)
3688 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
3689 (type != ASSIGNMENT && !set[pos])) {
3691 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
3693 if(type == ASSIGNMENT)
3696 value[pos].str = text;
3697 value[pos].len = strlen(text);
3699 printf("setting parameter %s (to %s)\n",
3700 strdup_n(name[pos].str, name[pos].len),
3701 strdup_n(value[pos].str, value[pos].len));
3707 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
3711 for(t=0;t<len;t++) {
3712 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
3715 for(t=0;t<len;t++) {
3716 if(value[t].str && value[t].str[0] == '*') {
3717 //relative default- take value from some other parameter
3719 for(s=0;s<len;s++) {
3720 if(value[s].len == value[t].len-1 &&
3721 !strncmp(&value[t].str[1], value[s].str, value[s].len))
3722 value[t].str = value[s].str;
3725 if(value[t].str == 0) {
3727 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
3731 /* ok, now construct the dictionary from the parameters */
3735 map_put(&result, name[t], value[t]);
3739 static void parseArgumentsForCommand(char*command)
3744 msg("<verbose> parse Command: %s (line %d)", command, line);
3746 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
3747 if(!strcmp(arguments[t].command, command)) {
3749 /* ugly hack- will be removed soon (once documentation and .sc generating
3750 utilities have been changed) */
3751 if(!strcmp(command, "swf") && !stackpos) {
3752 warning("Please use .flash instead of .swf- this will be mandatory soon");
3757 args = parseArguments(command, arguments[t].arguments);
3763 syntaxerror("command %s not known", command);
3765 // catch missing .flash directives at the beginning of a file
3766 if(strcmp(command, "flash") && !stackpos)
3768 syntaxerror("No movie defined- use .flash first");
3772 printf(".%s\n", command);fflush(stdout);
3773 map_dump(&args, stdout, "\t");fflush(stdout);
3776 (*arguments[nr].func)(&args);
3778 /*if(!strcmp(command, "button") ||
3779 !strcmp(command, "action")) {
3782 if(type == COMMAND) {
3783 if(!strcmp(text, "end"))
3798 /* for now only intended to find what glyphs of each font are to be included in the swf file.
3799 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
3800 * No syntax checking is done */
3801 static void analyseArgumentsForCommand(char*command)
3807 msg("<verbose> analyse Command: %s (line %d)", command, line);
3809 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
3811 if(!strcmp(arguments[t].command, command))
3813 args = parseArguments(command, arguments[t].arguments);
3819 printf(".%s\n", command);fflush(stdout);
3820 map_dump(&args, stdout, "\t");fflush(stdout);
3822 char* name = lu(&args, "name");
3823 if (!strcmp(command, "font"))
3825 if(dictionary_lookup(&fonts, name))
3826 syntaxerror("font %s defined twice", name);
3829 fontfile = lu(&args, "filename");
3830 font = swf_LoadFont(fontfile);
3832 warning("Couldn't open font file \"%s\"", fontfile);
3833 font = (SWFFONT*)malloc(sizeof(SWFFONT));
3834 memset(font, 0, sizeof(SWFFONT));
3836 swf_FontPrepareForEditText(font);
3837 dictionary_put2(&fonts, name, font);
3841 SWFFONT* font = dictionary_lookup(&fonts, lu(&args, "font"));
3843 syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
3845 if (!strcmp(command, "edittext"))
3846 swf_FontUseAll(font);
3848 swf_FontUseUTF8(font, lu(&args, "text"));
3854 void skipParameters()
3858 while (type != COMMAND);
3862 void findFontUsage()
3864 char* fontRelated = "font;text;textshape;edittext;";
3865 while(!noMoreTokens())
3869 syntaxerror("command expected");
3870 if (strstr(fontRelated, text))
3871 analyseArgumentsForCommand(text);
3873 if(strcmp(text, "end"))
3882 dictionary_init(&fonts);
3883 cleanUp = &freeFontDictionary;
3887 int main (int argc,char ** argv)
3890 processargs(argc, argv);
3891 initLog(0,-1,0,0,-1,verbose);
3894 args_callback_usage(argv[0]);
3898 file = generateTokens(filename);
3900 fprintf(stderr, "parser returned error.\n");
3907 while(!noMoreTokens()) {
3910 syntaxerror("command expected");
3911 parseArgumentsForCommand(text);