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)
170 // ------------------------------ swf routines ----------------------------
174 int type; //0=swf, 1=sprite, 2=clip, 3=button
180 /* for sprites (1): */
186 dictionary_t oldinstances;
191 static int stackpos = 0;
193 static dictionary_t characters;
194 static dictionary_t images;
195 static dictionary_t textures;
196 static dictionary_t outlines;
197 static dictionary_t gradients;
198 static dictionary_t filters;
199 static dictionary_t interpolations;
200 static char idmap[65536];
201 static TAG*tag = 0; //current tag
203 static int id; //current character id
204 static int currentframe; //current frame in current level
205 static SRECT currentrect; //current bounding box in current level
206 static U16 currentdepth;
207 static dictionary_t instances;
208 static dictionary_t fonts;
209 static dictionary_t sounds;
210 static dictionary_t fontUsage;
212 typedef struct _parameters {
214 float scalex, scaley;
220 U8 blendmode; //not interpolated
222 U16 set; // bits indicating wether a parameter was set in the c_placement function
223 U16 flags; // bits to toggle anything you may care to implement as a toggle
226 typedef struct _character {
232 typedef struct _instance {
233 character_t*character;
235 parameters_t parameters;
239 typedef struct _outline {
244 typedef struct _gradient {
250 typedef struct _filter {
254 typedef struct _texture {
258 char* interpolationFunctions[] = {"linear", \
259 "quadIn", "quadOut", "quadInOut", \
260 "cubicIn", "cubicOut", "cubicInOut", \
261 "quartIn", "quartOut", "quartInOut", \
262 "quintIn", "quintOut", "quintInOut", \
263 "circleIn", "circleOut", "circleInOut", \
264 "exponentialIn", "exponentialOut", "exponentialInOut", \
265 "sineIn", "sineOut", "sineInOut", \
266 "elasticIn", "elasticOut", "elasticInOut", \
267 "backIn", "backOut", "backInOut", \
268 "bounceIn", "bounceOut", "bounceInOut", \
269 "fastBounceIn", "fastBounceOut", "fastBounceInOut"};
271 static void character_init(character_t*c)
273 memset(c, 0, sizeof(character_t));
276 static character_t* character_new()
279 c = (character_t*)malloc(sizeof(character_t));
284 static void instance_init(instance_t*i)
286 memset(i, 0, sizeof(instance_t));
287 i->history = history_new();
290 static void instance_free(instance_t* i)
292 history_free(i->history);
296 static instance_t* instance_new()
299 c = (instance_t*)malloc(sizeof(instance_t));
304 static void free_instance(void* i)
306 instance_free((instance_t*)i);
309 static void free_font(void* f)
311 swf_FontFree((SWFFONT*)f);
314 static void gradient_free(GRADIENT* grad)
321 static void free_gradient(void* grad)
323 gradient_free((GRADIENT*) grad);
326 static void outline_free(outline_t* o)
328 free(o->shape->data);
333 static void free_outline(void* o)
335 outline_free((outline_t*)o);
338 static void freeDictionaries()
340 dictionary_free_all(&instances, free_instance);
341 dictionary_free_all(&characters, free);
342 dictionary_free_all(&images, free);
343 dictionary_free_all(&textures, free);
344 dictionary_free_all(&outlines, free_outline);
345 dictionary_free_all(&gradients, free_gradient);
346 dictionary_free_all(&filters, free);
347 dictionary_free_all(&fonts, free_font);
348 dictionary_free_all(&sounds, free);
349 dictionary_free_all(&interpolations, free);
352 static void freeFontDictionary()
354 dictionary_free_all(&fonts, free_font);
357 static void incrementid()
361 syntaxerror("Out of character ids.");
366 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
368 if(dictionary_lookup(&characters, name))
369 syntaxerror("character %s defined twice", name);
370 character_t* c = character_new();
372 c->definingTag = ctag;
375 dictionary_put2(&characters, name, c);
377 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
379 swf_SetString(tag, name);
380 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
383 swf_SetString(tag, name);
385 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
387 if(dictionary_lookup(&images, name))
388 syntaxerror("image %s defined twice", name);
390 character_t* c = character_new();
391 c->definingTag = ctag;
394 dictionary_put2(&images, name, c);
396 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
398 if(dictionary_lookup(&instances, name))
399 syntaxerror("object %s defined twice", name);
400 instance_t* i = instance_new();
403 //swf_GetMatrix(0, &i->matrix);
404 dictionary_put2(&instances, name, i);
408 static void parameters_clear(parameters_t*p)
411 p->scalex = 1.0; p->scaley = 1.0;
414 p->pivot.x = 0; p->pivot.y = 0;
419 swf_GetCXForm(0, &p->cxform, 1);
422 static void makeMatrix(MATRIX*m, parameters_t*p)
431 sx = p->scalex*cos(p->rotate/360*2*M_PI);
432 r1 = -p->scalex*sin(p->rotate/360*2*M_PI)+sx*p->shear;
433 r0 = p->scaley*sin(p->rotate/360*2*M_PI);
434 sy = p->scaley*cos(p->rotate/360*2*M_PI)+r0*p->shear;
436 m->sx = (int)(sx*65536+0.5);
437 m->r1 = (int)(r1*65536+0.5);
438 m->r0 = (int)(r0*65536+0.5);
439 m->sy = (int)(sy*65536+0.5);
443 h = swf_TurnPoint(p->pin, m);
448 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
453 r = swf_TurnRect(rect, &m);
454 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
455 currentrect.xmax == 0 && currentrect.ymax == 0)
458 swf_ExpandRect2(¤trect, &r);
464 interpolation_t* new;
465 new = (interpolation_t*)malloc(sizeof(interpolation_t));
466 new->function = IF_LINEAR;
467 dictionary_put2(&interpolations, "linear", new);
469 new = (interpolation_t*)malloc(sizeof(interpolation_t));
470 new->function = IF_QUAD_IN;
472 dictionary_put2(&interpolations, "quadIn", new);
473 new = (interpolation_t*)malloc(sizeof(interpolation_t));
474 new->function = IF_QUAD_OUT;
476 dictionary_put2(&interpolations, "quadOut", new);
477 new = (interpolation_t*)malloc(sizeof(interpolation_t));
478 new->function = IF_QUAD_IN_OUT;
480 dictionary_put2(&interpolations, "quadInOut", new);
482 new = (interpolation_t*)malloc(sizeof(interpolation_t));
483 new->function = IF_CUBIC_IN;
485 dictionary_put2(&interpolations, "cubicIn", new);
486 new = (interpolation_t*)malloc(sizeof(interpolation_t));
487 new->function = IF_CUBIC_OUT;
489 dictionary_put2(&interpolations, "cubicOut", new);
490 new = (interpolation_t*)malloc(sizeof(interpolation_t));
491 new->function = IF_CUBIC_IN_OUT;
493 dictionary_put2(&interpolations, "cubicInOut", new);
495 new = (interpolation_t*)malloc(sizeof(interpolation_t));
496 new->function = IF_QUART_IN;
498 dictionary_put2(&interpolations, "quartIn", new);
499 new = (interpolation_t*)malloc(sizeof(interpolation_t));
500 new->function = IF_QUART_OUT;
502 dictionary_put2(&interpolations, "quartOut", new);
503 new = (interpolation_t*)malloc(sizeof(interpolation_t));
504 new->function = IF_QUART_IN_OUT;
506 dictionary_put2(&interpolations, "quartInOut", new);
508 new = (interpolation_t*)malloc(sizeof(interpolation_t));
509 new->function = IF_QUINT_IN;
511 dictionary_put2(&interpolations, "quintIn", new);
512 new = (interpolation_t*)malloc(sizeof(interpolation_t));
513 new->function = IF_QUINT_OUT;
515 dictionary_put2(&interpolations, "quintOut", new);
516 new = (interpolation_t*)malloc(sizeof(interpolation_t));
517 new->function = IF_QUINT_IN_OUT;
519 dictionary_put2(&interpolations, "quintInOut", new);
521 new = (interpolation_t*)malloc(sizeof(interpolation_t));
522 new->function = IF_CIRCLE_IN;
523 dictionary_put2(&interpolations, "circleIn", new);
524 new = (interpolation_t*)malloc(sizeof(interpolation_t));
525 new->function = IF_CIRCLE_OUT;
526 dictionary_put2(&interpolations, "circleOut", new);
527 new = (interpolation_t*)malloc(sizeof(interpolation_t));
528 new->function = IF_CIRCLE_IN_OUT;
529 dictionary_put2(&interpolations, "circleInOut", new);
531 new = (interpolation_t*)malloc(sizeof(interpolation_t));
532 new->function = IF_EXPONENTIAL_IN;
533 dictionary_put2(&interpolations, "exponentialIn", new);
534 new = (interpolation_t*)malloc(sizeof(interpolation_t));
535 new->function = IF_EXPONENTIAL_OUT;
536 dictionary_put2(&interpolations, "exponentialOut", new);
537 new = (interpolation_t*)malloc(sizeof(interpolation_t));
538 new->function = IF_EXPONENTIAL_IN_OUT;
539 dictionary_put2(&interpolations, "exponentialInOut", new);
541 new = (interpolation_t*)malloc(sizeof(interpolation_t));
542 new->function = IF_SINE_IN;
543 dictionary_put2(&interpolations, "sineIn", new);
544 new = (interpolation_t*)malloc(sizeof(interpolation_t));
545 new->function = IF_SINE_OUT;
546 dictionary_put2(&interpolations, "sineOut", new);
547 new = (interpolation_t*)malloc(sizeof(interpolation_t));
548 new->function = IF_SINE_IN_OUT;
549 dictionary_put2(&interpolations, "sineInOut", new);
552 memset(&c, 0, sizeof(RGBA));
553 gradient_t* noGradient = (gradient_t*)malloc(sizeof(gradient_t));
554 noGradient->gradient.ratios = (U8*)malloc(16 * sizeof(U8));
555 noGradient->gradient.rgba = (RGBA*)malloc(16 * sizeof(RGBA));
556 noGradient->gradient.num = 2;
557 noGradient->gradient.rgba[0] = c;
558 noGradient->gradient.ratios[0] = 0;
559 noGradient->gradient.rgba[1] = c;
560 noGradient->gradient.ratios[1] = 255;
561 noGradient->radial = 0;
562 noGradient->rotate = 0;
563 dictionary_put2(&gradients, "no_gradient", noGradient);
566 // put a no_filters entry in the filters dictionary to provoce a message when a user tries
567 // to define a no_filters filter. The real filter=no_filters case is handled in parseFilters.
568 FILTER* dummy = (FILTER*)malloc(sizeof(FILTER));
569 dictionary_put2(&filters, "no_filters", dummy);
570 noBlur = (FILTER_BLUR*) swf_NewFilter(FILTERTYPE_BLUR);
572 dictionary_put2(&filters, "no_blur", noBlur);
573 noBevel = (FILTER_BEVEL*) swf_NewFilter(FILTERTYPE_BEVEL);
575 noBevel->composite = 1;
576 dictionary_put2(&filters, "no_bevel", noBevel);
577 noDropshadow = (FILTER_DROPSHADOW*) swf_NewFilter(FILTERTYPE_DROPSHADOW);
578 noDropshadow->passes = 1;
579 noDropshadow->composite = 1;
580 dictionary_put2(&filters, "no_dropshadow", noDropshadow);
581 noGradientGlow = (FILTER_GRADIENTGLOW*) swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
582 noGradientGlow->passes = 1;
583 noGradientGlow->composite = 1;
584 noGradientGlow->gradient = &noGradient->gradient;
585 dictionary_put2(&filters, "no_gradientglow", noGradientGlow);
588 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
591 syntaxerror(".swf blocks can't be nested");
592 if(stackpos==sizeof(stack)/sizeof(stack[0]))
593 syntaxerror("too many levels of recursion");
595 SWF*swf = (SWF*)malloc(sizeof(SWF));
597 memset(swf, 0, sizeof(swf));
598 swf->fileVersion = version;
600 swf->frameRate = fps;
601 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
602 swf->compressed = compress;
603 swf_SetRGB(tag,&background);
605 dictionary_init(&characters);
606 dictionary_init(&images);
607 dictionary_init(&textures);
608 dictionary_init(&outlines);
609 dictionary_init(&gradients);
610 dictionary_init(&filters);
611 dictionary_init(&instances);
612 dictionary_init(&sounds);
613 dictionary_init(&interpolations);
615 cleanUp = &freeDictionaries;
617 memset(&stack[stackpos], 0, sizeof(stack[0]));
618 stack[stackpos].type = 0;
619 stack[stackpos].filename = strdup(name);
620 stack[stackpos].swf = swf;
621 stack[stackpos].oldframe = -1;
625 memset(¤trect, 0, sizeof(currentrect));
628 memset(idmap, 0, sizeof(idmap));
632 void s_sprite(char*name)
634 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
635 swf_SetU16(tag, id); //id
636 swf_SetU16(tag, 0); //frames
638 memset(&stack[stackpos], 0, sizeof(stack[0]));
639 stack[stackpos].type = 1;
640 stack[stackpos].oldframe = currentframe;
641 stack[stackpos].olddepth = currentdepth;
642 stack[stackpos].oldrect = currentrect;
643 stack[stackpos].oldinstances = instances;
644 stack[stackpos].tag = tag;
645 stack[stackpos].id = id;
646 stack[stackpos].name = strdup(name);
648 /* FIXME: those four fields should be bundled together */
649 dictionary_init(&instances);
652 memset(¤trect, 0, sizeof(currentrect));
658 typedef struct _buttonrecord
666 typedef struct _button
670 buttonrecord_t records[4];
673 static button_t mybutton;
675 void s_button(char*name)
677 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
678 swf_SetU16(tag, id); //id
679 swf_ButtonSetFlags(tag, 0); //menu=no
681 memset(&mybutton, 0, sizeof(mybutton));
683 memset(&stack[stackpos], 0, sizeof(stack[0]));
684 stack[stackpos].type = 3;
685 stack[stackpos].tag = tag;
686 stack[stackpos].id = id;
687 stack[stackpos].name = strdup(name);
688 stack[stackpos].oldrect = currentrect;
689 memset(¤trect, 0, sizeof(currentrect));
694 void s_buttonput(char*character, char*as, parameters_t p)
696 character_t* c = dictionary_lookup(&characters, character);
701 if(!stackpos || (stack[stackpos-1].type != 3)) {
702 syntaxerror(".show may only appear in .button");
705 syntaxerror("character %s not known (in .shape %s)", character, character);
707 if(mybutton.endofshapes) {
708 syntaxerror("a .do may not precede a .show", character, character);
711 m = s_instancepos(c->size, &p);
719 if(*s==',' || *s==0) {
720 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
721 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
722 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
723 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
724 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
725 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
732 static void setbuttonrecords(TAG*tag)
734 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
735 if(!mybutton.endofshapes) {
738 if(!mybutton.records[3].set) {
739 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
743 if(mybutton.records[t].set) {
744 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
747 swf_SetU8(tag,0); // end of button records
748 mybutton.endofshapes = 1;
752 void s_buttonaction(int flags, char*action)
758 setbuttonrecords(stack[stackpos-1].tag);
760 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
762 syntaxerror("Couldn't compile ActionScript");
765 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
766 swf_ActionSet(stack[stackpos-1].tag, a);
767 mybutton.nr_actions++;
772 static void setactionend(TAG*tag)
774 if(!mybutton.nr_actions) {
775 /* no actions means we didn't have an actionoffset,
776 which means we can't signal the end of the
777 buttonaction records, so, *sigh*, we have
778 to insert a dummy record */
779 swf_SetU16(tag, 0); //offset
780 swf_SetU16(tag, 0); //condition
781 swf_SetU8(tag, 0); //action
785 static void s_endButton()
788 setbuttonrecords(stack[stackpos-1].tag);
789 setactionend(stack[stackpos-1].tag);
792 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
796 tag = stack[stackpos].tag;
797 currentrect = stack[stackpos].oldrect;
799 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
800 free(stack[stackpos].name);
803 TAG* removeFromTo(TAG*from, TAG*to)
805 TAG*save = from->prev;
807 TAG*next = from->next;
815 static int parametersChange(history_t* history, int frame)
819 willChange = willChange || history_change(history, frame, "x");
820 willChange = willChange || history_change(history, frame, "y");
821 willChange = willChange || history_change(history, frame, "scalex");
822 willChange = willChange || history_change(history, frame, "scaley");
823 willChange = willChange || history_change(history, frame, "cxform.r0");
824 willChange = willChange || history_change(history, frame, "cxform.g0");
825 willChange = willChange || history_change(history, frame, "cxform.b0");
826 willChange = willChange || history_change(history, frame, "cxform.a0");
827 willChange = willChange || history_change(history, frame, "cxform.r1");
828 willChange = willChange || history_change(history, frame, "cxform.g1");
829 willChange = willChange || history_change(history, frame, "cxform.b1");
830 willChange = willChange || history_change(history, frame, "cxform.a1");
831 willChange = willChange || history_change(history, frame, "rotate");
832 willChange = willChange || history_change(history, frame, "shear");
833 willChange = willChange || history_change(history, frame, "pivot.x");
834 willChange = willChange || history_change(history, frame, "pivot.y");
835 willChange = willChange || history_change(history, frame, "pin.x");
836 willChange = willChange || history_change(history, frame, "pin.y");
837 willChange = willChange || history_change(history, frame, "blendmode");
838 willChange = willChange || history_changeFilter(history, frame);
843 static void free_filterlist(FILTERLIST* f_list)
846 for (i = 0; i < f_list->num; i++)
848 if (f_list->filter[i]->type == FILTERTYPE_GRADIENTGLOW)
849 gradient_free(((FILTER_GRADIENTGLOW*)f_list->filter[i])->gradient);
850 free(f_list->filter[i]);
855 static void readParameters(history_t* history, parameters_t* p, int frame)
857 p->x = history_value(history, frame, "x");
858 p->y = history_value(history, frame, "y");
859 p->scalex = history_value(history, frame, "scalex");
860 p->scaley = history_value(history, frame, "scaley");
861 p->cxform.r0 = history_value(history, frame, "cxform.r0");
862 p->cxform.g0 = history_value(history, frame, "cxform.g0");
863 p->cxform.b0 = history_value(history, frame, "cxform.b0");
864 p->cxform.a0 = history_value(history, frame, "cxform.a0");
865 p->cxform.r1 = history_value(history, frame, "cxform.r1");
866 p->cxform.g1 = history_value(history, frame, "cxform.g1");
867 p->cxform.b1 = history_value(history, frame, "cxform.b1");
868 p->cxform.a1 = history_value(history, frame, "cxform.a1");
869 p->rotate = history_rotateValue(history, frame);
870 p->shear = history_value(history, frame, "shear");
871 p->pivot.x = history_value(history, frame, "pivot.x");
872 p->pivot.y = history_value(history, frame, "pivot.y");
873 p->pin.x = history_value(history, frame, "pin.x");
874 p->pin.y = history_value(history, frame, "pin.y");
875 p->blendmode = history_value(history, frame, "blendmode");
876 p->filters = history_filterValue(history, frame);
879 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, char*name, parameters_t*p, char move)
883 swf_GetPlaceObject(NULL, &po);
887 po.cxform = p->cxform;
893 po.blendmode = p->blendmode;
896 po.filters = p->filters;
897 swf_SetPlaceObject(tag, &po);
900 static void writeInstance(instance_t* i)
904 int frame = i->history->firstFrame;
905 TAG* tag = i->history->firstTag;
906 history_processFlags(i->history);
907 while (frame < currentframe)
910 while (tag->id != ST_SHOWFRAME)
912 if (parametersChange(i->history, frame))
914 readParameters(i->history, &p, frame);
915 m = s_instancepos(i->character->size, &p);
917 if(p.blendmode || p.filters)
918 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
920 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
921 setPlacement(tag, 0, i->depth, m, 0, &p, 1);
923 free_filterlist(p.filters);
930 void dumpSWF(SWF*swf)
932 TAG* tag = swf->firstTag;
933 printf("vvvvvvvvvvvvvvvvvvvvv\n");
935 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
938 printf("^^^^^^^^^^^^^^^^^^^^^\n");
941 static void s_endSprite()
943 SRECT r = currentrect;
945 if(stack[stackpos].cut)
946 tag = removeFromTo(stack[stackpos].cut, tag);
950 stringarray_t* index =dictionary_index(&instances);
952 for (num = 0; num < dictionary_count(&instances); num++)
954 char* name = stringarray_at(index, num);
957 i = dictionary_lookup(&instances, name);
964 tag = swf_InsertTag(tag, ST_SHOWFRAME);
965 tag = swf_InsertTag(tag, ST_END);
967 tag = stack[stackpos].tag;
970 syntaxerror("internal error(7)");
971 /* TODO: before clearing, prepend "<spritename>." to names and
972 copy into old instances dict */
973 dictionary_free_all(&instances, free_instance);
975 currentframe = stack[stackpos].oldframe;
976 currentrect = stack[stackpos].oldrect;
977 currentdepth = stack[stackpos].olddepth;
978 instances = stack[stackpos].oldinstances;
980 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
981 free(stack[stackpos].name);
984 static void s_endSWF()
991 stringarray_t* index = dictionary_index(&instances);
993 for (num = 0; num < dictionary_count(&instances); num++)
995 char* name = stringarray_at(index, num);
998 i = dictionary_lookup(&instances, name);
1003 if(stack[stackpos].cut)
1004 tag = removeFromTo(stack[stackpos].cut, tag);
1008 swf = stack[stackpos].swf;
1009 filename = stack[stackpos].filename;
1011 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
1012 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
1013 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1015 tag = swf_InsertTag(tag, ST_END);
1017 swf_OptimizeTagOrder(swf);
1023 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1024 swf->movieSize = currentrect; /* "autocrop" */
1027 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1028 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
1029 swf->movieSize.ymax += 20;
1030 warning("Empty bounding box for movie");
1033 if(do_cgi || !strcmp(filename, "-"))
1034 fi = fileno(stdout);
1036 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
1038 syntaxerror("couldn't create output file %s", filename);
1041 {if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
1042 else if(swf->compressed)
1043 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
1045 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
1059 if(stack[stackpos-1].type == 0)
1060 syntaxerror("End of file encountered in .flash block");
1061 if(stack[stackpos-1].type == 1)
1062 syntaxerror("End of file encountered in .sprite block");
1063 if(stack[stackpos-1].type == 2)
1064 syntaxerror("End of file encountered in .clip block");
1070 return currentframe+1;
1073 void s_frame(int nr, int cut, char*name, char anchor)
1079 syntaxerror("Illegal frame number");
1080 nr--; // internally, frame 1 is frame 0
1082 for(t=currentframe;t<nr;t++) {
1083 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1084 if(t==nr-1 && name && *name) {
1085 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1086 swf_SetString(tag, name);
1088 swf_SetU8(tag, 1); //make this an anchor
1091 if(nr == 0 && currentframe == 0 && name && *name) {
1092 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1093 swf_SetString(tag, name);
1095 swf_SetU8(tag, 1); //make this an anchor
1100 syntaxerror("Can't cut, frame empty");
1102 stack[stackpos].cut = tag;
1108 int parseColor2(char*str, RGBA*color);
1110 int addFillStyle(SHAPE*s, SRECT*r, char*name)
1114 gradient_t*gradient;
1116 if(name[0] == '#') {
1117 parseColor2(name, &color);
1118 return swf_ShapeAddSolidFillStyle(s, &color);
1119 } else if ((texture = dictionary_lookup(&textures, name))) {
1120 return swf_ShapeAddFillStyle2(s, &texture->fs);
1121 } else if((image = dictionary_lookup(&images, name))) {
1123 swf_GetMatrix(0, &m);
1124 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1125 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1128 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1129 } else if ((gradient = dictionary_lookup(&gradients, name))) {
1133 swf_GetMatrix(0, &rot);
1134 ccos = cos(-gradient->rotate*2*M_PI/360);
1135 csin = sin(-gradient->rotate*2*M_PI/360);
1136 rot.sx = ccos*65536;
1137 rot.r1 = -csin*65536;
1138 rot.r0 = csin*65536;
1139 rot.sy = ccos*65536;
1140 r2 = swf_TurnRect(*r, &rot);
1141 swf_GetMatrix(0, &m);
1142 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1143 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1144 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1145 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1146 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1147 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1148 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1149 } else if (parseColor2(name, &color)) {
1150 return swf_ShapeAddSolidFillStyle(s, &color);
1152 syntaxerror("not a color/fillstyle: %s", name);
1157 RGBA black={r:0,g:0,b:0,a:0};
1158 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
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 r.xmin = r2.xmin-linewidth/2;
1178 r.ymin = r2.ymin-linewidth/2;
1179 r.xmax = r2.xmax+linewidth/2;
1180 r.ymax = r2.ymax+linewidth/2;
1181 swf_SetRect(tag,&r);
1182 swf_SetShapeHeader(tag,s);
1183 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1184 swf_ShapeSetLine(tag,s,width,0);
1185 swf_ShapeSetLine(tag,s,0,height);
1186 swf_ShapeSetLine(tag,s,-width,0);
1187 swf_ShapeSetLine(tag,s,0,-height);
1188 swf_ShapeSetEnd(tag);
1191 s_addcharacter(name, id, tag, r);
1195 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
1201 outline = dictionary_lookup(&outlines, outlinename);
1203 syntaxerror("outline %s not defined", outlinename);
1207 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1210 linewidth = linewidth>=20?linewidth-20:0;
1211 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1214 fs1 = addFillStyle(s, &r2, texture);
1217 rect.xmin = r2.xmin-linewidth/2;
1218 rect.ymin = r2.ymin-linewidth/2;
1219 rect.xmax = r2.xmax+linewidth/2;
1220 rect.ymax = r2.ymax+linewidth/2;
1222 swf_SetRect(tag,&rect);
1223 swf_SetShapeStyles(tag, s);
1224 swf_ShapeCountBits(s,0,0);
1225 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1226 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1227 swf_SetShapeBits(tag, s);
1228 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1231 s_addcharacter(name, id, tag, rect);
1235 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
1240 r2.xmin = r2.ymin = 0;
1244 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1247 linewidth = linewidth>=20?linewidth-20:0;
1248 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1251 fs1 = addFillStyle(s, &r2, texture);
1253 rect.xmin = r2.xmin-linewidth/2;
1254 rect.ymin = r2.ymin-linewidth/2;
1255 rect.xmax = r2.xmax+linewidth/2;
1256 rect.ymax = r2.ymax+linewidth/2;
1258 swf_SetRect(tag,&rect);
1259 swf_SetShapeHeader(tag,s);
1260 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1261 swf_ShapeSetCircle(tag, s, r,r,r,r);
1262 swf_ShapeSetEnd(tag);
1265 s_addcharacter(name, id, tag, rect);
1269 void s_textshape(char*name, char*fontname, float size, char*_text)
1272 U8*text = (U8*)_text;
1276 font = dictionary_lookup(&fonts, fontname);
1278 syntaxerror("font \"%s\" not known!", fontname);
1280 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1281 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1282 s_box(name, 0, 0, black, 20, 0);
1285 g = font->ascii2glyph[text[0]];
1287 outline = malloc(sizeof(outline_t));
1288 memset(outline, 0, sizeof(outline_t));
1289 outline->shape = font->glyph[g].shape;
1290 outline->bbox = font->layout->bounds[g];
1294 swf_Shape11DrawerInit(&draw, 0);
1295 swf_DrawText(&draw, font, (int)(size*100), _text);
1297 outline->shape = swf_ShapeDrawerToShape(&draw);
1298 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1299 draw.dealloc(&draw);
1302 if(dictionary_lookup(&outlines, name))
1303 syntaxerror("outline %s defined twice", name);
1304 dictionary_put2(&outlines, name, outline);
1307 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
1312 font = dictionary_lookup(&fonts, fontname);
1314 syntaxerror("font \"%s\" not known!", fontname);
1316 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1317 swf_SetU16(tag, id);
1318 if(!font->numchars) {
1319 s_box(name, 0, 0, black, 20, 0);
1322 r = swf_SetDefineText(tag, font, &color, text, size);
1324 if(stack[0].swf->fileVersion >= 8) {
1325 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1326 swf_SetU16(tag, id);
1327 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1328 swf_SetU32(tag, 0);//thickness
1329 swf_SetU32(tag, 0);//sharpness
1330 swf_SetU8(tag, 0);//reserved
1333 s_addcharacter(name, id, tag, r);
1337 void s_quicktime(char*name, char*url)
1342 memset(&r, 0, sizeof(r));
1344 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1345 swf_SetU16(tag, id);
1346 swf_SetString(tag, url);
1348 s_addcharacter(name, id, tag, r);
1352 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)
1355 EditTextLayout layout;
1358 if(fontname && *fontname) {
1359 flags |= ET_USEOUTLINES;
1360 font = dictionary_lookup(&fonts, fontname);
1362 syntaxerror("font \"%s\" not known!", fontname);
1364 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1365 swf_SetU16(tag, id);
1366 layout.align = align;
1367 layout.leftmargin = 0;
1368 layout.rightmargin = 0;
1376 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
1378 s_addcharacter(name, id, tag, r);
1382 /* type: either "jpeg" or "png"
1384 void s_image(char*name, char*type, char*filename, int quality)
1386 /* an image is actually two folded: 1st bitmap, 2nd character.
1387 Both of them can be used separately */
1389 /* step 1: the bitmap */
1393 if(!strcmp(type,"jpeg")) {
1394 #ifndef HAVE_JPEGLIB
1395 warning("no jpeg support compiled in");
1396 s_box(name, 0, 0, black, 20, 0);
1399 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1400 swf_SetU16(tag, imageID);
1402 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1403 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1406 swf_GetJPEGSize(filename, &width, &height);
1413 s_addimage(name, id, tag, r);
1416 } else if(!strcmp(type,"png")) {
1418 swf_SetU16(tag, imageID);
1420 getPNG(filename, &width, &height, (unsigned char**)&data);
1423 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1426 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1427 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1428 swf_SetU16(tag, imageID);
1429 swf_SetLosslessImage(tag, data, width, height);
1436 s_addimage(name, id, tag, r);
1439 warning("image type \"%s\" not supported yet!", type);
1440 s_box(name, 0, 0, black, 20, 0);
1444 /* step 2: the character */
1445 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1446 swf_SetU16(tag, id);
1447 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1449 s_addcharacter(name, id, tag, r);
1453 void s_getBitmapSize(char*name, int*width, int*height)
1455 character_t* image = dictionary_lookup(&images, name);
1456 gradient_t* gradient = dictionary_lookup(&gradients,name);
1458 *width = image->size.xmax;
1459 *height = image->size.ymax;
1463 /* internal SWF gradient size */
1464 if(gradient->radial) {
1473 syntaxerror("No such bitmap/gradient: %s", name);
1476 void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1478 if(dictionary_lookup(&textures, name))
1479 syntaxerror("texture %s defined twice", name);
1480 gradient_t* gradient = dictionary_lookup(&gradients, object);
1481 character_t* bitmap = dictionary_lookup(&images, object);
1482 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1484 FILLSTYLE*fs = &texture->fs;
1486 memset(&p, 0, sizeof(parameters_t));
1489 fs->type = FILL_TILED;
1490 fs->id_bitmap = bitmap->id;
1491 } else if(gradient) {
1492 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1493 fs->gradient = gradient->gradient;
1495 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1496 makeMatrix(&fs->m, &p);
1497 if(gradient && !gradient->radial) {
1504 p2 = swf_TurnPoint(p1, &m);
1513 dictionary_put2(&textures, name, texture);
1516 void s_font(char*name, char*filename)
1519 font = dictionary_lookup(&fonts, name);
1522 /* fix the layout. Only needed for old fonts */
1524 for(t=0;t<font->numchars;t++) {
1525 font->glyph[t].advance = 0;
1528 swf_FontCreateLayout(font);
1531 swf_FontReduce_swfc(font);
1532 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1533 swf_FontSetDefine2(tag, font);
1534 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1536 swf_SetU16(tag, id);
1537 swf_SetString(tag, name);
1544 typedef struct _sound_t
1550 void s_sound(char*name, char*filename)
1552 struct WAV wav, wav2;
1556 unsigned numsamples = 1;
1557 unsigned blocksize = 1152;
1560 if(dictionary_lookup(&sounds, name))
1561 syntaxerror("sound %s defined twice", name);
1563 if(wav_read(&wav, filename))
1566 wav_convert2mono(&wav, &wav2, 44100);
1567 samples = (U16*)wav2.data;
1568 numsamples = wav2.size/2;
1570 #ifdef WORDS_BIGENDIAN
1572 for(t=0;t<numsamples;t++)
1573 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1577 if(mp3_read(&mp3, filename))
1579 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1585 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1590 if(numsamples%blocksize != 0)
1592 // apply padding, so that block is a multiple of blocksize
1593 int numblocks = (numsamples+blocksize-1)/blocksize;
1596 numsamples2 = numblocks * blocksize;
1597 samples2 = malloc(sizeof(U16)*numsamples2);
1598 memcpy(samples2, samples, numsamples*sizeof(U16));
1599 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1600 numsamples = numsamples2;
1605 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1606 swf_SetU16(tag, id); //id
1609 swf_SetSoundDefineMP3(
1610 tag, mp3.data, mp3.size,
1617 swf_SetSoundDefine(tag, samples, numsamples);
1619 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1620 swf_SetU16(tag, id);
1621 swf_SetString(tag, name);
1622 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1624 swf_SetU16(tag, id);
1625 swf_SetString(tag, name);
1627 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1631 dictionary_put2(&sounds, name, sound);
1639 static char* gradient_getToken(const char**p)
1643 while(**p && strchr(" \t\n\r", **p)) {
1647 while(**p && !strchr(" \t\n\r", **p)) {
1650 result = malloc((*p)-start+1);
1651 memcpy(result,start,(*p)-start+1);
1652 result[(*p)-start] = 0;
1656 float parsePercent(char*str);
1657 RGBA parseColor(char*str);
1659 GRADIENT parseGradient(const char*str)
1663 const char* p = str;
1664 memset(&gradient, 0, sizeof(GRADIENT));
1665 gradient.ratios = rfx_calloc(16*sizeof(U8));
1666 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1670 char*posstr,*colorstr;
1673 posstr = gradient_getToken(&p);
1679 pos = (int)(parsePercent(posstr)*255.0);
1684 rfx_free(gradient.ratios);
1685 rfx_free(gradient.rgba);
1687 syntaxerror("Error in shape data: Color expected after %s", posstr);
1689 colorstr = gradient_getToken(&p);
1690 color = parseColor(colorstr);
1691 if(gradient.num == 16)
1693 warning("gradient record too big- max size is 16, rest ignored");
1696 gradient.ratios[gradient.num] = pos;
1697 gradient.rgba[gradient.num] = color;
1706 FILTERLIST* parseFilters(char* list)
1708 if (!strcmp(list, "no_filters"))
1711 FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1713 char* f_start = list;
1717 f_end = strchr(f_start, ',');
1720 f = dictionary_lookup(&filters, f_start);
1724 syntaxerror("unknown filter %s", f_start);
1726 if (f_list->num == 8)
1728 warning("too many filters in filterlist, no more than 8 please, rest ignored");
1731 f_list->filter[f_list->num] = f;
1736 f_start = f_end + 1;
1744 void s_gradient(char*name, const char*text, int radial, int rotate)
1746 gradient_t* gradient;
1747 gradient = malloc(sizeof(gradient_t));
1748 memset(gradient, 0, sizeof(gradient_t));
1749 gradient->gradient = parseGradient(text);
1750 gradient->radial = radial;
1751 gradient->rotate = rotate;
1753 dictionary_put2(&gradients, name, gradient);
1756 void s_gradientglow(char*name, char*gradient, float blurx, float blury,
1757 float angle, float distance, float strength, char innershadow,
1758 char knockout, char composite, char ontop, int passes)
1760 if(dictionary_lookup(&filters, name))
1761 syntaxerror("filter %s defined twice", name);
1763 gradient_t* g = dictionary_lookup(&gradients, gradient);
1765 syntaxerror("unknown gradient %s", gradient);
1769 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1770 filter->type = FILTERTYPE_GRADIENTGLOW;
1771 filter->gradient = &g->gradient;
1772 filter->blurx = blurx;
1773 filter->blury = blury;
1774 filter->strength = strength;
1775 filter->angle = angle;
1776 filter->distance = distance;
1777 filter->innershadow = innershadow;
1778 filter->knockout = knockout;
1779 filter->composite = composite;
1780 filter->ontop = ontop;
1781 filter->passes = passes;
1783 dictionary_put2(&filters, name, filter);
1786 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)
1788 if(dictionary_lookup(&filters, name))
1789 syntaxerror("filter %s defined twice", name);
1792 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1793 filter->type = FILTERTYPE_DROPSHADOW;
1794 filter->color= color;
1795 filter->blurx = blurx;
1796 filter->blury = blury;
1797 filter->strength = strength;
1798 filter->angle = angle;
1799 filter->distance = distance;
1800 filter->innershadow = innershadow;
1801 filter->knockout = knockout;
1802 filter->composite = composite;
1803 filter->passes = passes;
1805 dictionary_put2(&filters, name, filter);
1808 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)
1810 if(dictionary_lookup(&filters, name))
1811 syntaxerror("filter %s defined twice", name);
1814 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1815 filter->type = FILTERTYPE_BEVEL;
1816 filter->shadow = shadow;
1817 filter->highlight = highlight;
1818 filter->blurx = blurx;
1819 filter->blury = blury;
1820 filter->strength = strength;
1821 filter->angle = angle;
1822 filter->distance = distance;
1823 filter->innershadow = innershadow;
1824 filter->knockout = knockout;
1825 filter->composite = composite;
1826 filter->ontop = ontop;
1827 filter->passes = passes;
1829 dictionary_put2(&filters, name, filter);
1832 void s_blur(char*name, double blurx, double blury, int passes)
1834 if(dictionary_lookup(&filters, name))
1835 syntaxerror("filter %s defined twice", name);
1837 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1838 filter->type = FILTERTYPE_BLUR;
1839 filter->blurx = blurx;
1840 filter->blury = blury;
1841 filter->passes = passes;
1843 dictionary_put2(&filters, name, filter);
1846 void s_action(const char*text)
1849 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1853 syntaxerror("Couldn't compile ActionScript");
1856 tag = swf_InsertTag(tag, ST_DOACTION);
1858 swf_ActionSet(tag, a);
1863 void s_initaction(const char*character, const char*text)
1867 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1871 syntaxerror("Couldn't compile ActionScript");
1874 c = (character_t*)dictionary_lookup(&characters, character);
1876 tag = swf_InsertTag(tag, ST_DOINITACTION);
1877 swf_SetU16(tag, c->id);
1878 swf_ActionSet(tag, a);
1883 int s_swf3action(char*name, char*action)
1886 instance_t* object = 0;
1888 object = (instance_t*)dictionary_lookup(&instances, name);
1889 if(!object && name && *name) {
1890 /* we have a name, but couldn't find it. Abort. */
1893 a = action_SetTarget(0, name);
1894 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1895 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1896 else if(!strcmp(action, "stop")) a = action_Stop(a);
1897 else if(!strcmp(action, "play")) a = action_Play(a);
1898 a = action_SetTarget(a, "");
1901 tag = swf_InsertTag(tag, ST_DOACTION);
1902 swf_ActionSet(tag, a);
1907 void s_outline(char*name, char*format, char*source)
1909 if(dictionary_lookup(&outlines, name))
1910 syntaxerror("outline %s defined twice", name);
1919 //swf_Shape10DrawerInit(&draw, 0);
1920 swf_Shape11DrawerInit(&draw, 0);
1922 draw_string(&draw, source);
1924 shape = swf_ShapeDrawerToShape(&draw);
1925 bounds = swf_ShapeDrawerGetBBox(&draw);
1926 draw.dealloc(&draw);
1928 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1929 outline->shape = shape;
1930 outline->bbox = bounds;
1932 dictionary_put2(&outlines, name, outline);
1935 int s_playsound(char*name, int loops, int nomultiple, int stop)
1941 sound = dictionary_lookup(&sounds, name);
1945 tag = swf_InsertTag(tag, ST_STARTSOUND);
1946 swf_SetU16(tag, sound->id); //id
1947 memset(&info, 0, sizeof(info));
1950 info.nomultiple = nomultiple;
1951 swf_SetSoundInfo(tag, &info);
1955 void s_includeswf(char*name, char*filename)
1963 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1964 f = open(filename,O_RDONLY|O_BINARY);
1966 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1967 s_box(name, 0, 0, black, 20, 0);
1970 if (swf_ReadSWF(f,&swf)<0) {
1971 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1972 s_box(name, 0, 0, black, 20, 0);
1977 /* FIXME: The following sets the bounding Box for the character.
1978 It is wrong for two reasons:
1979 a) It may be too small (in case objects in the movie clip at the borders)
1980 b) it may be too big (because the poor movie never got autocropped)
1984 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1985 swf_SetU16(tag, id);
1986 swf_SetU16(tag, swf.frameCount);
1988 swf_Relocate(&swf, idmap);
1990 ftag = swf.firstTag;
1994 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1995 if(cutout[t] == ftag->id) {
1999 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
2001 if(ftag->id == ST_END)
2006 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
2007 /* We simply dump all tags right after the sprite
2008 header, relying on the fact that swf_OptimizeTagOrder() will
2009 sort things out for us later.
2010 We also rely on the fact that the imported SWF is well-formed.
2012 tag = swf_InsertTag(tag, ftag->id);
2013 swf_SetBlock(tag, ftag->data, ftag->len);
2019 syntaxerror("Included file %s contains errors", filename);
2020 tag = swf_InsertTag(tag, ST_END);
2024 s_addcharacter(name, id, tag, r);
2027 SRECT s_getCharBBox(char*name)
2029 character_t* c = dictionary_lookup(&characters, name);
2030 if(!c) syntaxerror("character '%s' unknown(2)", name);
2033 SRECT s_getInstanceBBox(char*name)
2035 instance_t * i = dictionary_lookup(&instances, name);
2037 if(!i) syntaxerror("instance '%s' unknown(4)", name);
2039 if(!c) syntaxerror("internal error(5)");
2042 void s_getParameters(char*name, parameters_t* p)
2044 instance_t * i = dictionary_lookup(&instances, name);
2046 syntaxerror("instance '%s' unknown(10)", name);
2047 if (change_sets_all)
2048 readParameters(i->history, p, currentframe);
2052 void s_startclip(char*instance, char*character, parameters_t p)
2054 character_t* c = dictionary_lookup(&characters, character);
2058 syntaxerror("character %s not known", character);
2060 i = s_addinstance(instance, c, currentdepth);
2062 m = s_instancepos(i->character->size, &p);
2064 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2065 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2066 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2068 stack[stackpos].tag = tag;
2069 stack[stackpos].type = 2;
2078 swf_SetTagPos(stack[stackpos].tag, 0);
2079 swf_GetPlaceObject(stack[stackpos].tag, &p);
2080 p.clipdepth = currentdepth;
2082 swf_ClearTag(stack[stackpos].tag);
2083 swf_SetPlaceObject(stack[stackpos].tag, &p);
2087 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2089 history_begin(i->history, "x", currentframe, tag, p->x);
2090 history_begin(i->history, "y", currentframe, tag, p->y);
2091 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2092 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2093 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2094 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2095 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2096 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2097 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2098 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2099 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2100 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2101 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2102 history_begin(i->history, "shear", currentframe, tag, p->shear);
2103 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2104 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2105 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2106 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2107 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2108 history_beginFilter(i->history, currentframe, tag, p->filters);
2109 history_begin(i->history, "flags", currentframe, tag, 0);
2112 void s_put(char*instance, char*character, parameters_t p)
2114 character_t* c = dictionary_lookup(&characters, character);
2118 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2120 i = s_addinstance(instance, c, currentdepth);
2122 m = s_instancepos(i->character->size, &p);
2124 if(p.blendmode || p.filters)
2126 if(stack[0].swf->fileVersion < 8)
2129 warning("blendmodes only supported for flash version>=8");
2131 warning("filters only supported for flash version>=8");
2133 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2136 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2137 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2138 setStartparameters(i, &p, tag);
2142 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2145 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2147 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2148 if (p.set & SF_SCALEX)
2149 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2150 if (p.set & SF_SCALEY)
2151 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2152 if (p.set & SF_CX_R)
2154 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2155 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2157 if (p.set & SF_CX_G)
2159 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2160 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2162 if (p.set & SF_CX_B)
2164 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2165 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2167 if (p.set & SF_CX_A)
2169 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2170 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2172 if (p.set & SF_ROTATE)
2173 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2174 if (p.set & SF_SHEAR)
2175 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2176 if (p.set & SF_PIVOT)
2178 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2179 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2183 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2184 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2186 if (p.set & SF_BLEND)
2187 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2188 if (p.set & SF_FILTER)
2189 history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2192 void s_jump(char* instance, parameters_t p)
2194 instance_t* i = dictionary_lookup(&instances, instance);
2196 syntaxerror("instance %s not known", instance);
2197 recordChanges(i->history, p, CF_JUMP, 0);
2200 void s_change(char*instance, parameters_t p, interpolation_t* inter)
2202 instance_t* i = dictionary_lookup(&instances, instance);
2204 syntaxerror("instance %s not known", instance);
2205 recordChanges(i->history, p, CF_CHANGE, inter);
2208 void s_sweep(char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
2210 instance_t* i = dictionary_lookup(&instances, instance);
2212 syntaxerror("instance %s not known", instance);
2213 history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
2216 void s_toggle(char* instance, U16 flagsOn, U16 flagsOff)
2218 instance_t* i = dictionary_lookup(&instances, instance);
2220 syntaxerror("instance %s not known", instance);
2221 U16 flags = (U16)history_value(i->history, currentframe, "flags");
2224 history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
2227 void s_delinstance(char*instance)
2229 instance_t* i = dictionary_lookup(&instances, instance);
2231 syntaxerror("instance %s not known", instance);
2233 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2234 swf_SetU16(tag, i->depth);
2235 dictionary_del(&instances, instance);
2238 void s_schange(char*instance, parameters_t p, interpolation_t* inter)
2240 instance_t* i = dictionary_lookup(&instances, instance);
2242 syntaxerror("instance %s not known", instance);
2243 recordChanges(i->history, p, CF_SCHANGE, inter);
2249 syntaxerror(".end unexpected");
2250 switch (stack[stackpos-1].type)
2265 syntaxerror("internal error 1");
2269 // ------------------------------------------------------------------------
2271 typedef int command_func_t(map_t*args);
2273 SRECT parseBox(char*str)
2275 SRECT r = {0,0,0,0};
2276 float xmin, xmax, ymin, ymax;
2277 char*x = strchr(str, 'x');
2279 if(!strcmp(str, "autocrop")) {
2280 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2284 d1 = strchr(x+1, ':');
2286 d2 = strchr(d1+1, ':');
2288 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2292 else if(d1 && !d2) {
2293 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2299 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2304 r.xmin = (SCOORD)(xmin*20);
2305 r.ymin = (SCOORD)(ymin*20);
2306 r.xmax = (SCOORD)(xmax*20);
2307 r.ymax = (SCOORD)(ymax*20);
2310 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2313 float parseFloat(char*str)
2317 int parseInt(char*str)
2322 if(str[0]=='+' || str[0]=='-')
2326 if(str[t]<'0' || str[t]>'9')
2327 syntaxerror("Not an Integer: \"%s\"", str);
2330 int parseTwip(char*str)
2334 if(str[0]=='+' || str[0]=='-') {
2339 dot = strchr(str, '.');
2343 return sign*parseInt(str)*20;
2345 char* old = strdup(str);
2346 int l=strlen(dot+1);
2349 for(s=str;s<dot-1;s++)
2350 if(*s<'0' || *s>'9')
2353 syntaxerror("Not a coordinate: \"%s\"", str);
2356 if(*s<'0' || *s>'9')
2359 syntaxerror("Not a coordinate: \"%s\"", str);
2361 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2362 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2365 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2369 return sign*atoi(str)*20;
2371 return sign*atoi(str)*20+atoi(dot)*2;
2373 return sign*atoi(str)*20+atoi(dot)/5;
2378 int parseArc(char* str)
2380 if (!strcmp(str, "short"))
2382 if (!strcmp(str, "long"))
2384 syntaxerror("invalid value for the arc parameter: %s", str);
2388 int parseDir(char* str)
2390 if (!strcmp(str, "clockwise"))
2392 if (!strcmp(str, "counterclockwise"))
2394 syntaxerror("invalid value for the dir parameter: %s", str);
2398 int isPoint(char*str)
2400 if(strchr(str, '('))
2406 SPOINT parsePoint(char*str)
2410 int l = strlen(str);
2411 char*comma = strchr(str, ',');
2412 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2413 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2414 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2415 p.x = parseTwip(tmp);
2416 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2417 p.y = parseTwip(tmp);
2421 int parseColor2(char*str, RGBA*color)
2423 int l = strlen(str);
2427 struct {unsigned char r,g,b;char*name;} colors[] =
2428 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2429 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2430 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2431 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2432 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2433 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2434 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2435 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2436 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2437 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2438 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2439 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2443 if(str[0]=='#' && (l==7 || l==9)) {
2444 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2446 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2448 color->r = r; color->g = g; color->b = b; color->a = a;
2451 int len=strlen(str);
2453 if(strchr(str, '/')) {
2454 len = strchr(str, '/')-str;
2455 sscanf(str+len+1,"%02x", &alpha);
2457 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2458 if(!strncmp(str, colors[t].name, len)) {
2463 color->r = r; color->g = g; color->b = b; color->a = a;
2469 RGBA parseColor(char*str)
2472 if(!parseColor2(str, &c))
2473 syntaxerror("Expression '%s' is not a color", str);
2477 typedef struct _muladd {
2482 MULADD parseMulAdd(char*str)
2485 char* str2 = (char*)malloc(strlen(str)+5);
2492 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2493 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2494 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2495 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2496 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2497 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2498 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2499 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2500 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2501 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2503 syntaxerror("'%s' is not a valid color transform expression", str);
2505 m.add = (int)(add*256);
2506 m.mul = (int)(mul*256);
2511 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2513 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2514 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2516 if(a<-32768) a=-32768;
2517 if(a>32767) a=32767;
2518 if(m<-32768) m=-32768;
2519 if(m>32767) m=32767;
2525 float parsePxOrPercent(char*fontname, char*str)
2527 int l = strlen(str);
2528 if(strchr(str, '%'))
2529 return parsePercent(str);
2530 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2531 float p = atof(str);
2532 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2534 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2538 float parsePercent(char*str)
2540 int l = strlen(str);
2544 return atoi(str)/100.0;
2546 syntaxerror("Expression '%s' is not a percentage", str);
2549 int isPercent(char*str)
2551 return str[strlen(str)-1]=='%';
2553 int parseNewSize(char*str, int size)
2556 return parsePercent(str)*size;
2558 return (int)(atof(str)*20);
2561 int isColor(char*str)
2564 return parseColor2(str, &c);
2567 static char* lu(map_t* args, char*name)
2569 char* value = map_lookup(args, name);
2571 map_dump(args, stdout, "");
2572 syntaxerror("internal error 2: value %s should be set", name);
2577 static int c_flash(map_t*args)
2579 char* filename = map_lookup(args, "filename");
2580 char* compressstr = lu(args, "compress");
2581 char* change_modestr = lu(args, "change-sets-all");
2582 SRECT bbox = parseBox(lu(args, "bbox"));
2583 int version = parseInt(lu(args, "version"));
2584 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2585 RGBA color = parseColor(lu(args, "background"));
2588 if(!filename || !*filename) {
2589 /* for compatibility */
2590 filename = map_lookup(args, "name");
2591 if(!filename || !*filename) {
2594 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2595 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2599 if(!filename || override_outputname)
2600 filename = outputname;
2602 if(!strcmp(compressstr, "default"))
2603 compress = version>=6;
2604 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2606 else if(!strcmp(compressstr, "no"))
2608 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2610 if(!strcmp(change_modestr, "yes"))
2611 change_sets_all = 1;
2613 if(strcmp(change_modestr, "no"))
2614 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2616 s_swf(filename, bbox, version, fps, compress, color);
2619 int isRelative(char*str)
2621 return !strncmp(str, "<plus>", 6) ||
2622 !strncmp(str, "<minus>", 7);
2624 char* getOffset(char*str)
2626 if(!strncmp(str, "<plus>", 6))
2628 if(!strncmp(str, "<minus>", 7))
2630 syntaxerror("internal error (347)");
2633 int getSign(char*str)
2635 if(!strncmp(str, "<plus>", 6))
2637 if(!strncmp(str, "<minus>", 7))
2639 syntaxerror("internal error (348)");
2642 static dictionary_t points;
2643 static mem_t mpoints;
2644 int points_initialized = 0;
2646 static int c_interpolation(map_t *args)
2649 char* name = lu(args, "name");
2650 if (dictionary_lookup(&interpolations, name))
2651 syntaxerror("interpolation %s defined twice", name);
2653 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2654 char* functionstr = lu(args, "function");
2655 inter->function = 0;
2656 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2657 if (!strcmp(functionstr,interpolationFunctions[i]))
2659 inter->function = i + 1;
2662 if (!inter->function)
2663 syntaxerror("unkown interpolation function %s", functionstr);
2664 inter->speed = parseFloat(lu(args, "speed"));
2665 inter->amplitude = parseTwip(lu(args, "amplitude"));
2666 inter->growth = parseFloat(lu(args, "growth"));
2667 inter->bounces = parseInt(lu(args, "bounces"));
2668 inter->damping = parseFloat(lu(args, "damping"));
2669 inter->slope = parseFloat(lu(args, "slope"));
2671 dictionary_put2(&interpolations, name, inter);
2675 SPOINT getPoint(SRECT r, char*name)
2678 if(!strcmp(name, "center")) {
2680 p.x = (r.xmin + r.xmax)/2;
2681 p.y = (r.ymin + r.ymax)/2;
2684 if (!strcmp(name, "bottom-center")) {
2686 p.x = (r.xmin + r.xmax)/2;
2690 if (!strcmp(name, "top-center")) {
2692 p.x = (r.xmin + r.xmax)/2;
2696 if (!strcmp(name, "top-left")) {
2702 if (!strcmp(name, "top-right")) {
2708 if (!strcmp(name, "bottom-right")) {
2714 if (!strcmp(name, "bottom-left")) {
2720 if (!strcmp(name, "left-center")) {
2723 p.y = (r.ymin + r.ymax)/2;
2726 if (!strcmp(name, "right-center")) {
2729 p.y = (r.ymin + r.ymax)/2;
2734 if(points_initialized)
2735 l = (int)dictionary_lookup(&points, name);
2737 syntaxerror("Invalid point: \"%s\".", name);
2740 return *(SPOINT*)&mpoints.buffer[l];
2744 static int texture2(char*name, char*object, map_t*args, int errors)
2747 char*xstr = map_lookup(args, "x");
2748 char*ystr = map_lookup(args, "y");
2749 char*widthstr = map_lookup(args, "width");
2750 char*heightstr = map_lookup(args, "height");
2751 char*scalestr = map_lookup(args, "scale");
2752 char*scalexstr = map_lookup(args, "scalex");
2753 char*scaleystr = map_lookup(args, "scaley");
2754 char*rotatestr = map_lookup(args, "rotate");
2755 char* shearstr = map_lookup(args, "shear");
2756 char* radiusstr = map_lookup(args, "r");
2758 float scalex = 1.0, scaley = 1.0;
2759 float rotate=0, shear=0;
2761 if(!*xstr && !*ystr) {
2763 syntaxerror("x and y must be set");
2766 if(*scalestr && (*scalexstr || *scaleystr)) {
2767 syntaxerror("scale and scalex/scaley can't both be set");
2770 if((*widthstr || *heightstr) && *radiusstr) {
2771 syntaxerror("width/height and radius can't both be set");
2774 widthstr = radiusstr;
2775 heightstr = radiusstr;
2777 if(!*xstr) xstr="0";
2778 if(!*ystr) ystr="0";
2779 if(!*rotatestr) rotatestr="0";
2780 if(!*shearstr) shearstr="0";
2783 scalex = scaley = parsePercent(scalestr);
2784 } else if(*scalexstr || *scaleystr) {
2785 if(scalexstr) scalex = parsePercent(scalexstr);
2786 if(scaleystr) scaley = parsePercent(scaleystr);
2787 } else if(*widthstr || *heightstr) {
2790 s_getBitmapSize(object, &width, &height);
2792 scalex = (float)parseTwip(widthstr)/(float)width;
2794 scaley = (float)parseTwip(heightstr)/(float)height;
2796 x = parseTwip(xstr);
2797 y = parseTwip(ystr);
2798 rotate = parseFloat(rotatestr);
2799 shear = parseFloat(shearstr);
2801 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2806 static int c_texture(map_t*args)
2808 char*name = lu(args, "instance");
2809 char*object = lu(args, "character");
2810 return texture2(name, object, args, 1);
2813 static int c_gradient(map_t*args)
2815 char*name = lu(args, "name");
2816 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2817 int rotate = parseInt(lu(args, "rotate"));
2821 syntaxerror("colon (:) expected");
2823 if(dictionary_lookup(&gradients, name))
2824 syntaxerror("gradient %s defined twice", name);
2826 s_gradient(name, text, radial, rotate);
2828 /* check whether we also have placement information,
2829 which would make this a positioned gradient.
2830 If there is placement information, texture2() will
2831 add a texture, which has priority over the gradient.
2833 texture2(name, name, args, 0);
2837 static char* checkFiltername(map_t* args)
2839 char* name = lu(args, "name");
2840 if (strchr(name, ','))
2841 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
2845 static int c_blur(map_t*args)
2847 char*name = checkFiltername(args);
2848 char*blurstr = lu(args, "blur");
2849 char*blurxstr = lu(args, "blurx");
2850 char*blurystr = lu(args, "blury");
2851 float blurx=1.0, blury=1.0;
2853 blurx = parseFloat(blurstr);
2854 blury = parseFloat(blurstr);
2857 blurx = parseFloat(blurxstr);
2859 blury = parseFloat(blurystr);
2860 int passes = parseInt(lu(args, "passes"));
2861 s_blur(name, blurx, blury, passes);
2865 static int c_gradientglow(map_t*args)
2867 char*name = checkFiltername(args);
2868 char*gradient = lu(args, "gradient");
2869 char*blurstr = lu(args, "blur");
2870 char*blurxstr = lu(args, "blurx");
2871 char*blurystr = lu(args, "blury");
2872 float blurx=1.0, blury=1.0;
2874 blurx = parseFloat(blurstr);
2875 blury = parseFloat(blurstr);
2878 blurx = parseFloat(blurxstr);
2880 blury = parseFloat(blurystr);
2882 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2883 float distance = parseFloat(lu(args, "distance"));
2884 float strength = parseFloat(lu(args, "strength"));
2885 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2886 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2887 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2888 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2889 int passes = parseInt(lu(args, "passes"));
2891 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2895 static int c_dropshadow(map_t*args)
2897 char*name = checkFiltername(args);
2898 RGBA color = parseColor(lu(args, "color"));
2899 char*blurstr = lu(args, "blur");
2900 char*blurxstr = lu(args, "blurx");
2901 char*blurystr = lu(args, "blury");
2902 float blurx=1.0, blury=1.0;
2904 blurx = parseFloat(blurstr);
2905 blury = parseFloat(blurstr);
2908 blurx = parseFloat(blurxstr);
2910 blury = parseFloat(blurystr);
2912 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2913 float distance = parseFloat(lu(args, "distance"));
2914 float strength = parseFloat(lu(args, "strength"));
2915 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2916 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2917 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2918 int passes = parseInt(lu(args, "passes"));
2920 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
2924 static int c_bevel(map_t*args)
2926 char*name = checkFiltername(args);
2927 RGBA shadow = parseColor(lu(args, "shadow"));
2928 RGBA highlight = parseColor(lu(args, "highlight"));
2929 char*blurstr = lu(args, "blur");
2930 char*blurxstr = lu(args, "blurx");
2931 char*blurystr = lu(args, "blury");
2932 float blurx=1.0, blury=1.0;
2934 blurx = parseFloat(blurstr);
2935 blury = parseFloat(blurstr);
2938 blurx = parseFloat(blurxstr);
2940 blury = parseFloat(blurystr);
2942 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2943 float distance = parseFloat(lu(args, "distance"));
2944 float strength = parseFloat(lu(args, "strength"));
2945 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2946 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2947 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2948 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2949 int passes = parseInt(lu(args, "passes"));
2951 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2955 static int c_point(map_t*args)
2957 char*name = lu(args, "name");
2961 if(!points_initialized) {
2962 dictionary_init(&points);
2964 points_initialized = 1;
2966 p.x = parseTwip(lu(args, "x"));
2967 p.y = parseTwip(lu(args, "y"));
2968 pos = mem_put(&mpoints, &p, sizeof(p));
2969 string_set(&s1, name);
2971 dictionary_put(&points, s1, (void*)pos);
2974 static int c_play(map_t*args)
2976 char*name = lu(args, "name");
2977 char*loop = lu(args, "loop");
2978 char*nomultiple = lu(args, "nomultiple");
2980 if(!strcmp(nomultiple, "nomultiple"))
2983 nm = parseInt(nomultiple);
2985 if(s_playsound(name, parseInt(loop), nm, 0)) {
2987 } else if(s_swf3action(name, "play")) {
2993 static int c_stop(map_t*args)
2995 char*name = map_lookup(args, "name");
2997 if(s_playsound(name, 0,0,1))
2999 else if(s_swf3action(name, "stop"))
3001 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
3005 static int c_nextframe(map_t*args)
3007 char*name = lu(args, "name");
3009 if(s_swf3action(name, "nextframe")) {
3012 syntaxerror("I don't know anything about movie \"%s\"", name);
3016 static int c_previousframe(map_t*args)
3018 char*name = lu(args, "name");
3020 if(s_swf3action(name, "previousframe")) {
3023 syntaxerror("I don't know anything about movie \"%s\"", name);
3027 static int c_movement(map_t*args, int type)
3029 char*instance = lu(args, "name");
3037 xstr = lu(args, "x");
3038 ystr = lu(args, "y");
3040 s_getParameters(instance, &p);
3045 if(isRelative(xstr))
3047 if(type == PT_PUT || type == PT_STARTCLIP)
3048 syntaxerror("relative x values not allowed for initial put or startclip");
3049 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3053 p.x = parseTwip(xstr);
3059 if(isRelative(ystr))
3061 if(type == PT_PUT || type == PT_STARTCLIP)
3062 syntaxerror("relative y values not allowed for initial put or startclip");
3063 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3067 p.y = parseTwip(ystr);
3072 if (change_sets_all)
3080 char* interstr = lu(args, "interpolation");
3081 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3083 syntaxerror("unkown interpolation %s", interstr);
3084 s_change(instance, p, inter);
3089 char* interstr = lu(args, "interpolation");
3090 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3092 syntaxerror("unkown interpolation %s", interstr);
3093 s_schange(instance, p, inter);
3098 char* rstr = lu(args, "r");
3099 int radius = parseTwip(rstr);
3101 syntaxerror("sweep not possible: radius must be greater than 0.");
3102 char* dirstr = lu(args, "dir");
3103 int clockwise = parseDir(dirstr);
3104 char* arcstr = lu(args, "arc");
3105 int short_arc = parseArc(arcstr);
3106 char* interstr = lu(args, "interpolation");
3107 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3109 syntaxerror("unkown interpolation %s", interstr);
3110 s_sweep(instance, p, radius, clockwise, short_arc, inter);
3117 static int c_placement(map_t*args, int type)
3119 char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3122 char* luminancestr = lu(args, "luminance");
3123 char* scalestr = lu(args, "scale");
3124 char* scalexstr = lu(args, "scalex");
3125 char* scaleystr = lu(args, "scaley");
3126 char* rotatestr = lu(args, "rotate");
3127 char* shearstr = lu(args, "shear");
3128 char* xstr="", *pivotstr="";
3129 char* ystr="", *anglestr="";
3130 char*above = lu(args, "above"); /*FIXME*/
3131 char*below = lu(args, "below");
3132 char* rstr = lu(args, "red");
3133 char* gstr = lu(args, "green");
3134 char* bstr = lu(args, "blue");
3135 char* astr = lu(args, "alpha");
3136 char* pinstr = lu(args, "pin");
3137 char* as = map_lookup(args, "as");
3138 char* blendmode = lu(args, "blend");
3139 char* filterstr = lu(args, "filter");
3150 { // (?) .rotate or .arcchange
3151 pivotstr = lu(args, "pivot");
3152 anglestr = lu(args, "angle");
3156 xstr = lu(args, "x");
3157 ystr = lu(args, "y");
3161 luminance = parseMulAdd(luminancestr);
3165 luminance.mul = 256;
3170 if(scalexstr[0]||scaleystr[0])
3171 syntaxerror("scalex/scaley and scale cannot both be set");
3172 scalexstr = scaleystr = scalestr;
3175 if(type == PT_PUT || type == PT_STARTCLIP) {
3177 character = lu(args, "character");
3178 parameters_clear(&p);
3179 } else if (type == PT_BUTTON) {
3180 character = lu(args, "name");
3181 parameters_clear(&p);
3184 s_getParameters(instance, &p);
3190 if(isRelative(xstr))
3192 if(type == PT_PUT || type == PT_STARTCLIP)
3193 syntaxerror("relative x values not allowed for initial put or startclip");
3194 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3198 p.x = parseTwip(xstr);
3204 if(isRelative(ystr))
3206 if(type == PT_PUT || type == PT_STARTCLIP)
3207 syntaxerror("relative y values not allowed for initial put or startclip");
3208 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3212 p.y = parseTwip(ystr);
3217 /* scale, scalex, scaley */
3219 oldbbox = s_getCharBBox(character);
3221 oldbbox = s_getInstanceBBox(instance);
3222 oldwidth = oldbbox.xmax - oldbbox.xmin;
3223 oldheight = oldbbox.ymax - oldbbox.ymin;
3230 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3231 set = set | SF_SCALEX;
3239 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3240 set = set | SF_SCALEY;
3246 if(isRelative(rotatestr))
3247 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3249 p.rotate = parseFloat(rotatestr);
3250 set = set | SF_ROTATE;
3256 if(isRelative(shearstr))
3257 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3259 p.shear = parseFloat(shearstr);
3260 set = set | SF_SHEAR;
3265 if(isPoint(pivotstr))
3266 p.pivot = parsePoint(pivotstr);
3268 p.pivot = getPoint(oldbbox, pivotstr);
3269 set = set | SF_PIVOT;
3275 p.pin = parsePoint(pinstr);
3277 p.pin = getPoint(oldbbox, pinstr);
3281 /* color transform */
3283 if(rstr[0] || luminancestr[0])
3287 r = parseMulAdd(rstr);
3290 r.add = p.cxform.r0;
3291 r.mul = p.cxform.r1;
3293 r = mergeMulAdd(r, luminance);
3294 p.cxform.r0 = r.mul;
3295 p.cxform.r1 = r.add;
3296 set = set | SF_CX_R;
3298 if(gstr[0] || luminancestr[0])
3302 g = parseMulAdd(gstr);
3305 g.add = p.cxform.g0;
3306 g.mul = p.cxform.g1;
3308 g = mergeMulAdd(g, luminance);
3309 p.cxform.g0 = g.mul;
3310 p.cxform.g1 = g.add;
3311 set = set | SF_CX_G;
3313 if(bstr[0] || luminancestr[0])
3317 b = parseMulAdd(bstr);
3320 b.add = p.cxform.b0;
3321 b.mul = p.cxform.b1;
3323 b = mergeMulAdd(b, luminance);
3324 p.cxform.b0 = b.mul;
3325 p.cxform.b1 = b.add;
3326 set = set | SF_CX_B;
3330 MULADD a = parseMulAdd(astr);
3331 p.cxform.a0 = a.mul;
3332 p.cxform.a1 = a.add;
3333 set = set | SF_CX_A;
3340 for(t = 0; blendModeNames[t]; t++)
3342 if(!strcmp(blendModeNames[t], blendmode))
3350 syntaxerror("unknown blend mode: '%s'", blendmode);
3352 p.blendmode = blend;
3353 set = set | SF_BLEND;
3358 p.filters = parseFilters(filterstr);
3359 set = set | SF_FILTER;
3362 if (type == PT_CHANGE && set & (SF_X | SF_Y))
3363 warning("As of version 0.8.2 using the .change command to modify an \
3364 object's position on the stage is considered deprecated. Future \
3365 versions may consider x and y parameters for the .change command \
3366 to be illegal; please use the .move command.");
3368 if (change_sets_all)
3375 s_put(instance, character, p);
3379 char* interstr = lu(args, "interpolation");
3380 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3382 syntaxerror("unkown interpolation %s", interstr);
3383 s_change(instance, p, inter);
3388 char* interstr = lu(args, "interpolation");
3389 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3391 syntaxerror("unkown interpolation %s", interstr);
3392 s_schange(instance, p, inter);
3396 s_jump(instance, p);
3399 s_startclip(instance, character, p);
3403 s_buttonput(character, as, p);
3405 s_buttonput(character, "shape", p);
3411 static int c_put(map_t*args)
3413 c_placement(args, PT_PUT);
3416 static int c_change(map_t*args)
3418 if (currentframe == 0)
3419 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3420 c_placement(args, PT_CHANGE);
3423 static int c_schange(map_t*args)
3425 c_placement(args, PT_SCHANGE);
3428 static int c_move(map_t* args)
3430 c_movement(args, PT_MOVE);
3433 static int c_smove(map_t* args)
3435 c_movement(args, PT_SMOVE);
3438 static int c_sweep(map_t* args)
3440 c_movement(args, PT_SWEEP);
3443 static int c_arcchange(map_t*args)
3445 c_placement(args, 0);
3448 static int c_jump(map_t*args)
3450 c_placement(args, PT_JUMP);
3453 static int c_startclip(map_t*args)
3455 c_placement(args, PT_STARTCLIP);
3458 static int c_show(map_t*args)
3460 c_placement(args, PT_BUTTON);
3463 static int c_toggle(map_t* args)
3465 char*instance = lu(args, "name");
3466 U16 flagsOn = 0x0000, flagsOff = 0xffff;
3467 char* alignstr = lu(args, "fixed_alignment");
3468 if (!strcmp(alignstr, "on"))
3469 flagsOn += IF_FIXED_ALIGNMENT;
3471 if (!strcmp(alignstr, "off"))
3472 flagsOff -= IF_FIXED_ALIGNMENT;
3474 syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3475 s_toggle(instance, flagsOn, flagsOff);
3478 static int c_del(map_t*args)
3480 char*instance = lu(args, "name");
3481 s_delinstance(instance);
3484 static int c_end(map_t*args)
3489 static int c_sprite(map_t*args)
3491 char* name = lu(args, "name");
3495 static int c_frame(map_t*args)
3497 char*framestr = lu(args, "n");
3498 char*cutstr = lu(args, "cut");
3500 char*name = lu(args, "name");
3501 char*anchor = lu(args, "anchor");
3504 if(!strcmp(anchor, "anchor") && !*name)
3509 if(strcmp(cutstr, "no"))
3511 if(isRelative(framestr)) {
3512 frame = s_getframe();
3513 if(getSign(framestr)<0)
3514 syntaxerror("relative frame expressions must be positive");
3515 frame += parseInt(getOffset(framestr));
3518 frame = parseInt(framestr);
3519 if(s_getframe() >= frame
3520 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3521 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3523 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3526 static int c_primitive(map_t*args)
3528 char*name = lu(args, "name");
3529 char*command = lu(args, "commandname");
3530 int width=0, height=0, r=0;
3531 int linewidth = parseTwip(lu(args, "line"));
3532 char*colorstr = lu(args, "color");
3533 RGBA color = parseColor(colorstr);
3534 char*fillstr = lu(args, "fill");
3541 if(!strcmp(command, "circle"))
3543 else if(!strcmp(command, "filled"))
3547 width = parseTwip(lu(args, "width"));
3548 height = parseTwip(lu(args, "height"));
3549 } else if (type==1) {
3550 r = parseTwip(lu(args, "r"));
3551 } else if (type==2) {
3552 outline = lu(args, "outline");
3555 if(!strcmp(fillstr, "fill"))
3557 if(!strcmp(fillstr, "none"))
3559 if(width<0 || height<0 || linewidth<0 || r<0)
3560 syntaxerror("values width, height, line, r must be positive");
3562 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3563 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3564 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3568 static int c_textshape(map_t*args)
3570 char*name = lu(args, "name");
3571 char*text = lu(args, "text");
3572 char*font = lu(args, "font");
3573 float size = parsePxOrPercent(font, lu(args, "size"));
3575 s_textshape(name, font, size, text);
3579 static int c_swf(map_t*args)
3581 char*name = lu(args, "name");
3582 char*filename = lu(args, "filename");
3583 char*command = lu(args, "commandname");
3584 if(!strcmp(command, "shape"))
3585 warning("Please use .swf instead of .shape");
3586 s_includeswf(name, filename);
3590 static int c_font(map_t*args)
3592 char*name = lu(args, "name");
3593 char*filename = lu(args, "filename");
3594 s_font(name, filename);
3598 static int c_sound(map_t*args)
3600 char*name = lu(args, "name");
3601 char*filename = lu(args, "filename");
3602 s_sound(name, filename);
3606 static int c_text(map_t*args)
3608 char*name = lu(args, "name");
3609 char*text = lu(args, "text");
3610 char*font = lu(args, "font");
3611 float size = parsePxOrPercent(font, lu(args, "size"));
3612 RGBA color = parseColor(lu(args, "color"));
3613 s_text(name, font, text, (int)(size*100), color);
3617 static int c_soundtrack(map_t*args)
3622 static int c_quicktime(map_t*args)
3624 char*name = lu(args, "name");
3625 char*url = lu(args, "url");
3626 s_quicktime(name, url);
3630 static int c_image(map_t*args)
3632 char*command = lu(args, "commandname");
3633 char*name = lu(args, "name");
3634 char*filename = lu(args, "filename");
3635 if(!strcmp(command,"jpeg")) {
3636 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3637 s_image(name, "jpeg", filename, quality);
3639 s_image(name, "png", filename, 0);
3644 static int c_outline(map_t*args)
3646 char*name = lu(args, "name");
3647 char*format = lu(args, "format");
3651 syntaxerror("colon (:) expected");
3653 s_outline(name, format, text);
3657 int fakechar(map_t*args)
3659 char*name = lu(args, "name");
3660 s_box(name, 0, 0, black, 20, 0);
3664 static int c_egon(map_t*args) {return fakechar(args);}
3665 static int c_button(map_t*args) {
3666 char*name = lu(args, "name");
3670 static int current_button_flags = 0;
3671 static int c_on_press(map_t*args)
3673 char*position = lu(args, "position");
3675 if(!strcmp(position, "inside")) {
3676 current_button_flags |= BC_OVERUP_OVERDOWN;
3677 } else if(!strcmp(position, "outside")) {
3678 //current_button_flags |= BC_IDLE_OUTDOWN;
3679 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3680 } else if(!strcmp(position, "anywhere")) {
3681 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3684 if(type == RAWDATA) {
3686 s_buttonaction(current_button_flags, action);
3687 current_button_flags = 0;
3693 static int c_on_release(map_t*args)
3695 char*position = lu(args, "position");
3697 if(!strcmp(position, "inside")) {
3698 current_button_flags |= BC_OVERDOWN_OVERUP;
3699 } else if(!strcmp(position, "outside")) {
3700 current_button_flags |= BC_OUTDOWN_IDLE;
3701 } else if(!strcmp(position, "anywhere")) {
3702 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3705 if(type == RAWDATA) {
3707 s_buttonaction(current_button_flags, action);
3708 current_button_flags = 0;
3714 static int c_on_move_in(map_t*args)
3716 char*position = lu(args, "state");
3718 if(!strcmp(position, "pressed")) {
3719 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3720 } else if(!strcmp(position, "not_pressed")) {
3721 current_button_flags |= BC_IDLE_OVERUP;
3722 } else if(!strcmp(position, "any")) {
3723 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3726 if(type == RAWDATA) {
3728 s_buttonaction(current_button_flags, action);
3729 current_button_flags = 0;
3735 static int c_on_move_out(map_t*args)
3737 char*position = lu(args, "state");
3739 if(!strcmp(position, "pressed")) {
3740 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3741 } else if(!strcmp(position, "not_pressed")) {
3742 current_button_flags |= BC_OVERUP_IDLE;
3743 } else if(!strcmp(position, "any")) {
3744 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3747 if(type == RAWDATA) {
3749 s_buttonaction(current_button_flags, action);
3750 current_button_flags = 0;
3756 static int c_on_key(map_t*args)
3758 char*key = lu(args, "key");
3760 if(strlen(key)==1) {
3763 current_button_flags |= 0x4000 + (key[0]*0x200);
3765 syntaxerror("invalid character: %c"+key[0]);
3770 <ctrl-x> = 0x200*(x-'a')
3774 syntaxerror("invalid key: %s",key);
3777 if(type == RAWDATA) {
3779 s_buttonaction(current_button_flags, action);
3780 current_button_flags = 0;
3787 static int c_edittext(map_t*args)
3789 //"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"},
3790 char*name = lu(args, "name");
3791 char*font = lu(args, "font");
3792 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3793 int width = parseTwip(lu(args, "width"));
3794 int height = parseTwip(lu(args, "height"));
3795 char*text = lu(args, "text");
3796 RGBA color = parseColor(lu(args, "color"));
3797 int maxlength = parseInt(lu(args, "maxlength"));
3798 char*variable = lu(args, "variable");
3799 char*passwordstr = lu(args, "password");
3800 char*wordwrapstr = lu(args, "wordwrap");
3801 char*multilinestr = lu(args, "multiline");
3802 char*htmlstr = lu(args, "html");
3803 char*noselectstr = lu(args, "noselect");
3804 char*readonlystr = lu(args, "readonly");
3805 char*borderstr = lu(args, "border");
3806 char*autosizestr = lu(args, "autosize");
3807 char*alignstr = lu(args, "align");
3811 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3812 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3813 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3814 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3815 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3816 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3817 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3818 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3819 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3820 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
3821 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
3822 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
3823 else syntaxerror("Unknown alignment: %s", alignstr);
3825 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
3829 static int c_morphshape(map_t*args) {return fakechar(args);}
3830 static int c_movie(map_t*args) {return fakechar(args);}
3832 static char* readfile(const char*filename)
3834 FILE*fi = fopen(filename, "rb");
3838 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
3839 fseek(fi, 0, SEEK_END);
3841 fseek(fi, 0, SEEK_SET);
3842 text = rfx_alloc(l+1);
3843 fread(text, l, 1, fi);
3849 static int c_action(map_t*args)
3851 char* filename = map_lookup(args, "filename");
3852 if(!filename ||!*filename) {
3854 if(type != RAWDATA) {
3855 syntaxerror("colon (:) expected");
3859 s_action(readfile(filename));
3865 static int c_initaction(map_t*args)
3867 char* character = lu(args, "name");
3868 char* filename = map_lookup(args, "filename");
3869 if(!filename ||!*filename) {
3871 if(type != RAWDATA) {
3872 syntaxerror("colon (:) expected");
3874 s_initaction(character, text);
3876 s_initaction(character, readfile(filename));
3884 command_func_t* func;
3887 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no"},
3888 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
3889 // "import" type stuff
3890 {"swf", c_swf, "name filename"},
3891 {"shape", c_swf, "name filename"},
3892 {"jpeg", c_image, "name filename quality=80%"},
3893 {"png", c_image, "name filename"},
3894 {"movie", c_movie, "name filename"},
3895 {"sound", c_sound, "name filename"},
3896 {"font", c_font, "name filename glyphs="},
3897 {"soundtrack", c_soundtrack, "filename"},
3898 {"quicktime", c_quicktime, "url"},
3900 // generators of primitives
3902 {"point", c_point, "name x=0 y=0"},
3903 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
3904 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
3905 {"outline", c_outline, "name format=simple"},
3906 {"textshape", c_textshape, "name font size=100% text"},
3909 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
3910 {"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"},
3911 {"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"},
3912 {"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"},
3914 // character generators
3915 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
3916 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
3917 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
3919 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
3920 {"text", c_text, "name text font size=100% color=white"},
3921 {"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="},
3922 {"morphshape", c_morphshape, "name start end"},
3923 {"button", c_button, "name"},
3924 {"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="},
3925 {"on_press", c_on_press, "position=inside"},
3926 {"on_release", c_on_release, "position=anywhere"},
3927 {"on_move_in", c_on_move_in, "state=not_pressed"},
3928 {"on_move_out", c_on_move_out, "state=not_pressed"},
3929 {"on_key", c_on_key, "key=any"},
3932 {"play", c_play, "name loop=0 @nomultiple=0"},
3933 {"stop", c_stop, "name= "},
3934 {"nextframe", c_nextframe, "name"},
3935 {"previousframe", c_previousframe, "name"},
3937 // object placement tags
3938 {"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="},
3939 {"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="},
3940 {"move", c_move, "name x= y= interpolation=linear"},
3941 {"smove", c_smove, "name x= y= interpolation=linear"},
3942 {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
3943 {"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"},
3944 //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3945 {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
3946 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3947 {"del", c_del, "name"},
3948 // virtual object placement
3949 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
3951 {"toggle", c_toggle, "name fixed_alignment="},
3953 // commands which start a block
3954 //startclip (see above)
3955 {"sprite", c_sprite, "name"},
3956 {"action", c_action, "filename="},
3957 {"initaction", c_initaction, "name filename="},
3963 static map_t parseArguments(char*command, char*pattern)
3979 string_set(&t1, "commandname");
3980 string_set(&t2, command);
3981 map_put(&result, t1, t2);
3983 if(!pattern || !*pattern)
3990 if(!strncmp("<i> ", x, 3)) {
3992 if(type == COMMAND || type == RAWDATA) {
3994 syntaxerror("character name expected");
3996 name[pos].str = "instance";
3998 value[pos].str = text;
3999 value[pos].len = strlen(text);
4003 if(type == ASSIGNMENT)
4006 name[pos].str = "character";
4008 value[pos].str = text;
4009 value[pos].len = strlen(text);
4017 isboolean[pos] = (x[0] =='@');
4030 name[pos].len = d-x;
4035 name[pos].len = e-x;
4036 value[pos].str = e+1;
4037 value[pos].len = d-e-1;
4045 /* for(t=0;t<len;t++) {
4046 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4047 isboolean[t]?"(boolean)":"");
4052 if(type == RAWDATA || type == COMMAND) {
4057 // first, search for boolean arguments
4058 for(pos=0;pos<len;pos++)
4060 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4062 if(type == ASSIGNMENT)
4064 value[pos].str = text;
4065 value[pos].len = strlen(text);
4066 /*printf("setting boolean parameter %s (to %s)\n",
4067 strdup_n(name[pos], namelen[pos]),
4068 strdup_n(value[pos], valuelen[pos]));*/
4073 // second, search for normal arguments
4075 for(pos=0;pos<len;pos++)
4077 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4078 (type != ASSIGNMENT && !set[pos])) {
4080 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4082 if(type == ASSIGNMENT)
4085 value[pos].str = text;
4086 value[pos].len = strlen(text);
4088 printf("setting parameter %s (to %s)\n",
4089 strdup_n(name[pos].str, name[pos].len),
4090 strdup_n(value[pos].str, value[pos].len));
4096 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4100 for(t=0;t<len;t++) {
4101 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4104 for(t=0;t<len;t++) {
4105 if(value[t].str && value[t].str[0] == '*') {
4106 //relative default- take value from some other parameter
4108 for(s=0;s<len;s++) {
4109 if(value[s].len == value[t].len-1 &&
4110 !strncmp(&value[t].str[1], value[s].str, value[s].len))
4111 value[t].str = value[s].str;
4114 if(value[t].str == 0) {
4116 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4120 /* ok, now construct the dictionary from the parameters */
4124 map_put(&result, name[t], value[t]);
4128 static void parseArgumentsForCommand(char*command)
4133 msg("<verbose> parse Command: %s (line %d)", command, line);
4135 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4136 if(!strcmp(arguments[t].command, command)) {
4138 /* ugly hack- will be removed soon (once documentation and .sc generating
4139 utilities have been changed) */
4140 if(!strcmp(command, "swf") && !stackpos) {
4141 warning("Please use .flash instead of .swf- this will be mandatory soon");
4146 args = parseArguments(command, arguments[t].arguments);
4152 syntaxerror("command %s not known", command);
4154 // catch missing .flash directives at the beginning of a file
4155 if(strcmp(command, "flash") && !stackpos)
4157 syntaxerror("No movie defined- use .flash first");
4161 printf(".%s\n", command);fflush(stdout);
4162 map_dump(&args, stdout, "\t");fflush(stdout);
4165 (*arguments[nr].func)(&args);
4167 /*if(!strcmp(command, "button") ||
4168 !strcmp(command, "action")) {
4171 if(type == COMMAND) {
4172 if(!strcmp(text, "end"))
4187 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4188 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4189 * No syntax checking is done */
4190 static void analyseArgumentsForCommand(char*command)
4196 msg("<verbose> analyse Command: %s (line %d)", command, line);
4198 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4200 if(!strcmp(arguments[t].command, command))
4202 args = parseArguments(command, arguments[t].arguments);
4208 printf(".%s\n", command);fflush(stdout);
4209 map_dump(&args, stdout, "\t");fflush(stdout);
4211 char* name = lu(&args, "name");
4212 if (!strcmp(command, "font"))
4214 if(dictionary_lookup(&fonts, name))
4215 syntaxerror("font %s defined twice", name);
4218 fontfile = lu(&args, "filename");
4219 font = swf_LoadFont(fontfile);
4221 warning("Couldn't open font file \"%s\"", fontfile);
4222 font = (SWFFONT*)malloc(sizeof(SWFFONT));
4223 memset(font, 0, sizeof(SWFFONT));
4225 swf_FontUseUTF8(font, lu(&args, "glyphs"));
4226 swf_FontPrepareForEditText(font);
4227 dictionary_put2(&fonts, name, font);
4231 SWFFONT* font = dictionary_lookup(&fonts, lu(&args, "font"));
4233 syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
4235 if (!strcmp(command, "edittext"))
4236 swf_FontUseAll(font);
4238 swf_FontUseUTF8(font, lu(&args, "text"));
4244 void skipParameters()
4248 while (type != COMMAND);
4252 void findFontUsage()
4254 char* fontRelated = "font;text;textshape;edittext;";
4255 while(!noMoreTokens())
4259 syntaxerror("command expected");
4260 if (strstr(fontRelated, text))
4261 analyseArgumentsForCommand(text);
4263 if(strcmp(text, "end"))
4272 dictionary_init(&fonts);
4273 cleanUp = &freeFontDictionary;
4277 int main (int argc,char ** argv)
4280 processargs(argc, argv);
4281 initLog(0,-1,0,0,-1,verbose);
4284 args_callback_usage(argv[0]);
4288 file = generateTokens(filename);
4290 fprintf(stderr, "parser returned error.\n");
4297 while(!noMoreTokens()) {
4300 syntaxerror("command expected");
4301 parseArgumentsForCommand(text);