2 Compiles swf code (.sc) files into .swf files.
4 Part of the swftools package.
6 Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
29 #include "../config.h"
30 #include "../lib/rfxswf.h"
31 #include "../lib/drawer.h"
32 #include "../lib/log.h"
33 #include "../lib/args.h"
35 #include "../lib/mp3.h"
36 #include "../lib/wav.h"
38 #include "../lib/png.h"
39 #include "swfc-feedback.h"
40 #include "swfc-interpolation.h"
41 #include "swfc-history.h"
44 static char * outputname = "output.swf";
45 static int verbose = 2;
46 static int optimize = 0;
47 static int override_outputname = 0;
48 static int do_cgi = 0;
49 static int change_sets_all = 0;
51 static struct options_t options[] = {
60 int args_callback_option(char*name,char*val)
62 if(!strcmp(name, "V")) {
63 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
66 else if(!strcmp(name, "o")) {
68 override_outputname = 1;
71 else if(!strcmp(name, "O")) {
75 else if(!strcmp(name, "C")) {
79 else if(!strcmp(name, "v")) {
84 printf("Unknown option: -%s\n", name);
89 int args_callback_longoption(char*name,char*val)
91 return args_long2shortoption(options, name, val);
93 void args_callback_usage(char *name)
96 printf("Usage: %s [-o file.swf] file.sc\n", name);
98 printf("-h , --help Print short help message and exit\n");
99 printf("-V , --version Print version info and exit\n");
100 printf("-C , --cgi Output to stdout (for use in CGI environments)\n");
101 printf("-v , --verbose Increase verbosity. \n");
102 printf("-o , --output <filename> Set output file to <filename>.\n");
105 int args_callback_command(char*name,char*val)
108 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
115 static struct token_t* file;
122 static void readToken()
124 type = file[pos].type;
126 syntaxerror("unexpected end of file");
128 text = file[pos].text;
129 textlen = strlen(text);
130 line = file[pos].line;
131 column = file[pos].column;
133 //printf("---> %d(%s) %s\n", type, type_names[type], text);
136 static void pushBack()
139 if(!pos) syntaxerror("internal error 3");
144 textlen = strlen(text);
147 column = file[p].column;
150 static int noMoreTokens()
152 if(file[pos].type == END)
157 // ------------------------------ swf routines ----------------------------
161 int type; //0=swf, 1=sprite, 2=clip, 3=button
167 /* for sprites (1): */
173 dictionary_t oldinstances;
178 static int stackpos = 0;
180 static dictionary_t characters;
181 static dictionary_t images;
182 static dictionary_t textures;
183 static dictionary_t outlines;
184 static dictionary_t gradients;
185 static dictionary_t filters;
186 static dictionary_t interpolations;
187 static char idmap[65536];
188 static TAG*tag = 0; //current tag
190 static int id; //current character id
191 static int currentframe; //current frame in current level
192 static SRECT currentrect; //current bounding box in current level
193 static U16 currentdepth;
194 static dictionary_t instances;
195 static dictionary_t fonts;
196 static dictionary_t sounds;
197 static dictionary_t fontUsage;
199 typedef struct _parameters {
201 float scalex, scaley;
207 U8 blendmode; //not interpolated
209 U16 set; // bits indicating wether a parameter was set in the c_placement function
212 typedef struct _character {
218 typedef struct _instance {
219 character_t*character;
221 parameters_t parameters;
222 TAG* lastTag; //last tag which set the object
223 U16 lastFrame; //frame lastTag is in
227 typedef struct _outline {
232 typedef struct _gradient {
238 typedef struct _filter {
242 typedef struct _texture {
246 char* interpolationFunctions[] = {"linear", \
247 "quadIn", "quadOut", "quadInOut", \
248 "cubicIn", "cubicOut", "cubicInOut", \
249 "quartIn", "quartOut", "quartInOut", \
250 "quintIn", "quintOut", "quintInOut", \
251 "circleIn", "circleOut", "circleInOut", \
252 "exponentialIn", "exponentialOut", "exponentialInOut", \
253 "sineIn", "sineOut", "sineInOut", \
254 "elasticIn", "elasticOut", "elasticInOut", \
255 "backIn", "backOut", "backInOut", \
256 "bounceIn", "bounceOut", "bounceInOut", \
257 "fastBounceIn", "fastBounceOut", "fastBounceInOut"};
259 static void character_init(character_t*c)
261 memset(c, 0, sizeof(character_t));
264 static character_t* character_new()
267 c = (character_t*)malloc(sizeof(character_t));
272 static void instance_init(instance_t*i)
274 memset(i, 0, sizeof(instance_t));
275 i->history = history_new();
278 static void instance_free(instance_t* i)
280 history_free(i->history);
284 static instance_t* instance_new()
287 c = (instance_t*)malloc(sizeof(instance_t));
292 static void free_instance(void* i)
294 instance_free((instance_t*)i);
297 static void free_font(void* f)
299 swf_FontFree((SWFFONT*)f);
302 static void gradient_free(GRADIENT* grad)
309 static void free_gradient(void* grad)
311 gradient_free((GRADIENT*) grad);
314 static void outline_free(outline_t* o)
316 free(o->shape->data);
321 static void free_outline(void* o)
323 outline_free((outline_t*)o);
326 static void freeDictionaries()
328 dictionary_free_all(&instances, free_instance);
329 dictionary_free_all(&characters, free);
330 dictionary_free_all(&images, free);
331 dictionary_free_all(&textures, free);
332 dictionary_free_all(&outlines, free_outline);
333 dictionary_free_all(&gradients, free_gradient);
334 dictionary_free_all(&filters, free);
335 dictionary_free_all(&fonts, free_font);
336 dictionary_free_all(&sounds, free);
337 dictionary_free_all(&interpolations, free);
340 static void freeFontDictionary()
342 dictionary_free_all(&fonts, free_font);
345 static void incrementid()
349 syntaxerror("Out of character ids.");
354 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
356 if(dictionary_lookup(&characters, name))
357 syntaxerror("character %s defined twice", name);
358 character_t* c = character_new();
360 c->definingTag = ctag;
363 dictionary_put2(&characters, name, c);
365 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
367 swf_SetString(tag, name);
368 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
371 swf_SetString(tag, name);
373 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
375 if(dictionary_lookup(&images, name))
376 syntaxerror("image %s defined twice", name);
378 character_t* c = character_new();
379 c->definingTag = ctag;
382 dictionary_put2(&images, name, c);
384 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
386 if(dictionary_lookup(&instances, name))
387 syntaxerror("object %s defined twice", name);
388 instance_t* i = instance_new();
391 //swf_GetMatrix(0, &i->matrix);
392 dictionary_put2(&instances, name, i);
396 static void parameters_clear(parameters_t*p)
399 p->scalex = 1.0; p->scaley = 1.0;
402 p->pivot.x = 0; p->pivot.y = 0;
407 swf_GetCXForm(0, &p->cxform, 1);
410 static void makeMatrix(MATRIX*m, parameters_t*p)
419 sx = p->scalex*cos(p->rotate/360*2*PI);
420 r1 = -p->scalex*sin(p->rotate/360*2*PI)+sx*p->shear;
421 r0 = p->scaley*sin(p->rotate/360*2*PI);
422 sy = p->scaley*cos(p->rotate/360*2*PI)+r0*p->shear;
424 m->sx = (int)(sx*65536+0.5);
425 m->r1 = (int)(r1*65536+0.5);
426 m->r0 = (int)(r0*65536+0.5);
427 m->sy = (int)(sy*65536+0.5);
431 h = swf_TurnPoint(p->pin, m);
436 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
441 r = swf_TurnRect(rect, &m);
442 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
443 currentrect.xmax == 0 && currentrect.ymax == 0)
446 swf_ExpandRect2(¤trect, &r);
452 interpolation_t* new;
453 new = (interpolation_t*)malloc(sizeof(interpolation_t));
454 new->function = IF_LINEAR;
455 dictionary_put2(&interpolations, "linear", new);
457 new = (interpolation_t*)malloc(sizeof(interpolation_t));
458 new->function = IF_QUAD_IN;
459 dictionary_put2(&interpolations, "quadIn", new);
460 new = (interpolation_t*)malloc(sizeof(interpolation_t));
461 new->function = IF_QUAD_OUT;
462 dictionary_put2(&interpolations, "quadOut", new);
463 new = (interpolation_t*)malloc(sizeof(interpolation_t));
464 new->function = IF_QUAD_IN_OUT;
465 dictionary_put2(&interpolations, "quadInOut", new);
467 new = (interpolation_t*)malloc(sizeof(interpolation_t));
468 new->function = IF_CUBIC_IN;
469 dictionary_put2(&interpolations, "cubicIn", new);
470 new = (interpolation_t*)malloc(sizeof(interpolation_t));
471 new->function = IF_CUBIC_OUT;
472 dictionary_put2(&interpolations, "cubicOut", new);
473 new = (interpolation_t*)malloc(sizeof(interpolation_t));
474 new->function = IF_CUBIC_IN_OUT;
475 dictionary_put2(&interpolations, "cubicInOut", new);
477 new = (interpolation_t*)malloc(sizeof(interpolation_t));
478 new->function = IF_QUART_IN;
479 dictionary_put2(&interpolations, "quartIn", new);
480 new = (interpolation_t*)malloc(sizeof(interpolation_t));
481 new->function = IF_QUART_OUT;
482 dictionary_put2(&interpolations, "quartOut", new);
483 new = (interpolation_t*)malloc(sizeof(interpolation_t));
484 new->function = IF_QUART_IN_OUT;
485 dictionary_put2(&interpolations, "quartInOut", new);
487 new = (interpolation_t*)malloc(sizeof(interpolation_t));
488 new->function = IF_QUINT_IN;
489 dictionary_put2(&interpolations, "quintIn", new);
490 new = (interpolation_t*)malloc(sizeof(interpolation_t));
491 new->function = IF_QUINT_OUT;
492 dictionary_put2(&interpolations, "quintOut", new);
493 new = (interpolation_t*)malloc(sizeof(interpolation_t));
494 new->function = IF_QUINT_IN_OUT;
495 dictionary_put2(&interpolations, "quintInOut", new);
497 new = (interpolation_t*)malloc(sizeof(interpolation_t));
498 new->function = IF_CIRCLE_IN;
499 dictionary_put2(&interpolations, "circleIn", new);
500 new = (interpolation_t*)malloc(sizeof(interpolation_t));
501 new->function = IF_CIRCLE_OUT;
502 dictionary_put2(&interpolations, "circleOut", new);
503 new = (interpolation_t*)malloc(sizeof(interpolation_t));
504 new->function = IF_CIRCLE_IN_OUT;
505 dictionary_put2(&interpolations, "circleInOut", new);
507 new = (interpolation_t*)malloc(sizeof(interpolation_t));
508 new->function = IF_EXPONENTIAL_IN;
509 dictionary_put2(&interpolations, "exponentialIn", new);
510 new = (interpolation_t*)malloc(sizeof(interpolation_t));
511 new->function = IF_EXPONENTIAL_OUT;
512 dictionary_put2(&interpolations, "exponentialOut", new);
513 new = (interpolation_t*)malloc(sizeof(interpolation_t));
514 new->function = IF_EXPONENTIAL_IN_OUT;
515 dictionary_put2(&interpolations, "exponentialInOut", new);
517 new = (interpolation_t*)malloc(sizeof(interpolation_t));
518 new->function = IF_SINE_IN;
519 dictionary_put2(&interpolations, "sineIn", new);
520 new = (interpolation_t*)malloc(sizeof(interpolation_t));
521 new->function = IF_SINE_OUT;
522 dictionary_put2(&interpolations, "sineOut", new);
523 new = (interpolation_t*)malloc(sizeof(interpolation_t));
524 new->function = IF_SINE_IN_OUT;
525 dictionary_put2(&interpolations, "sineInOut", new);
528 memset(&c, 0, sizeof(RGBA));
529 gradient_t* noGradient = (gradient_t*)malloc(sizeof(gradient_t));
530 noGradient->gradient.ratios = (U8*)malloc(16 * sizeof(U8));
531 noGradient->gradient.rgba = (RGBA*)malloc(16 * sizeof(RGBA));
532 noGradient->gradient.num = 2;
533 noGradient->gradient.rgba[0] = c;
534 noGradient->gradient.ratios[0] = 0;
535 noGradient->gradient.rgba[1] = c;
536 noGradient->gradient.ratios[1] = 255;
537 noGradient->radial = 0;
538 noGradient->rotate = 0;
539 dictionary_put2(&gradients, "no_gradient", noGradient);
541 noBlur = (FILTER_BLUR*) swf_NewFilter(FILTERTYPE_BLUR);
543 dictionary_put2(&filters, "no_blur", noBlur);
544 noBevel = (FILTER_BEVEL*) swf_NewFilter(FILTERTYPE_BEVEL);
546 dictionary_put2(&filters, "no_bevel", noBevel);
547 noDropshadow = (FILTER_DROPSHADOW*) swf_NewFilter(FILTERTYPE_DROPSHADOW);
548 noDropshadow->passes = 1;
549 dictionary_put2(&filters, "no_dropshadow", noDropshadow);
550 noGradientGlow = (FILTER_GRADIENTGLOW*) swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
551 noGradientGlow->passes = 1;
552 noGradientGlow->gradient = &noGradient->gradient;
553 dictionary_put2(&filters, "no_gradientglow", noGradientGlow);
556 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
559 syntaxerror(".swf blocks can't be nested");
560 if(stackpos==sizeof(stack)/sizeof(stack[0]))
561 syntaxerror("too many levels of recursion");
563 SWF*swf = (SWF*)malloc(sizeof(SWF));
565 memset(swf, 0, sizeof(swf));
566 swf->fileVersion = version;
568 swf->frameRate = fps;
569 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
570 swf->compressed = compress;
571 swf_SetRGB(tag,&background);
573 dictionary_init(&characters);
574 dictionary_init(&images);
575 dictionary_init(&textures);
576 dictionary_init(&outlines);
577 dictionary_init(&gradients);
578 dictionary_init(&filters);
579 dictionary_init(&instances);
580 dictionary_init(&sounds);
581 dictionary_init(&interpolations);
583 cleanUp = &freeDictionaries;
585 memset(&stack[stackpos], 0, sizeof(stack[0]));
586 stack[stackpos].type = 0;
587 stack[stackpos].filename = strdup(name);
588 stack[stackpos].swf = swf;
589 stack[stackpos].oldframe = -1;
593 memset(¤trect, 0, sizeof(currentrect));
596 memset(idmap, 0, sizeof(idmap));
600 void s_sprite(char*name)
602 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
603 swf_SetU16(tag, id); //id
604 swf_SetU16(tag, 0); //frames
606 memset(&stack[stackpos], 0, sizeof(stack[0]));
607 stack[stackpos].type = 1;
608 stack[stackpos].oldframe = currentframe;
609 stack[stackpos].olddepth = currentdepth;
610 stack[stackpos].oldrect = currentrect;
611 stack[stackpos].oldinstances = instances;
612 stack[stackpos].tag = tag;
613 stack[stackpos].id = id;
614 stack[stackpos].name = strdup(name);
616 /* FIXME: those four fields should be bundled together */
617 dictionary_init(&instances);
620 memset(¤trect, 0, sizeof(currentrect));
626 typedef struct _buttonrecord
634 typedef struct _button
638 buttonrecord_t records[4];
641 static button_t mybutton;
643 void s_button(char*name)
645 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
646 swf_SetU16(tag, id); //id
647 swf_ButtonSetFlags(tag, 0); //menu=no
649 memset(&mybutton, 0, sizeof(mybutton));
651 memset(&stack[stackpos], 0, sizeof(stack[0]));
652 stack[stackpos].type = 3;
653 stack[stackpos].tag = tag;
654 stack[stackpos].id = id;
655 stack[stackpos].name = strdup(name);
656 stack[stackpos].oldrect = currentrect;
657 memset(¤trect, 0, sizeof(currentrect));
662 void s_buttonput(char*character, char*as, parameters_t p)
664 character_t* c = dictionary_lookup(&characters, character);
669 if(!stackpos || (stack[stackpos-1].type != 3)) {
670 syntaxerror(".show may only appear in .button");
673 syntaxerror("character %s not known (in .shape %s)", character, character);
675 if(mybutton.endofshapes) {
676 syntaxerror("a .do may not precede a .show", character, character);
679 m = s_instancepos(c->size, &p);
687 if(*s==',' || *s==0) {
688 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
689 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
690 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
691 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
692 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
693 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
700 static void setbuttonrecords(TAG*tag)
702 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
703 if(!mybutton.endofshapes) {
706 if(!mybutton.records[3].set) {
707 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
711 if(mybutton.records[t].set) {
712 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
715 swf_SetU8(tag,0); // end of button records
716 mybutton.endofshapes = 1;
720 void s_buttonaction(int flags, char*action)
726 setbuttonrecords(stack[stackpos-1].tag);
728 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
730 syntaxerror("Couldn't compile ActionScript");
733 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
734 swf_ActionSet(stack[stackpos-1].tag, a);
735 mybutton.nr_actions++;
740 static void setactionend(TAG*tag)
742 if(!mybutton.nr_actions) {
743 /* no actions means we didn't have an actionoffset,
744 which means we can't signal the end of the
745 buttonaction records, so, *sigh*, we have
746 to insert a dummy record */
747 swf_SetU16(tag, 0); //offset
748 swf_SetU16(tag, 0); //condition
749 swf_SetU8(tag, 0); //action
753 static void s_endButton()
756 setbuttonrecords(stack[stackpos-1].tag);
757 setactionend(stack[stackpos-1].tag);
760 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
764 tag = stack[stackpos].tag;
765 currentrect = stack[stackpos].oldrect;
767 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
768 free(stack[stackpos].name);
771 TAG* removeFromTo(TAG*from, TAG*to)
773 TAG*save = from->prev;
775 TAG*next = from->next;
783 static int parametersChange(history_t* history, int frame)
787 willChange = willChange || history_change(history, frame, "x");
788 willChange = willChange || history_change(history, frame, "y");
789 willChange = willChange || history_change(history, frame, "scalex");
790 willChange = willChange || history_change(history, frame, "scaley");
791 willChange = willChange || history_change(history, frame, "cxform.r0");
792 willChange = willChange || history_change(history, frame, "cxform.g0");
793 willChange = willChange || history_change(history, frame, "cxform.b0");
794 willChange = willChange || history_change(history, frame, "cxform.a0");
795 willChange = willChange || history_change(history, frame, "cxform.r1");
796 willChange = willChange || history_change(history, frame, "cxform.g1");
797 willChange = willChange || history_change(history, frame, "cxform.b1");
798 willChange = willChange || history_change(history, frame, "cxform.a1");
799 willChange = willChange || history_change(history, frame, "rotate");
800 willChange = willChange || history_change(history, frame, "shear");
801 willChange = willChange || history_change(history, frame, "pivot.x");
802 willChange = willChange || history_change(history, frame, "pivot.y");
803 willChange = willChange || history_change(history, frame, "pin.x");
804 willChange = willChange || history_change(history, frame, "pin.y");
805 willChange = willChange || history_change(history, frame, "blendmode");
806 willChange = willChange || history_changeFilter(history, frame);
811 static void readParameters(history_t* history, parameters_t* p, int frame)
813 p->x = history_value(history, frame, "x");
814 p->y = history_value(history, frame, "y");
815 p->scalex = history_value(history, frame, "scalex");
816 p->scaley = history_value(history, frame, "scaley");
817 p->cxform.r0 = history_value(history, frame, "cxform.r0");
818 p->cxform.g0 = history_value(history, frame, "cxform.g0");
819 p->cxform.b0 = history_value(history, frame, "cxform.b0");
820 p->cxform.a0 = history_value(history, frame, "cxform.a0");
821 p->cxform.r1 = history_value(history, frame, "cxform.r1");
822 p->cxform.g1 = history_value(history, frame, "cxform.g1");
823 p->cxform.b1 = history_value(history, frame, "cxform.b1");
824 p->cxform.a1 = history_value(history, frame, "cxform.a1");
825 p->rotate = history_value(history, frame, "rotate");
826 p->shear = history_value(history, frame, "shear");
827 p->pivot.x = history_value(history, frame, "pivot.x");
828 p->pivot.y = history_value(history, frame, "pivot.y");
829 p->pin.x = history_value(history, frame, "pin.x");
830 p->pin.y = history_value(history, frame, "pin.y");
831 p->blendmode = history_value(history, frame, "blendmode");
832 p->filter = history_valueFilter(history, frame);
835 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move)
839 swf_GetPlaceObject(NULL, &po);
843 po.cxform = p->cxform;
849 po.blendmode = p->blendmode;
853 flist.filter[0] = p->filter;
856 swf_SetPlaceObject(tag, &po);
859 static void writeInstance(instance_t* i)
863 int frame = i->history->firstFrame;
864 TAG* tag = i->history->firstTag;
865 while (frame < currentframe)
868 while (tag->id != ST_SHOWFRAME)
870 if (parametersChange(i->history, frame))
872 readParameters(i->history, &p, frame);
873 m = s_instancepos(i->character->size, &p);
875 if(p.blendmode || p.filter)
876 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
878 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
879 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
882 if (p.filter->type == FILTERTYPE_GRADIENTGLOW)
883 gradient_free(((FILTER_GRADIENTGLOW*)p.filter)->gradient);
892 void dumpSWF(SWF*swf)
894 TAG* tag = swf->firstTag;
895 printf("vvvvvvvvvvvvvvvvvvvvv\n");
897 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
900 printf("^^^^^^^^^^^^^^^^^^^^^\n");
903 static void s_endSprite()
905 SRECT r = currentrect;
907 if(stack[stackpos].cut)
908 tag = removeFromTo(stack[stackpos].cut, tag);
912 stringarray_t* index =dictionary_index(&instances);
914 char* name = stringarray_at(index, num);
917 i = dictionary_lookup(&instances, name);
920 name = stringarray_at(index, num);
925 tag = swf_InsertTag(tag, ST_SHOWFRAME);
926 tag = swf_InsertTag(tag, ST_END);
928 tag = stack[stackpos].tag;
931 syntaxerror("internal error(7)");
932 /* TODO: before clearing, prepend "<spritename>." to names and
933 copy into old instances dict */
934 dictionary_free_all(&instances, free_instance);
936 currentframe = stack[stackpos].oldframe;
937 currentrect = stack[stackpos].oldrect;
938 currentdepth = stack[stackpos].olddepth;
939 instances = stack[stackpos].oldinstances;
941 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
942 free(stack[stackpos].name);
945 static void s_endSWF()
952 stringarray_t* index = dictionary_index(&instances);
954 char* name = stringarray_at(index, num);
957 i = dictionary_lookup(&instances, name);
960 name = stringarray_at(index, num);
963 if(stack[stackpos].cut)
964 tag = removeFromTo(stack[stackpos].cut, tag);
968 swf = stack[stackpos].swf;
969 filename = stack[stackpos].filename;
971 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
972 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
973 tag = swf_InsertTag(tag, ST_SHOWFRAME);
975 tag = swf_InsertTag(tag, ST_END);
977 swf_OptimizeTagOrder(swf);
983 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
984 swf->movieSize = currentrect; /* "autocrop" */
987 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
988 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
989 swf->movieSize.ymax += 20;
990 warning("Empty bounding box for movie");
993 if(do_cgi || !strcmp(filename, "-"))
996 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
998 syntaxerror("couldn't create output file %s", filename);
1001 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
1002 else if(swf->compressed)
1003 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
1005 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
1019 if(stack[stackpos-1].type == 0)
1020 syntaxerror("End of file encountered in .flash block");
1021 if(stack[stackpos-1].type == 1)
1022 syntaxerror("End of file encountered in .sprite block");
1023 if(stack[stackpos-1].type == 2)
1024 syntaxerror("End of file encountered in .clip block");
1030 return currentframe+1;
1033 void s_frame(int nr, int cut, char*name, char anchor)
1039 syntaxerror("Illegal frame number");
1040 nr--; // internally, frame 1 is frame 0
1042 for(t=currentframe;t<nr;t++) {
1043 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1044 if(t==nr-1 && name && *name) {
1045 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1046 swf_SetString(tag, name);
1048 swf_SetU8(tag, 1); //make this an anchor
1051 if(nr == 0 && currentframe == 0 && name && *name) {
1052 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1053 swf_SetString(tag, name);
1055 swf_SetU8(tag, 1); //make this an anchor
1060 syntaxerror("Can't cut, frame empty");
1062 stack[stackpos].cut = tag;
1068 int parseColor2(char*str, RGBA*color);
1070 int addFillStyle(SHAPE*s, SRECT*r, char*name)
1074 gradient_t*gradient;
1076 if(name[0] == '#') {
1077 parseColor2(name, &color);
1078 return swf_ShapeAddSolidFillStyle(s, &color);
1079 } else if ((texture = dictionary_lookup(&textures, name))) {
1080 return swf_ShapeAddFillStyle2(s, &texture->fs);
1081 } else if((image = dictionary_lookup(&images, name))) {
1083 swf_GetMatrix(0, &m);
1084 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1085 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1088 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1089 } else if ((gradient = dictionary_lookup(&gradients, name))) {
1093 swf_GetMatrix(0, &rot);
1094 ccos = cos(-gradient->rotate*2*PI/360);
1095 csin = sin(-gradient->rotate*2*PI/360);
1096 rot.sx = ccos*65536;
1097 rot.r1 = -csin*65536;
1098 rot.r0 = csin*65536;
1099 rot.sy = ccos*65536;
1100 r2 = swf_TurnRect(*r, &rot);
1101 swf_GetMatrix(0, &m);
1102 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1103 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1104 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1105 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1106 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1107 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1108 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1109 } else if (parseColor2(name, &color)) {
1110 return swf_ShapeAddSolidFillStyle(s, &color);
1112 syntaxerror("not a color/fillstyle: %s", name);
1117 RGBA black={r:0,g:0,b:0,a:0};
1118 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
1127 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1130 linewidth = linewidth>=20?linewidth-20:0;
1131 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1134 fs1 = addFillStyle(s, &r2, texture);
1137 r.xmin = r2.xmin-linewidth/2;
1138 r.ymin = r2.ymin-linewidth/2;
1139 r.xmax = r2.xmax+linewidth/2;
1140 r.ymax = r2.ymax+linewidth/2;
1141 swf_SetRect(tag,&r);
1142 swf_SetShapeHeader(tag,s);
1143 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1144 swf_ShapeSetLine(tag,s,width,0);
1145 swf_ShapeSetLine(tag,s,0,height);
1146 swf_ShapeSetLine(tag,s,-width,0);
1147 swf_ShapeSetLine(tag,s,0,-height);
1148 swf_ShapeSetEnd(tag);
1151 s_addcharacter(name, id, tag, r);
1155 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
1161 outline = dictionary_lookup(&outlines, outlinename);
1163 syntaxerror("outline %s not defined", outlinename);
1167 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1170 linewidth = linewidth>=20?linewidth-20:0;
1171 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1174 fs1 = addFillStyle(s, &r2, texture);
1177 rect.xmin = r2.xmin-linewidth/2;
1178 rect.ymin = r2.ymin-linewidth/2;
1179 rect.xmax = r2.xmax+linewidth/2;
1180 rect.ymax = r2.ymax+linewidth/2;
1182 swf_SetRect(tag,&rect);
1183 swf_SetShapeStyles(tag, s);
1184 swf_ShapeCountBits(s,0,0);
1185 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1186 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1187 swf_SetShapeBits(tag, s);
1188 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1191 s_addcharacter(name, id, tag, rect);
1195 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
1200 r2.xmin = r2.ymin = 0;
1204 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1207 linewidth = linewidth>=20?linewidth-20:0;
1208 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1211 fs1 = addFillStyle(s, &r2, texture);
1213 rect.xmin = r2.xmin-linewidth/2;
1214 rect.ymin = r2.ymin-linewidth/2;
1215 rect.xmax = r2.xmax+linewidth/2;
1216 rect.ymax = r2.ymax+linewidth/2;
1218 swf_SetRect(tag,&rect);
1219 swf_SetShapeHeader(tag,s);
1220 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1221 swf_ShapeSetCircle(tag, s, r,r,r,r);
1222 swf_ShapeSetEnd(tag);
1225 s_addcharacter(name, id, tag, rect);
1229 void s_textshape(char*name, char*fontname, float size, char*_text)
1232 U8*text = (U8*)_text;
1236 font = dictionary_lookup(&fonts, fontname);
1238 syntaxerror("font \"%s\" not known!", fontname);
1240 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1241 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1242 s_box(name, 0, 0, black, 20, 0);
1245 g = font->ascii2glyph[text[0]];
1247 outline = malloc(sizeof(outline_t));
1248 memset(outline, 0, sizeof(outline_t));
1249 outline->shape = font->glyph[g].shape;
1250 outline->bbox = font->layout->bounds[g];
1254 swf_Shape11DrawerInit(&draw, 0);
1255 swf_DrawText(&draw, font, (int)(size*100), _text);
1257 outline->shape = swf_ShapeDrawerToShape(&draw);
1258 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1259 draw.dealloc(&draw);
1262 if(dictionary_lookup(&outlines, name))
1263 syntaxerror("outline %s defined twice", name);
1264 dictionary_put2(&outlines, name, outline);
1267 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
1272 font = dictionary_lookup(&fonts, fontname);
1274 syntaxerror("font \"%s\" not known!", fontname);
1276 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1277 swf_SetU16(tag, id);
1278 if(!font->numchars) {
1279 s_box(name, 0, 0, black, 20, 0);
1282 r = swf_SetDefineText(tag, font, &color, text, size);
1284 if(stack[0].swf->fileVersion >= 8) {
1285 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1286 swf_SetU16(tag, id);
1287 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1288 swf_SetU32(tag, 0);//thickness
1289 swf_SetU32(tag, 0);//sharpness
1290 swf_SetU8(tag, 0);//reserved
1293 s_addcharacter(name, id, tag, r);
1297 void s_quicktime(char*name, char*url)
1302 memset(&r, 0, sizeof(r));
1304 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1305 swf_SetU16(tag, id);
1306 swf_SetString(tag, url);
1308 s_addcharacter(name, id, tag, r);
1312 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)
1315 EditTextLayout layout;
1318 if(fontname && *fontname) {
1319 flags |= ET_USEOUTLINES;
1320 font = dictionary_lookup(&fonts, fontname);
1322 syntaxerror("font \"%s\" not known!", fontname);
1324 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1325 swf_SetU16(tag, id);
1326 layout.align = align;
1327 layout.leftmargin = 0;
1328 layout.rightmargin = 0;
1336 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
1338 s_addcharacter(name, id, tag, r);
1342 /* type: either "jpeg" or "png"
1344 void s_image(char*name, char*type, char*filename, int quality)
1346 /* an image is actually two folded: 1st bitmap, 2nd character.
1347 Both of them can be used separately */
1349 /* step 1: the bitmap */
1353 if(!strcmp(type,"jpeg")) {
1354 #ifndef HAVE_JPEGLIB
1355 warning("no jpeg support compiled in");
1356 s_box(name, 0, 0, black, 20, 0);
1359 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1360 swf_SetU16(tag, imageID);
1362 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1363 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1366 swf_GetJPEGSize(filename, &width, &height);
1373 s_addimage(name, id, tag, r);
1376 } else if(!strcmp(type,"png")) {
1378 swf_SetU16(tag, imageID);
1380 getPNG(filename, &width, &height, (unsigned char**)&data);
1383 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1386 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1387 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1388 swf_SetU16(tag, imageID);
1389 swf_SetLosslessImage(tag, data, width, height);
1396 s_addimage(name, id, tag, r);
1399 warning("image type \"%s\" not supported yet!", type);
1400 s_box(name, 0, 0, black, 20, 0);
1404 /* step 2: the character */
1405 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1406 swf_SetU16(tag, id);
1407 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1409 s_addcharacter(name, id, tag, r);
1413 void s_getBitmapSize(char*name, int*width, int*height)
1415 character_t* image = dictionary_lookup(&images, name);
1416 gradient_t* gradient = dictionary_lookup(&gradients,name);
1418 *width = image->size.xmax;
1419 *height = image->size.ymax;
1423 /* internal SWF gradient size */
1424 if(gradient->radial) {
1433 syntaxerror("No such bitmap/gradient: %s", name);
1436 void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1438 if(dictionary_lookup(&textures, name))
1439 syntaxerror("texture %s defined twice", name);
1440 gradient_t* gradient = dictionary_lookup(&gradients, object);
1441 character_t* bitmap = dictionary_lookup(&images, object);
1442 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1444 FILLSTYLE*fs = &texture->fs;
1446 memset(&p, 0, sizeof(parameters_t));
1449 fs->type = FILL_TILED;
1450 fs->id_bitmap = bitmap->id;
1451 } else if(gradient) {
1452 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1453 fs->gradient = gradient->gradient;
1455 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1456 makeMatrix(&fs->m, &p);
1457 if(gradient && !gradient->radial) {
1464 p2 = swf_TurnPoint(p1, &m);
1473 dictionary_put2(&textures, name, texture);
1476 void s_font(char*name, char*filename)
1479 font = dictionary_lookup(&fonts, name);
1482 /* fix the layout. Only needed for old fonts */
1484 for(t=0;t<font->numchars;t++) {
1485 font->glyph[t].advance = 0;
1488 swf_FontCreateLayout(font);
1491 swf_FontReduce_swfc(font);
1492 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1493 swf_FontSetDefine2(tag, font);
1494 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1496 swf_SetU16(tag, id);
1497 swf_SetString(tag, name);
1504 typedef struct _sound_t
1510 void s_sound(char*name, char*filename)
1512 struct WAV wav, wav2;
1516 unsigned numsamples = 1;
1517 unsigned blocksize = 1152;
1520 if(dictionary_lookup(&sounds, name))
1521 syntaxerror("sound %s defined twice", name);
1523 if(wav_read(&wav, filename))
1526 wav_convert2mono(&wav, &wav2, 44100);
1527 samples = (U16*)wav2.data;
1528 numsamples = wav2.size/2;
1530 #ifdef WORDS_BIGENDIAN
1532 for(t=0;t<numsamples;t++)
1533 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1537 if(mp3_read(&mp3, filename))
1539 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1545 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1550 if(numsamples%blocksize != 0)
1552 // apply padding, so that block is a multiple of blocksize
1553 int numblocks = (numsamples+blocksize-1)/blocksize;
1556 numsamples2 = numblocks * blocksize;
1557 samples2 = malloc(sizeof(U16)*numsamples2);
1558 memcpy(samples2, samples, numsamples*sizeof(U16));
1559 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1560 numsamples = numsamples2;
1565 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1566 swf_SetU16(tag, id); //id
1569 swf_SetSoundDefineMP3(
1570 tag, mp3.data, mp3.size,
1577 swf_SetSoundDefine(tag, samples, numsamples);
1579 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1580 swf_SetU16(tag, id);
1581 swf_SetString(tag, name);
1582 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1584 swf_SetU16(tag, id);
1585 swf_SetString(tag, name);
1587 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1591 dictionary_put2(&sounds, name, sound);
1599 static char* gradient_getToken(const char**p)
1603 while(**p && strchr(" \t\n\r", **p)) {
1607 while(**p && !strchr(" \t\n\r", **p)) {
1610 result = malloc((*p)-start+1);
1611 memcpy(result,start,(*p)-start+1);
1612 result[(*p)-start] = 0;
1616 float parsePercent(char*str);
1617 RGBA parseColor(char*str);
1619 GRADIENT parseGradient(const char*str)
1623 const char* p = str;
1624 memset(&gradient, 0, sizeof(GRADIENT));
1625 gradient.ratios = rfx_calloc(16*sizeof(U8));
1626 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1630 char*posstr,*colorstr;
1633 posstr = gradient_getToken(&p);
1639 pos = (int)(parsePercent(posstr)*255.0);
1644 rfx_free(gradient.ratios);
1645 rfx_free(gradient.rgba);
1647 syntaxerror("Error in shape data: Color expected after %s", posstr);
1649 colorstr = gradient_getToken(&p);
1650 color = parseColor(colorstr);
1651 if(gradient.num == 16)
1653 warning("gradient record too big- max size is 16, rest ignored");
1656 gradient.ratios[gradient.num] = pos;
1657 gradient.rgba[gradient.num] = color;
1666 void s_gradient(char*name, const char*text, int radial, int rotate)
1668 gradient_t* gradient;
1669 gradient = malloc(sizeof(gradient_t));
1670 memset(gradient, 0, sizeof(gradient_t));
1671 gradient->gradient = parseGradient(text);
1672 gradient->radial = radial;
1673 gradient->rotate = rotate;
1675 dictionary_put2(&gradients, name, gradient);
1678 void s_gradientglow(char*name, char*gradient, float blurx, float blury,
1679 float angle, float distance, float strength, char innershadow,
1680 char knockout, char composite, char ontop, int passes)
1682 if(dictionary_lookup(&filters, name))
1683 syntaxerror("filter %s defined twice", name);
1685 gradient_t* g = dictionary_lookup(&gradients, gradient);
1687 syntaxerror("unknown gradient %s", gradient);
1691 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1692 filter->type = FILTERTYPE_GRADIENTGLOW;
1693 filter->gradient = &g->gradient;
1694 filter->blurx = blurx;
1695 filter->blury = blury;
1696 filter->strength = strength;
1697 filter->angle = angle;
1698 filter->distance = distance;
1699 filter->innershadow = innershadow;
1700 filter->knockout = knockout;
1701 filter->composite = composite;
1702 filter->ontop = ontop;
1703 filter->passes = passes;
1705 dictionary_put2(&filters, name, filter);
1708 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)
1710 if(dictionary_lookup(&filters, name))
1711 syntaxerror("filter %s defined twice", name);
1714 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1715 filter->type = FILTERTYPE_DROPSHADOW;
1716 filter->color= color;
1717 filter->blurx = blurx;
1718 filter->blury = blury;
1719 filter->strength = strength;
1720 filter->angle = angle;
1721 filter->distance = distance;
1722 filter->innershadow = innershadow;
1723 filter->knockout = knockout;
1724 filter->composite = composite;
1725 filter->passes = passes;
1727 dictionary_put2(&filters, name, filter);
1730 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)
1732 if(dictionary_lookup(&filters, name))
1733 syntaxerror("filter %s defined twice", name);
1736 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1737 filter->type = FILTERTYPE_BEVEL;
1738 filter->shadow = shadow;
1739 filter->highlight = highlight;
1740 filter->blurx = blurx;
1741 filter->blury = blury;
1742 filter->strength = strength;
1743 filter->angle = angle;
1744 filter->distance = distance;
1745 filter->innershadow = innershadow;
1746 filter->knockout = knockout;
1747 filter->composite = composite;
1748 filter->ontop = ontop;
1749 filter->passes = passes;
1751 dictionary_put2(&filters, name, filter);
1754 void s_blur(char*name, double blurx, double blury, int passes)
1756 if(dictionary_lookup(&filters, name))
1757 syntaxerror("filter %s defined twice", name);
1759 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1760 filter->type = FILTERTYPE_BLUR;
1761 filter->blurx = blurx;
1762 filter->blury = blury;
1763 filter->passes = passes;
1765 dictionary_put2(&filters, name, filter);
1768 void s_action(const char*text)
1771 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1775 syntaxerror("Couldn't compile ActionScript");
1778 tag = swf_InsertTag(tag, ST_DOACTION);
1780 swf_ActionSet(tag, a);
1785 void s_initaction(const char*character, const char*text)
1789 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1793 syntaxerror("Couldn't compile ActionScript");
1796 c = (character_t*)dictionary_lookup(&characters, character);
1798 tag = swf_InsertTag(tag, ST_DOINITACTION);
1799 swf_SetU16(tag, c->id);
1800 swf_ActionSet(tag, a);
1805 int s_swf3action(char*name, char*action)
1808 instance_t* object = 0;
1810 object = (instance_t*)dictionary_lookup(&instances, name);
1811 if(!object && name && *name) {
1812 /* we have a name, but couldn't find it. Abort. */
1815 a = action_SetTarget(0, name);
1816 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1817 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1818 else if(!strcmp(action, "stop")) a = action_Stop(a);
1819 else if(!strcmp(action, "play")) a = action_Play(a);
1820 a = action_SetTarget(a, "");
1823 tag = swf_InsertTag(tag, ST_DOACTION);
1824 swf_ActionSet(tag, a);
1829 void s_outline(char*name, char*format, char*source)
1831 if(dictionary_lookup(&outlines, name))
1832 syntaxerror("outline %s defined twice", name);
1841 //swf_Shape10DrawerInit(&draw, 0);
1842 swf_Shape11DrawerInit(&draw, 0);
1844 draw_string(&draw, source);
1846 shape = swf_ShapeDrawerToShape(&draw);
1847 bounds = swf_ShapeDrawerGetBBox(&draw);
1848 draw.dealloc(&draw);
1850 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1851 outline->shape = shape;
1852 outline->bbox = bounds;
1854 dictionary_put2(&outlines, name, outline);
1857 int s_playsound(char*name, int loops, int nomultiple, int stop)
1863 sound = dictionary_lookup(&sounds, name);
1867 tag = swf_InsertTag(tag, ST_STARTSOUND);
1868 swf_SetU16(tag, sound->id); //id
1869 memset(&info, 0, sizeof(info));
1872 info.nomultiple = nomultiple;
1873 swf_SetSoundInfo(tag, &info);
1877 void s_includeswf(char*name, char*filename)
1885 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1886 f = open(filename,O_RDONLY|O_BINARY);
1888 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1889 s_box(name, 0, 0, black, 20, 0);
1892 if (swf_ReadSWF(f,&swf)<0) {
1893 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1894 s_box(name, 0, 0, black, 20, 0);
1899 /* FIXME: The following sets the bounding Box for the character.
1900 It is wrong for two reasons:
1901 a) It may be too small (in case objects in the movie clip at the borders)
1902 b) it may be too big (because the poor movie never got autocropped)
1906 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1907 swf_SetU16(tag, id);
1908 swf_SetU16(tag, swf.frameCount);
1910 swf_Relocate(&swf, idmap);
1912 ftag = swf.firstTag;
1916 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1917 if(cutout[t] == ftag->id) {
1921 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1923 if(ftag->id == ST_END)
1928 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
1929 /* We simply dump all tags right after the sprite
1930 header, relying on the fact that swf_OptimizeTagOrder() will
1931 sort things out for us later.
1932 We also rely on the fact that the imported SWF is well-formed.
1934 tag = swf_InsertTag(tag, ftag->id);
1935 swf_SetBlock(tag, ftag->data, ftag->len);
1941 syntaxerror("Included file %s contains errors", filename);
1942 tag = swf_InsertTag(tag, ST_END);
1946 s_addcharacter(name, id, tag, r);
1949 SRECT s_getCharBBox(char*name)
1951 character_t* c = dictionary_lookup(&characters, name);
1952 if(!c) syntaxerror("character '%s' unknown(2)", name);
1955 SRECT s_getInstanceBBox(char*name)
1957 instance_t * i = dictionary_lookup(&instances, name);
1959 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1961 if(!c) syntaxerror("internal error(5)");
1964 void s_getParameters(char*name, parameters_t* p)
1966 instance_t * i = dictionary_lookup(&instances, name);
1968 syntaxerror("instance '%s' unknown(10)", name);
1969 if (change_sets_all)
1970 readParameters(i->history, p, currentframe);
1974 void s_startclip(char*instance, char*character, parameters_t p)
1976 character_t* c = dictionary_lookup(&characters, character);
1980 syntaxerror("character %s not known", character);
1982 i = s_addinstance(instance, c, currentdepth);
1984 m = s_instancepos(i->character->size, &p);
1986 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1987 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1988 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1990 i->lastFrame= currentframe;
1992 stack[stackpos].tag = tag;
1993 stack[stackpos].type = 2;
2002 swf_SetTagPos(stack[stackpos].tag, 0);
2003 swf_GetPlaceObject(stack[stackpos].tag, &p);
2004 p.clipdepth = currentdepth;
2006 swf_ClearTag(stack[stackpos].tag);
2007 swf_SetPlaceObject(stack[stackpos].tag, &p);
2011 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2013 history_begin(i->history, "x", currentframe, tag, p->x);
2014 history_begin(i->history, "y", currentframe, tag, p->y);
2015 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2016 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2017 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2018 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2019 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2020 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2021 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2022 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2023 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2024 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2025 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2026 history_begin(i->history, "shear", currentframe, tag, p->shear);
2027 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2028 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2029 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2030 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2031 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2032 history_beginFilter(i->history, currentframe, tag, p->filter);
2035 void s_put(char*instance, char*character, parameters_t p)
2037 character_t* c = dictionary_lookup(&characters, character);
2041 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2043 i = s_addinstance(instance, c, currentdepth);
2045 m = s_instancepos(i->character->size, &p);
2047 if(p.blendmode || p.filter)
2049 if(stack[0].swf->fileVersion < 8)
2052 warning("blendmodes only supported for flash version>=8");
2054 warning("filters only supported for flash version>=8");
2056 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2059 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2060 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2061 setStartparameters(i, &p, tag);
2063 i->lastFrame = currentframe;
2067 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2070 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2072 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2073 if (p.set & SF_SCALEX)
2074 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2075 if (p.set & SF_SCALEY)
2076 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2077 if (p.set & SF_CX_R)
2079 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2080 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2082 if (p.set & SF_CX_G)
2084 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2085 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2087 if (p.set & SF_CX_B)
2089 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2090 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2092 if (p.set & SF_CX_A)
2094 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2095 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2097 if (p.set & SF_ROTATE)
2098 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2099 if (p.set & SF_SHEAR)
2100 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2101 if (p.set & SF_PIVOT)
2103 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2104 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2108 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2109 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2111 if (p.set & SF_BLEND)
2112 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2113 if (p.set & SF_FILTER)
2114 history_rememberFilter(history, currentframe, changeFunction, p.filter, inter);
2117 void s_jump(char* instance, parameters_t p)
2119 instance_t* i = dictionary_lookup(&instances, instance);
2121 syntaxerror("instance %s not known", instance);
2122 recordChanges(i->history, p, CF_JUMP, 0);
2125 void s_change(char*instance, parameters_t p2, interpolation_t* inter)
2127 instance_t* i = dictionary_lookup(&instances, instance);
2129 syntaxerror("instance %s not known", instance);
2131 recordChanges(i->history, p2, CF_CHANGE, inter);
2134 void s_delinstance(char*instance)
2136 instance_t* i = dictionary_lookup(&instances, instance);
2138 syntaxerror("instance %s not known", instance);
2139 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2140 swf_SetU16(tag, i->depth);
2141 dictionary_del(&instances, instance);
2144 void s_qchange(char*instance, parameters_t p)
2146 instance_t* i = dictionary_lookup(&instances, instance);
2148 syntaxerror("instance %s not known", instance);
2149 recordChanges(i->history, p, CF_QCHANGE, 0);
2155 syntaxerror(".end unexpected");
2156 switch (stack[stackpos-1].type)
2171 syntaxerror("internal error 1");
2175 // ------------------------------------------------------------------------
2177 typedef int command_func_t(map_t*args);
2179 SRECT parseBox(char*str)
2181 SRECT r = {0,0,0,0};
2182 float xmin, xmax, ymin, ymax;
2183 char*x = strchr(str, 'x');
2185 if(!strcmp(str, "autocrop")) {
2186 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2190 d1 = strchr(x+1, ':');
2192 d2 = strchr(d1+1, ':');
2194 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2198 else if(d1 && !d2) {
2199 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2205 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2210 r.xmin = (SCOORD)(xmin*20);
2211 r.ymin = (SCOORD)(ymin*20);
2212 r.xmax = (SCOORD)(xmax*20);
2213 r.ymax = (SCOORD)(ymax*20);
2216 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2219 float parseFloat(char*str)
2223 int parseInt(char*str)
2228 if(str[0]=='+' || str[0]=='-')
2232 if(str[t]<'0' || str[t]>'9')
2233 syntaxerror("Not an Integer: \"%s\"", str);
2236 int parseTwip(char*str)
2240 if(str[0]=='+' || str[0]=='-') {
2245 dot = strchr(str, '.');
2249 return sign*parseInt(str)*20;
2251 char* old = strdup(str);
2252 int l=strlen(dot+1);
2255 for(s=str;s<dot-1;s++)
2256 if(*s<'0' || *s>'9')
2259 syntaxerror("Not a coordinate: \"%s\"", str);
2262 if(*s<'0' || *s>'9')
2265 syntaxerror("Not a coordinate: \"%s\"", str);
2267 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2268 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2271 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2275 return sign*atoi(str)*20;
2277 return sign*atoi(str)*20+atoi(dot)*2;
2279 return sign*atoi(str)*20+atoi(dot)/5;
2284 int isPoint(char*str)
2286 if(strchr(str, '('))
2292 SPOINT parsePoint(char*str)
2296 int l = strlen(str);
2297 char*comma = strchr(str, ',');
2298 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2299 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2300 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2301 p.x = parseTwip(tmp);
2302 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2303 p.y = parseTwip(tmp);
2307 int parseColor2(char*str, RGBA*color)
2309 int l = strlen(str);
2313 struct {unsigned char r,g,b;char*name;} colors[] =
2314 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2315 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2316 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2317 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2318 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2319 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2320 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2321 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2322 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2323 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2324 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2325 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2329 if(str[0]=='#' && (l==7 || l==9)) {
2330 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2332 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2334 color->r = r; color->g = g; color->b = b; color->a = a;
2337 int len=strlen(str);
2339 if(strchr(str, '/')) {
2340 len = strchr(str, '/')-str;
2341 sscanf(str+len+1,"%02x", &alpha);
2343 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2344 if(!strncmp(str, colors[t].name, len)) {
2349 color->r = r; color->g = g; color->b = b; color->a = a;
2355 RGBA parseColor(char*str)
2358 if(!parseColor2(str, &c))
2359 syntaxerror("Expression '%s' is not a color", str);
2363 typedef struct _muladd {
2368 MULADD parseMulAdd(char*str)
2371 char* str2 = (char*)malloc(strlen(str)+5);
2378 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2379 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2380 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2381 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2382 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2383 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2384 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2385 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2386 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2387 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2389 syntaxerror("'%s' is not a valid color transform expression", str);
2391 m.add = (int)(add*256);
2392 m.mul = (int)(mul*256);
2397 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2399 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2400 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2402 if(a<-32768) a=-32768;
2403 if(a>32767) a=32767;
2404 if(m<-32768) m=-32768;
2405 if(m>32767) m=32767;
2411 float parsePxOrPercent(char*fontname, char*str)
2413 int l = strlen(str);
2414 if(strchr(str, '%'))
2415 return parsePercent(str);
2416 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2417 float p = atof(str);
2418 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2420 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2424 float parsePercent(char*str)
2426 int l = strlen(str);
2430 return atoi(str)/100.0;
2432 syntaxerror("Expression '%s' is not a percentage", str);
2435 int isPercent(char*str)
2437 return str[strlen(str)-1]=='%';
2439 int parseNewSize(char*str, int size)
2442 return parsePercent(str)*size;
2444 return (int)(atof(str)*20);
2447 int isColor(char*str)
2450 return parseColor2(str, &c);
2453 static char* lu(map_t* args, char*name)
2455 char* value = map_lookup(args, name);
2457 map_dump(args, stdout, "");
2458 syntaxerror("internal error 2: value %s should be set", name);
2463 static int c_flash(map_t*args)
2465 char* filename = map_lookup(args, "filename");
2466 char* compressstr = lu(args, "compress");
2467 char* change_modestr = lu(args, "change-sets-all");
2468 SRECT bbox = parseBox(lu(args, "bbox"));
2469 int version = parseInt(lu(args, "version"));
2470 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2471 RGBA color = parseColor(lu(args, "background"));
2474 if(!filename || !*filename) {
2475 /* for compatibility */
2476 filename = map_lookup(args, "name");
2477 if(!filename || !*filename) {
2480 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2481 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2485 if(!filename || override_outputname)
2486 filename = outputname;
2488 if(!strcmp(compressstr, "default"))
2489 compress = version>=6;
2490 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2492 else if(!strcmp(compressstr, "no"))
2494 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2496 if(!strcmp(change_modestr, "yes"))
2497 change_sets_all = 1;
2499 if(strcmp(change_modestr, "no"))
2500 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2502 s_swf(filename, bbox, version, fps, compress, color);
2505 int isRelative(char*str)
2507 return !strncmp(str, "<plus>", 6) ||
2508 !strncmp(str, "<minus>", 7);
2510 char* getOffset(char*str)
2512 if(!strncmp(str, "<plus>", 6))
2514 if(!strncmp(str, "<minus>", 7))
2516 syntaxerror("internal error (347)");
2519 int getSign(char*str)
2521 if(!strncmp(str, "<plus>", 6))
2523 if(!strncmp(str, "<minus>", 7))
2525 syntaxerror("internal error (348)");
2528 static dictionary_t points;
2529 static mem_t mpoints;
2530 int points_initialized = 0;
2532 static int c_interpolation(map_t *args)
2535 char* name = lu(args, "name");
2536 if (dictionary_lookup(&interpolations, name))
2537 syntaxerror("interpolation %s defined twice", name);
2539 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2540 char* functionstr = lu(args, "function");
2541 inter->function = 0;
2542 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2543 if (!strcmp(functionstr,interpolationFunctions[i]))
2545 inter->function = i + 1;
2548 if (!inter->function)
2549 syntaxerror("unkown interpolation function %s", functionstr);
2550 inter->speed = parseFloat(lu(args, "speed"));
2551 inter->amplitude = parseFloat(lu(args, "amplitude"));
2552 inter->growth = parseFloat(lu(args, "growth"));
2553 inter->bounces = parseInt(lu(args, "bounces"));
2554 inter->damping = parseInt(lu(args, "damping"));
2556 dictionary_put2(&interpolations, name, inter);
2560 SPOINT getPoint(SRECT r, char*name)
2563 if(!strcmp(name, "center")) {
2565 p.x = (r.xmin + r.xmax)/2;
2566 p.y = (r.ymin + r.ymax)/2;
2570 if(points_initialized)
2571 l = (int)dictionary_lookup(&points, name);
2573 syntaxerror("Invalid point: \"%s\".", name);
2576 return *(SPOINT*)&mpoints.buffer[l];
2579 static int texture2(char*name, char*object, map_t*args, int errors)
2582 char*xstr = map_lookup(args, "x");
2583 char*ystr = map_lookup(args, "y");
2584 char*widthstr = map_lookup(args, "width");
2585 char*heightstr = map_lookup(args, "height");
2586 char*scalestr = map_lookup(args, "scale");
2587 char*scalexstr = map_lookup(args, "scalex");
2588 char*scaleystr = map_lookup(args, "scaley");
2589 char*rotatestr = map_lookup(args, "rotate");
2590 char* shearstr = map_lookup(args, "shear");
2591 char* radiusstr = map_lookup(args, "r");
2593 float scalex = 1.0, scaley = 1.0;
2594 float rotate=0, shear=0;
2596 if(!*xstr && !*ystr) {
2598 syntaxerror("x and y must be set");
2601 if(*scalestr && (*scalexstr || *scaleystr)) {
2602 syntaxerror("scale and scalex/scaley can't both be set");
2605 if((*widthstr || *heightstr) && *radiusstr) {
2606 syntaxerror("width/height and radius can't both be set");
2609 widthstr = radiusstr;
2610 heightstr = radiusstr;
2612 if(!*xstr) xstr="0";
2613 if(!*ystr) ystr="0";
2614 if(!*rotatestr) rotatestr="0";
2615 if(!*shearstr) shearstr="0";
2618 scalex = scaley = parsePercent(scalestr);
2619 } else if(*scalexstr || *scaleystr) {
2620 if(scalexstr) scalex = parsePercent(scalexstr);
2621 if(scaleystr) scaley = parsePercent(scaleystr);
2622 } else if(*widthstr || *heightstr) {
2625 s_getBitmapSize(object, &width, &height);
2627 scalex = (float)parseTwip(widthstr)/(float)width;
2629 scaley = (float)parseTwip(heightstr)/(float)height;
2631 x = parseTwip(xstr);
2632 y = parseTwip(ystr);
2633 rotate = parseFloat(rotatestr);
2634 shear = parseFloat(shearstr);
2636 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2641 static int c_texture(map_t*args)
2643 char*name = lu(args, "instance");
2644 char*object = lu(args, "character");
2645 return texture2(name, object, args, 1);
2648 static int c_gradient(map_t*args)
2650 char*name = lu(args, "name");
2651 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2652 int rotate = parseInt(lu(args, "rotate"));
2656 syntaxerror("colon (:) expected");
2658 if(dictionary_lookup(&gradients, name))
2659 syntaxerror("gradient %s defined twice", name);
2661 s_gradient(name, text, radial, rotate);
2663 /* check whether we also have placement information,
2664 which would make this a positioned gradient.
2665 If there is placement information, texture2() will
2666 add a texture, which has priority over the gradient.
2668 texture2(name, name, args, 0);
2672 static int c_blur(map_t*args)
2674 char*name = lu(args, "name");
2675 char*blurstr = lu(args, "blur");
2676 char*blurxstr = lu(args, "blurx");
2677 char*blurystr = lu(args, "blury");
2678 float blurx=1.0, blury=1.0;
2680 blurx = parseFloat(blurstr);
2681 blury = parseFloat(blurstr);
2684 blurx = parseFloat(blurxstr);
2686 blury = parseFloat(blurystr);
2687 int passes = parseInt(lu(args, "passes"));
2688 s_blur(name, blurx, blury, passes);
2692 static int c_gradientglow(map_t*args)
2694 char*name = lu(args, "name");
2695 char*gradient = lu(args, "gradient");
2696 char*blurstr = lu(args, "blur");
2697 char*blurxstr = lu(args, "blurx");
2698 char*blurystr = lu(args, "blury");
2699 float blurx=1.0, blury=1.0;
2701 blurx = parseFloat(blurstr);
2702 blury = parseFloat(blurstr);
2705 blurx = parseFloat(blurxstr);
2707 blury = parseFloat(blurystr);
2709 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2710 float distance = parseFloat(lu(args, "distance"));
2711 float strength = parseFloat(lu(args, "strength"));
2712 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2713 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2714 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2715 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2716 int passes = parseInt(lu(args, "passes"));
2718 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2722 static int c_dropshadow(map_t*args)
2724 char*name = lu(args, "name");
2725 RGBA color = parseColor(lu(args, "color"));
2726 char*blurstr = lu(args, "blur");
2727 char*blurxstr = lu(args, "blurx");
2728 char*blurystr = lu(args, "blury");
2729 float blurx=1.0, blury=1.0;
2731 blurx = parseFloat(blurstr);
2732 blury = parseFloat(blurstr);
2735 blurx = parseFloat(blurxstr);
2737 blury = parseFloat(blurystr);
2739 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2740 float distance = parseFloat(lu(args, "distance"));
2741 float strength = parseFloat(lu(args, "strength"));
2742 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2743 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2744 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2745 int passes = parseInt(lu(args, "passes"));
2747 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
2751 static int c_bevel(map_t*args)
2753 char*name = lu(args, "name");
2754 RGBA shadow = parseColor(lu(args, "shadow"));
2755 RGBA highlight = parseColor(lu(args, "highlight"));
2756 char*blurstr = lu(args, "blur");
2757 char*blurxstr = lu(args, "blurx");
2758 char*blurystr = lu(args, "blury");
2759 float blurx=1.0, blury=1.0;
2761 blurx = parseFloat(blurstr);
2762 blury = parseFloat(blurstr);
2765 blurx = parseFloat(blurxstr);
2767 blury = parseFloat(blurystr);
2769 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2770 float distance = parseFloat(lu(args, "distance"));
2771 float strength = parseFloat(lu(args, "strength"));
2772 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2773 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2774 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2775 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2776 int passes = parseInt(lu(args, "passes"));
2778 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2782 static int c_point(map_t*args)
2784 char*name = lu(args, "name");
2788 if(!points_initialized) {
2789 dictionary_init(&points);
2791 points_initialized = 1;
2793 p.x = parseTwip(lu(args, "x"));
2794 p.y = parseTwip(lu(args, "y"));
2795 pos = mem_put(&mpoints, &p, sizeof(p));
2796 string_set(&s1, name);
2798 dictionary_put(&points, s1, (void*)pos);
2801 static int c_play(map_t*args)
2803 char*name = lu(args, "name");
2804 char*loop = lu(args, "loop");
2805 char*nomultiple = lu(args, "nomultiple");
2807 if(!strcmp(nomultiple, "nomultiple"))
2810 nm = parseInt(nomultiple);
2812 if(s_playsound(name, parseInt(loop), nm, 0)) {
2814 } else if(s_swf3action(name, "play")) {
2820 static int c_stop(map_t*args)
2822 char*name = map_lookup(args, "name");
2824 if(s_playsound(name, 0,0,1))
2826 else if(s_swf3action(name, "stop"))
2828 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
2832 static int c_nextframe(map_t*args)
2834 char*name = lu(args, "name");
2836 if(s_swf3action(name, "nextframe")) {
2839 syntaxerror("I don't know anything about movie \"%s\"", name);
2843 static int c_previousframe(map_t*args)
2845 char*name = lu(args, "name");
2847 if(s_swf3action(name, "previousframe")) {
2850 syntaxerror("I don't know anything about movie \"%s\"", name);
2854 static int c_placement(map_t*args, int type)
2856 char*instance = lu(args, (type==0||type==4)?"instance":"name");
2859 char* luminancestr = lu(args, "luminance");
2860 char* scalestr = lu(args, "scale");
2861 char* scalexstr = lu(args, "scalex");
2862 char* scaleystr = lu(args, "scaley");
2863 char* rotatestr = lu(args, "rotate");
2864 char* shearstr = lu(args, "shear");
2865 char* xstr="", *pivotstr="";
2866 char* ystr="", *anglestr="";
2867 char*above = lu(args, "above"); /*FIXME*/
2868 char*below = lu(args, "below");
2869 char* rstr = lu(args, "red");
2870 char* gstr = lu(args, "green");
2871 char* bstr = lu(args, "blue");
2872 char* astr = lu(args, "alpha");
2873 char* pinstr = lu(args, "pin");
2874 char* as = map_lookup(args, "as");
2875 char* blendmode = lu(args, "blend");
2876 char* filterstr = lu(args, "filter");
2887 { // (?) .rotate or .arcchange
2888 pivotstr = lu(args, "pivot");
2889 anglestr = lu(args, "angle");
2893 xstr = lu(args, "x");
2894 ystr = lu(args, "y");
2898 luminance = parseMulAdd(luminancestr);
2902 luminance.mul = 256;
2907 if(scalexstr[0]||scaleystr[0])
2908 syntaxerror("scalex/scaley and scale cannot both be set");
2909 scalexstr = scaleystr = scalestr;
2912 if(type == 0 || type == 4) {
2914 character = lu(args, "character");
2915 parameters_clear(&p);
2916 } else if (type == 5) {
2917 character = lu(args, "name");
2918 parameters_clear(&p);
2921 s_getParameters(instance, &p);
2927 if(isRelative(xstr))
2929 if(type == 0 || type == 4)
2930 syntaxerror("relative x values not allowed for initial put or startclip");
2931 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2935 p.x = parseTwip(xstr);
2941 if(isRelative(ystr))
2943 if(type == 0 || type == 4)
2944 syntaxerror("relative y values not allowed for initial put or startclip");
2945 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2949 p.y = parseTwip(ystr);
2954 /* scale, scalex, scaley */
2956 oldbbox = s_getCharBBox(character);
2958 oldbbox = s_getInstanceBBox(instance);
2959 oldwidth = oldbbox.xmax - oldbbox.xmin;
2960 oldheight = oldbbox.ymax - oldbbox.ymin;
2967 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2968 set = set | SF_SCALEX;
2976 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2977 set = set | SF_SCALEY;
2983 if(isRelative(rotatestr))
2984 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2986 p.rotate = parseFloat(rotatestr);
2987 set = set | SF_ROTATE;
2993 if(isRelative(shearstr))
2994 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2996 p.shear = parseFloat(shearstr);
2997 set = set | SF_SHEAR;
3002 if(isPoint(pivotstr))
3003 p.pivot = parsePoint(pivotstr);
3005 p.pivot = getPoint(oldbbox, pivotstr);
3006 set = set | SF_PIVOT;
3012 p.pin = parsePoint(pinstr);
3014 p.pin = getPoint(oldbbox, pinstr);
3018 /* color transform */
3020 if(rstr[0] || luminancestr[0])
3024 r = parseMulAdd(rstr);
3027 r.add = p.cxform.r0;
3028 r.mul = p.cxform.r1;
3030 r = mergeMulAdd(r, luminance);
3031 p.cxform.r0 = r.mul;
3032 p.cxform.r1 = r.add;
3033 set = set | SF_CX_R;
3035 if(gstr[0] || luminancestr[0])
3039 g = parseMulAdd(gstr);
3042 g.add = p.cxform.g0;
3043 g.mul = p.cxform.g1;
3045 g = mergeMulAdd(g, luminance);
3046 p.cxform.g0 = g.mul;
3047 p.cxform.g1 = g.add;
3048 set = set | SF_CX_G;
3050 if(bstr[0] || luminancestr[0])
3054 b = parseMulAdd(bstr);
3057 b.add = p.cxform.b0;
3058 b.mul = p.cxform.b1;
3060 b = mergeMulAdd(b, luminance);
3061 p.cxform.b0 = b.mul;
3062 p.cxform.b1 = b.add;
3063 set = set | SF_CX_B;
3067 MULADD a = parseMulAdd(astr);
3068 p.cxform.a0 = a.mul;
3069 p.cxform.a1 = a.add;
3070 set = set | SF_CX_A;
3077 for(t = 0; blendModeNames[t]; t++)
3079 if(!strcmp(blendModeNames[t], blendmode))
3087 syntaxerror("unknown blend mode: '%s'", blendmode);
3089 p.blendmode = blend;
3090 set = set | SF_BLEND;
3095 FILTER*f = dictionary_lookup(&filters, filterstr);
3097 syntaxerror("Unknown filter %s", filterstr);
3099 set = set | SF_FILTER;
3102 if (change_sets_all)
3109 s_put(instance, character, p);
3113 char* interstr = lu(args, "interpolation");
3114 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3116 syntaxerror("unkown interpolation %s", interstr);
3117 s_change(instance, p, inter);
3121 s_qchange(instance, p);
3124 s_jump(instance, p);
3127 s_startclip(instance, character, p);
3131 s_buttonput(character, as, p);
3133 s_buttonput(character, "shape", p);
3139 static int c_put(map_t*args)
3141 c_placement(args, 0);
3144 static int c_change(map_t*args)
3146 if (currentframe == 0)
3147 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3148 c_placement(args, 1);
3151 static int c_qchange(map_t*args)
3153 c_placement(args, 2);
3156 static int c_arcchange(map_t*args)
3158 c_placement(args, 2);
3161 static int c_jump(map_t*args)
3163 c_placement(args, 3);
3166 static int c_startclip(map_t*args)
3168 c_placement(args, 4);
3171 static int c_show(map_t*args)
3173 c_placement(args, 5);
3176 static int c_del(map_t*args)
3178 char*instance = lu(args, "name");
3179 s_delinstance(instance);
3182 static int c_end(map_t*args)
3187 static int c_sprite(map_t*args)
3189 char* name = lu(args, "name");
3193 static int c_frame(map_t*args)
3195 char*framestr = lu(args, "n");
3196 char*cutstr = lu(args, "cut");
3198 char*name = lu(args, "name");
3199 char*anchor = lu(args, "anchor");
3202 if(!strcmp(anchor, "anchor") && !*name)
3207 if(strcmp(cutstr, "no"))
3209 if(isRelative(framestr)) {
3210 frame = s_getframe();
3211 if(getSign(framestr)<0)
3212 syntaxerror("relative frame expressions must be positive");
3213 frame += parseInt(getOffset(framestr));
3216 frame = parseInt(framestr);
3217 if(s_getframe() >= frame
3218 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3219 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3221 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3224 static int c_primitive(map_t*args)
3226 char*name = lu(args, "name");
3227 char*command = lu(args, "commandname");
3228 int width=0, height=0, r=0;
3229 int linewidth = parseTwip(lu(args, "line"));
3230 char*colorstr = lu(args, "color");
3231 RGBA color = parseColor(colorstr);
3232 char*fillstr = lu(args, "fill");
3239 if(!strcmp(command, "circle"))
3241 else if(!strcmp(command, "filled"))
3245 width = parseTwip(lu(args, "width"));
3246 height = parseTwip(lu(args, "height"));
3247 } else if (type==1) {
3248 r = parseTwip(lu(args, "r"));
3249 } else if (type==2) {
3250 outline = lu(args, "outline");
3253 if(!strcmp(fillstr, "fill"))
3255 if(!strcmp(fillstr, "none"))
3257 if(width<0 || height<0 || linewidth<0 || r<0)
3258 syntaxerror("values width, height, line, r must be positive");
3260 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3261 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3262 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3266 static int c_textshape(map_t*args)
3268 char*name = lu(args, "name");
3269 char*text = lu(args, "text");
3270 char*font = lu(args, "font");
3271 float size = parsePxOrPercent(font, lu(args, "size"));
3273 s_textshape(name, font, size, text);
3277 static int c_swf(map_t*args)
3279 char*name = lu(args, "name");
3280 char*filename = lu(args, "filename");
3281 char*command = lu(args, "commandname");
3282 if(!strcmp(command, "shape"))
3283 warning("Please use .swf instead of .shape");
3284 s_includeswf(name, filename);
3288 static int c_font(map_t*args)
3290 char*name = lu(args, "name");
3291 char*filename = lu(args, "filename");
3292 s_font(name, filename);
3296 static int c_sound(map_t*args)
3298 char*name = lu(args, "name");
3299 char*filename = lu(args, "filename");
3300 s_sound(name, filename);
3304 static int c_text(map_t*args)
3306 char*name = lu(args, "name");
3307 char*text = lu(args, "text");
3308 char*font = lu(args, "font");
3309 float size = parsePxOrPercent(font, lu(args, "size"));
3310 RGBA color = parseColor(lu(args, "color"));
3311 s_text(name, font, text, (int)(size*100), color);
3315 static int c_soundtrack(map_t*args)
3320 static int c_quicktime(map_t*args)
3322 char*name = lu(args, "name");
3323 char*url = lu(args, "url");
3324 s_quicktime(name, url);
3328 static int c_image(map_t*args)
3330 char*command = lu(args, "commandname");
3331 char*name = lu(args, "name");
3332 char*filename = lu(args, "filename");
3333 if(!strcmp(command,"jpeg")) {
3334 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3335 s_image(name, "jpeg", filename, quality);
3337 s_image(name, "png", filename, 0);
3342 static int c_outline(map_t*args)
3344 char*name = lu(args, "name");
3345 char*format = lu(args, "format");
3349 syntaxerror("colon (:) expected");
3351 s_outline(name, format, text);
3355 int fakechar(map_t*args)
3357 char*name = lu(args, "name");
3358 s_box(name, 0, 0, black, 20, 0);
3362 static int c_egon(map_t*args) {return fakechar(args);}
3363 static int c_button(map_t*args) {
3364 char*name = lu(args, "name");
3368 static int current_button_flags = 0;
3369 static int c_on_press(map_t*args)
3371 char*position = lu(args, "position");
3373 if(!strcmp(position, "inside")) {
3374 current_button_flags |= BC_OVERUP_OVERDOWN;
3375 } else if(!strcmp(position, "outside")) {
3376 //current_button_flags |= BC_IDLE_OUTDOWN;
3377 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3378 } else if(!strcmp(position, "anywhere")) {
3379 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3382 if(type == RAWDATA) {
3384 s_buttonaction(current_button_flags, action);
3385 current_button_flags = 0;
3391 static int c_on_release(map_t*args)
3393 char*position = lu(args, "position");
3395 if(!strcmp(position, "inside")) {
3396 current_button_flags |= BC_OVERDOWN_OVERUP;
3397 } else if(!strcmp(position, "outside")) {
3398 current_button_flags |= BC_OUTDOWN_IDLE;
3399 } else if(!strcmp(position, "anywhere")) {
3400 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3403 if(type == RAWDATA) {
3405 s_buttonaction(current_button_flags, action);
3406 current_button_flags = 0;
3412 static int c_on_move_in(map_t*args)
3414 char*position = lu(args, "state");
3416 if(!strcmp(position, "pressed")) {
3417 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3418 } else if(!strcmp(position, "not_pressed")) {
3419 current_button_flags |= BC_IDLE_OVERUP;
3420 } else if(!strcmp(position, "any")) {
3421 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3424 if(type == RAWDATA) {
3426 s_buttonaction(current_button_flags, action);
3427 current_button_flags = 0;
3433 static int c_on_move_out(map_t*args)
3435 char*position = lu(args, "state");
3437 if(!strcmp(position, "pressed")) {
3438 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3439 } else if(!strcmp(position, "not_pressed")) {
3440 current_button_flags |= BC_OVERUP_IDLE;
3441 } else if(!strcmp(position, "any")) {
3442 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3445 if(type == RAWDATA) {
3447 s_buttonaction(current_button_flags, action);
3448 current_button_flags = 0;
3454 static int c_on_key(map_t*args)
3456 char*key = lu(args, "key");
3458 if(strlen(key)==1) {
3461 current_button_flags |= 0x4000 + (key[0]*0x200);
3463 syntaxerror("invalid character: %c"+key[0]);
3468 <ctrl-x> = 0x200*(x-'a')
3472 syntaxerror("invalid key: %s",key);
3475 if(type == RAWDATA) {
3477 s_buttonaction(current_button_flags, action);
3478 current_button_flags = 0;
3485 static int c_edittext(map_t*args)
3487 //"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"},
3488 char*name = lu(args, "name");
3489 char*font = lu(args, "font");
3490 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3491 int width = parseTwip(lu(args, "width"));
3492 int height = parseTwip(lu(args, "height"));
3493 char*text = lu(args, "text");
3494 RGBA color = parseColor(lu(args, "color"));
3495 int maxlength = parseInt(lu(args, "maxlength"));
3496 char*variable = lu(args, "variable");
3497 char*passwordstr = lu(args, "password");
3498 char*wordwrapstr = lu(args, "wordwrap");
3499 char*multilinestr = lu(args, "multiline");
3500 char*htmlstr = lu(args, "html");
3501 char*noselectstr = lu(args, "noselect");
3502 char*readonlystr = lu(args, "readonly");
3503 char*borderstr = lu(args, "border");
3504 char*autosizestr = lu(args, "autosize");
3505 char*alignstr = lu(args, "align");
3509 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3510 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3511 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3512 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3513 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3514 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3515 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3516 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3517 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3518 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
3519 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
3520 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
3521 else syntaxerror("Unknown alignment: %s", alignstr);
3523 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
3527 static int c_morphshape(map_t*args) {return fakechar(args);}
3528 static int c_movie(map_t*args) {return fakechar(args);}
3530 static char* readfile(const char*filename)
3532 FILE*fi = fopen(filename, "rb");
3536 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
3537 fseek(fi, 0, SEEK_END);
3539 fseek(fi, 0, SEEK_SET);
3540 text = rfx_alloc(l+1);
3541 fread(text, l, 1, fi);
3547 static int c_action(map_t*args)
3549 char* filename = map_lookup(args, "filename");
3550 if(!filename ||!*filename) {
3552 if(type != RAWDATA) {
3553 syntaxerror("colon (:) expected");
3557 s_action(readfile(filename));
3563 static int c_initaction(map_t*args)
3565 char* character = lu(args, "name");
3566 char* filename = map_lookup(args, "filename");
3567 if(!filename ||!*filename) {
3569 if(type != RAWDATA) {
3570 syntaxerror("colon (:) expected");
3572 s_initaction(character, text);
3574 s_initaction(character, readfile(filename));
3582 command_func_t* func;
3585 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no"},
3586 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
3587 // "import" type stuff
3588 {"swf", c_swf, "name filename"},
3589 {"shape", c_swf, "name filename"},
3590 {"jpeg", c_image, "name filename quality=80%"},
3591 {"png", c_image, "name filename"},
3592 {"movie", c_movie, "name filename"},
3593 {"sound", c_sound, "name filename"},
3594 {"font", c_font, "name filename"},
3595 {"soundtrack", c_soundtrack, "filename"},
3596 {"quicktime", c_quicktime, "url"},
3598 // generators of primitives
3600 {"point", c_point, "name x=0 y=0"},
3601 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
3602 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5, damping=2"},
3603 {"outline", c_outline, "name format=simple"},
3604 {"textshape", c_textshape, "name font size=100% text"},
3607 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
3608 {"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"},
3609 {"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"},
3610 {"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"},
3612 // character generators
3613 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
3614 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
3615 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
3617 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
3618 {"text", c_text, "name text font size=100% color=white"},
3619 {"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="},
3620 {"morphshape", c_morphshape, "name start end"},
3621 {"button", c_button, "name"},
3622 {"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="},
3623 {"on_press", c_on_press, "position=inside"},
3624 {"on_release", c_on_release, "position=anywhere"},
3625 {"on_move_in", c_on_move_in, "state=not_pressed"},
3626 {"on_move_out", c_on_move_out, "state=not_pressed"},
3627 {"on_key", c_on_key, "key=any"},
3630 {"play", c_play, "name loop=0 @nomultiple=0"},
3631 {"stop", c_stop, "name= "},
3632 {"nextframe", c_nextframe, "name"},
3633 {"previousframe", c_previousframe, "name"},
3635 // object placement tags
3636 {"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="},
3637 {"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="},
3638 {"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"},
3639 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3640 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3641 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3642 {"del", c_del, "name"},
3643 // virtual object placement
3644 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
3646 // commands which start a block
3647 //startclip (see above)
3648 {"sprite", c_sprite, "name"},
3649 {"action", c_action, "filename="},
3650 {"initaction", c_initaction, "name filename="},
3656 static map_t parseArguments(char*command, char*pattern)
3672 string_set(&t1, "commandname");
3673 string_set(&t2, command);
3674 map_put(&result, t1, t2);
3676 if(!pattern || !*pattern)
3683 if(!strncmp("<i> ", x, 3)) {
3685 if(type == COMMAND || type == RAWDATA) {
3687 syntaxerror("character name expected");
3689 name[pos].str = "instance";
3691 value[pos].str = text;
3692 value[pos].len = strlen(text);
3696 if(type == ASSIGNMENT)
3699 name[pos].str = "character";
3701 value[pos].str = text;
3702 value[pos].len = strlen(text);
3710 isboolean[pos] = (x[0] =='@');
3723 name[pos].len = d-x;
3728 name[pos].len = e-x;
3729 value[pos].str = e+1;
3730 value[pos].len = d-e-1;
3738 /* for(t=0;t<len;t++) {
3739 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
3740 isboolean[t]?"(boolean)":"");
3745 if(type == RAWDATA || type == COMMAND) {
3750 // first, search for boolean arguments
3751 for(pos=0;pos<len;pos++)
3753 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
3755 if(type == ASSIGNMENT)
3757 value[pos].str = text;
3758 value[pos].len = strlen(text);
3759 /*printf("setting boolean parameter %s (to %s)\n",
3760 strdup_n(name[pos], namelen[pos]),
3761 strdup_n(value[pos], valuelen[pos]));*/
3766 // second, search for normal arguments
3768 for(pos=0;pos<len;pos++)
3770 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
3771 (type != ASSIGNMENT && !set[pos])) {
3773 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
3775 if(type == ASSIGNMENT)
3778 value[pos].str = text;
3779 value[pos].len = strlen(text);
3781 printf("setting parameter %s (to %s)\n",
3782 strdup_n(name[pos].str, name[pos].len),
3783 strdup_n(value[pos].str, value[pos].len));
3789 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
3793 for(t=0;t<len;t++) {
3794 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
3797 for(t=0;t<len;t++) {
3798 if(value[t].str && value[t].str[0] == '*') {
3799 //relative default- take value from some other parameter
3801 for(s=0;s<len;s++) {
3802 if(value[s].len == value[t].len-1 &&
3803 !strncmp(&value[t].str[1], value[s].str, value[s].len))
3804 value[t].str = value[s].str;
3807 if(value[t].str == 0) {
3809 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
3813 /* ok, now construct the dictionary from the parameters */
3817 map_put(&result, name[t], value[t]);
3821 static void parseArgumentsForCommand(char*command)
3826 msg("<verbose> parse Command: %s (line %d)", command, line);
3828 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
3829 if(!strcmp(arguments[t].command, command)) {
3831 /* ugly hack- will be removed soon (once documentation and .sc generating
3832 utilities have been changed) */
3833 if(!strcmp(command, "swf") && !stackpos) {
3834 warning("Please use .flash instead of .swf- this will be mandatory soon");
3839 args = parseArguments(command, arguments[t].arguments);
3845 syntaxerror("command %s not known", command);
3847 // catch missing .flash directives at the beginning of a file
3848 if(strcmp(command, "flash") && !stackpos)
3850 syntaxerror("No movie defined- use .flash first");
3854 printf(".%s\n", command);fflush(stdout);
3855 map_dump(&args, stdout, "\t");fflush(stdout);
3858 (*arguments[nr].func)(&args);
3860 /*if(!strcmp(command, "button") ||
3861 !strcmp(command, "action")) {
3864 if(type == COMMAND) {
3865 if(!strcmp(text, "end"))
3880 /* for now only intended to find what glyphs of each font are to be included in the swf file.
3881 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
3882 * No syntax checking is done */
3883 static void analyseArgumentsForCommand(char*command)
3889 msg("<verbose> analyse Command: %s (line %d)", command, line);
3891 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
3893 if(!strcmp(arguments[t].command, command))
3895 args = parseArguments(command, arguments[t].arguments);
3901 printf(".%s\n", command);fflush(stdout);
3902 map_dump(&args, stdout, "\t");fflush(stdout);
3904 char* name = lu(&args, "name");
3905 if (!strcmp(command, "font"))
3907 if(dictionary_lookup(&fonts, name))
3908 syntaxerror("font %s defined twice", name);
3911 fontfile = lu(&args, "filename");
3912 font = swf_LoadFont(fontfile);
3914 warning("Couldn't open font file \"%s\"", fontfile);
3915 font = (SWFFONT*)malloc(sizeof(SWFFONT));
3916 memset(font, 0, sizeof(SWFFONT));
3918 swf_FontPrepareForEditText(font);
3919 dictionary_put2(&fonts, name, font);
3923 SWFFONT* font = dictionary_lookup(&fonts, lu(&args, "font"));
3925 syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
3927 if (!strcmp(command, "edittext"))
3928 swf_FontUseAll(font);
3930 swf_FontUseUTF8(font, lu(&args, "text"));
3936 void skipParameters()
3940 while (type != COMMAND);
3944 void findFontUsage()
3946 char* fontRelated = "font;text;textshape;edittext;";
3947 while(!noMoreTokens())
3951 syntaxerror("command expected");
3952 if (strstr(fontRelated, text))
3953 analyseArgumentsForCommand(text);
3955 if(strcmp(text, "end"))
3964 dictionary_init(&fonts);
3965 cleanUp = &freeFontDictionary;
3969 int main (int argc,char ** argv)
3972 processargs(argc, argv);
3973 initLog(0,-1,0,0,-1,verbose);
3976 args_callback_usage(argv[0]);
3980 file = generateTokens(filename);
3982 fprintf(stderr, "parser returned error.\n");
3989 while(!noMoreTokens()) {
3992 syntaxerror("command expected");
3993 parseArgumentsForCommand(text);