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");}
1043 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
1057 if(stack[stackpos-1].type == 0)
1058 syntaxerror("End of file encountered in .flash block");
1059 if(stack[stackpos-1].type == 1)
1060 syntaxerror("End of file encountered in .sprite block");
1061 if(stack[stackpos-1].type == 2)
1062 syntaxerror("End of file encountered in .clip block");
1068 return currentframe+1;
1071 void s_frame(int nr, int cut, char*name, char anchor)
1077 syntaxerror("Illegal frame number");
1078 nr--; // internally, frame 1 is frame 0
1080 for(t=currentframe;t<nr;t++) {
1081 tag = swf_InsertTag(tag, ST_SHOWFRAME);
1082 if(t==nr-1 && name && *name) {
1083 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1084 swf_SetString(tag, name);
1086 swf_SetU8(tag, 1); //make this an anchor
1089 if(nr == 0 && currentframe == 0 && name && *name) {
1090 tag = swf_InsertTag(tag, ST_FRAMELABEL);
1091 swf_SetString(tag, name);
1093 swf_SetU8(tag, 1); //make this an anchor
1098 syntaxerror("Can't cut, frame empty");
1100 stack[stackpos].cut = tag;
1106 int parseColor2(char*str, RGBA*color);
1108 int addFillStyle(SHAPE*s, SRECT*r, char*name)
1112 gradient_t*gradient;
1114 if(name[0] == '#') {
1115 parseColor2(name, &color);
1116 return swf_ShapeAddSolidFillStyle(s, &color);
1117 } else if ((texture = dictionary_lookup(&textures, name))) {
1118 return swf_ShapeAddFillStyle2(s, &texture->fs);
1119 } else if((image = dictionary_lookup(&images, name))) {
1121 swf_GetMatrix(0, &m);
1122 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1123 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1126 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1127 } else if ((gradient = dictionary_lookup(&gradients, name))) {
1131 swf_GetMatrix(0, &rot);
1132 ccos = cos(-gradient->rotate*2*M_PI/360);
1133 csin = sin(-gradient->rotate*2*M_PI/360);
1134 rot.sx = ccos*65536;
1135 rot.r1 = -csin*65536;
1136 rot.r0 = csin*65536;
1137 rot.sy = ccos*65536;
1138 r2 = swf_TurnRect(*r, &rot);
1139 swf_GetMatrix(0, &m);
1140 m.sx = (r2.xmax - r2.xmin)*2*ccos;
1141 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1142 m.r0 = (r2.ymax - r2.ymin)*2*csin;
1143 m.sy = (r2.ymax - r2.ymin)*2*ccos;
1144 m.tx = r->xmin + (r->xmax - r->xmin)/2;
1145 m.ty = r->ymin + (r->ymax - r->ymin)/2;
1146 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1147 } else if (parseColor2(name, &color)) {
1148 return swf_ShapeAddSolidFillStyle(s, &color);
1150 syntaxerror("not a color/fillstyle: %s", name);
1155 RGBA black={r:0,g:0,b:0,a:0};
1156 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
1165 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1168 linewidth = linewidth>=20?linewidth-20:0;
1169 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1172 fs1 = addFillStyle(s, &r2, texture);
1175 r.xmin = r2.xmin-linewidth/2;
1176 r.ymin = r2.ymin-linewidth/2;
1177 r.xmax = r2.xmax+linewidth/2;
1178 r.ymax = r2.ymax+linewidth/2;
1179 swf_SetRect(tag,&r);
1180 swf_SetShapeHeader(tag,s);
1181 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1182 swf_ShapeSetLine(tag,s,width,0);
1183 swf_ShapeSetLine(tag,s,0,height);
1184 swf_ShapeSetLine(tag,s,-width,0);
1185 swf_ShapeSetLine(tag,s,0,-height);
1186 swf_ShapeSetEnd(tag);
1189 s_addcharacter(name, id, tag, r);
1193 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
1199 outline = dictionary_lookup(&outlines, outlinename);
1201 syntaxerror("outline %s not defined", outlinename);
1205 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1208 linewidth = linewidth>=20?linewidth-20:0;
1209 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1212 fs1 = addFillStyle(s, &r2, texture);
1215 rect.xmin = r2.xmin-linewidth/2;
1216 rect.ymin = r2.ymin-linewidth/2;
1217 rect.xmax = r2.xmax+linewidth/2;
1218 rect.ymax = r2.ymax+linewidth/2;
1220 swf_SetRect(tag,&rect);
1221 swf_SetShapeStyles(tag, s);
1222 swf_ShapeCountBits(s,0,0);
1223 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1224 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
1225 swf_SetShapeBits(tag, s);
1226 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1229 s_addcharacter(name, id, tag, rect);
1233 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
1238 r2.xmin = r2.ymin = 0;
1242 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1245 linewidth = linewidth>=20?linewidth-20:0;
1246 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1249 fs1 = addFillStyle(s, &r2, texture);
1251 rect.xmin = r2.xmin-linewidth/2;
1252 rect.ymin = r2.ymin-linewidth/2;
1253 rect.xmax = r2.xmax+linewidth/2;
1254 rect.ymax = r2.ymax+linewidth/2;
1256 swf_SetRect(tag,&rect);
1257 swf_SetShapeHeader(tag,s);
1258 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1259 swf_ShapeSetCircle(tag, s, r,r,r,r);
1260 swf_ShapeSetEnd(tag);
1263 s_addcharacter(name, id, tag, rect);
1267 void s_textshape(char*name, char*fontname, float size, char*_text)
1270 U8*text = (U8*)_text;
1274 font = dictionary_lookup(&fonts, fontname);
1276 syntaxerror("font \"%s\" not known!", fontname);
1278 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1279 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1280 s_box(name, 0, 0, black, 20, 0);
1283 g = font->ascii2glyph[text[0]];
1285 outline = malloc(sizeof(outline_t));
1286 memset(outline, 0, sizeof(outline_t));
1287 outline->shape = font->glyph[g].shape;
1288 outline->bbox = font->layout->bounds[g];
1292 swf_Shape11DrawerInit(&draw, 0);
1293 swf_DrawText(&draw, font, (int)(size*100), _text);
1295 outline->shape = swf_ShapeDrawerToShape(&draw);
1296 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1297 draw.dealloc(&draw);
1300 if(dictionary_lookup(&outlines, name))
1301 syntaxerror("outline %s defined twice", name);
1302 dictionary_put2(&outlines, name, outline);
1305 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
1310 font = dictionary_lookup(&fonts, fontname);
1312 syntaxerror("font \"%s\" not known!", fontname);
1314 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1315 swf_SetU16(tag, id);
1316 if(!font->numchars) {
1317 s_box(name, 0, 0, black, 20, 0);
1320 r = swf_SetDefineText(tag, font, &color, text, size);
1322 if(stack[0].swf->fileVersion >= 8) {
1323 tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1324 swf_SetU16(tag, id);
1325 swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1326 swf_SetU32(tag, 0);//thickness
1327 swf_SetU32(tag, 0);//sharpness
1328 swf_SetU8(tag, 0);//reserved
1331 s_addcharacter(name, id, tag, r);
1335 void s_quicktime(char*name, char*url)
1340 memset(&r, 0, sizeof(r));
1342 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1343 swf_SetU16(tag, id);
1344 swf_SetString(tag, url);
1346 s_addcharacter(name, id, tag, r);
1350 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)
1353 EditTextLayout layout;
1356 if(fontname && *fontname) {
1357 flags |= ET_USEOUTLINES;
1358 font = dictionary_lookup(&fonts, fontname);
1360 syntaxerror("font \"%s\" not known!", fontname);
1362 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1363 swf_SetU16(tag, id);
1364 layout.align = align;
1365 layout.leftmargin = 0;
1366 layout.rightmargin = 0;
1374 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
1376 s_addcharacter(name, id, tag, r);
1380 /* type: either "jpeg" or "png"
1382 void s_image(char*name, char*type, char*filename, int quality)
1384 /* an image is actually two folded: 1st bitmap, 2nd character.
1385 Both of them can be used separately */
1387 /* step 1: the bitmap */
1391 if(!strcmp(type,"jpeg")) {
1392 #ifndef HAVE_JPEGLIB
1393 warning("no jpeg support compiled in");
1394 s_box(name, 0, 0, black, 20, 0);
1397 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1398 swf_SetU16(tag, imageID);
1400 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1401 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1404 swf_GetJPEGSize(filename, &width, &height);
1411 s_addimage(name, id, tag, r);
1414 } else if(!strcmp(type,"png")) {
1416 swf_SetU16(tag, imageID);
1418 getPNG(filename, &width, &height, (unsigned char**)&data);
1421 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1424 /*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1425 tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1426 swf_SetU16(tag, imageID);
1427 swf_SetLosslessImage(tag, data, width, height);
1434 s_addimage(name, id, tag, r);
1437 warning("image type \"%s\" not supported yet!", type);
1438 s_box(name, 0, 0, black, 20, 0);
1442 /* step 2: the character */
1443 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1444 swf_SetU16(tag, id);
1445 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1447 s_addcharacter(name, id, tag, r);
1451 void s_getBitmapSize(char*name, int*width, int*height)
1453 character_t* image = dictionary_lookup(&images, name);
1454 gradient_t* gradient = dictionary_lookup(&gradients,name);
1456 *width = image->size.xmax;
1457 *height = image->size.ymax;
1461 /* internal SWF gradient size */
1462 if(gradient->radial) {
1471 syntaxerror("No such bitmap/gradient: %s", name);
1474 void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1476 if(dictionary_lookup(&textures, name))
1477 syntaxerror("texture %s defined twice", name);
1478 gradient_t* gradient = dictionary_lookup(&gradients, object);
1479 character_t* bitmap = dictionary_lookup(&images, object);
1480 texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1482 FILLSTYLE*fs = &texture->fs;
1484 memset(&p, 0, sizeof(parameters_t));
1487 fs->type = FILL_TILED;
1488 fs->id_bitmap = bitmap->id;
1489 } else if(gradient) {
1490 fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1491 fs->gradient = gradient->gradient;
1493 p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1494 makeMatrix(&fs->m, &p);
1495 if(gradient && !gradient->radial) {
1502 p2 = swf_TurnPoint(p1, &m);
1511 dictionary_put2(&textures, name, texture);
1514 void s_font(char*name, char*filename)
1517 font = dictionary_lookup(&fonts, name);
1520 /* fix the layout. Only needed for old fonts */
1522 for(t=0;t<font->numchars;t++) {
1523 font->glyph[t].advance = 0;
1526 swf_FontCreateLayout(font);
1529 swf_FontReduce_swfc(font);
1530 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1531 swf_FontSetDefine2(tag, font);
1532 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1534 swf_SetU16(tag, id);
1535 swf_SetString(tag, name);
1542 typedef struct _sound_t
1548 void s_sound(char*name, char*filename)
1550 struct WAV wav, wav2;
1554 unsigned numsamples = 1;
1555 unsigned blocksize = 1152;
1558 if(dictionary_lookup(&sounds, name))
1559 syntaxerror("sound %s defined twice", name);
1561 if(wav_read(&wav, filename))
1564 wav_convert2mono(&wav, &wav2, 44100);
1565 samples = (U16*)wav2.data;
1566 numsamples = wav2.size/2;
1568 #ifdef WORDS_BIGENDIAN
1570 for(t=0;t<numsamples;t++)
1571 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1575 if(mp3_read(&mp3, filename))
1577 fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1583 warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1588 if(numsamples%blocksize != 0)
1590 // apply padding, so that block is a multiple of blocksize
1591 int numblocks = (numsamples+blocksize-1)/blocksize;
1594 numsamples2 = numblocks * blocksize;
1595 samples2 = malloc(sizeof(U16)*numsamples2);
1596 memcpy(samples2, samples, numsamples*sizeof(U16));
1597 memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1598 numsamples = numsamples2;
1603 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1604 swf_SetU16(tag, id); //id
1607 swf_SetSoundDefineMP3(
1608 tag, mp3.data, mp3.size,
1615 swf_SetSoundDefine(tag, samples, numsamples);
1617 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1618 swf_SetU16(tag, id);
1619 swf_SetString(tag, name);
1620 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1622 swf_SetU16(tag, id);
1623 swf_SetString(tag, name);
1625 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1629 dictionary_put2(&sounds, name, sound);
1637 static char* gradient_getToken(const char**p)
1641 while(**p && strchr(" \t\n\r", **p)) {
1645 while(**p && !strchr(" \t\n\r", **p)) {
1648 result = malloc((*p)-start+1);
1649 memcpy(result,start,(*p)-start+1);
1650 result[(*p)-start] = 0;
1654 float parsePercent(char*str);
1655 RGBA parseColor(char*str);
1657 GRADIENT parseGradient(const char*str)
1661 const char* p = str;
1662 memset(&gradient, 0, sizeof(GRADIENT));
1663 gradient.ratios = rfx_calloc(16*sizeof(U8));
1664 gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1668 char*posstr,*colorstr;
1671 posstr = gradient_getToken(&p);
1677 pos = (int)(parsePercent(posstr)*255.0);
1682 rfx_free(gradient.ratios);
1683 rfx_free(gradient.rgba);
1685 syntaxerror("Error in shape data: Color expected after %s", posstr);
1687 colorstr = gradient_getToken(&p);
1688 color = parseColor(colorstr);
1689 if(gradient.num == 16)
1691 warning("gradient record too big- max size is 16, rest ignored");
1694 gradient.ratios[gradient.num] = pos;
1695 gradient.rgba[gradient.num] = color;
1704 FILTERLIST* parseFilters(char* list)
1706 if (!strcmp(list, "no_filters"))
1709 FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1711 char* f_start = list;
1715 f_end = strchr(f_start, ',');
1718 f = dictionary_lookup(&filters, f_start);
1722 syntaxerror("unknown filter %s", f_start);
1724 if (f_list->num == 8)
1726 warning("too many filters in filterlist, no more than 8 please, rest ignored");
1729 f_list->filter[f_list->num] = f;
1734 f_start = f_end + 1;
1742 void s_gradient(char*name, const char*text, int radial, int rotate)
1744 gradient_t* gradient;
1745 gradient = malloc(sizeof(gradient_t));
1746 memset(gradient, 0, sizeof(gradient_t));
1747 gradient->gradient = parseGradient(text);
1748 gradient->radial = radial;
1749 gradient->rotate = rotate;
1751 dictionary_put2(&gradients, name, gradient);
1754 void s_gradientglow(char*name, char*gradient, float blurx, float blury,
1755 float angle, float distance, float strength, char innershadow,
1756 char knockout, char composite, char ontop, int passes)
1758 if(dictionary_lookup(&filters, name))
1759 syntaxerror("filter %s defined twice", name);
1761 gradient_t* g = dictionary_lookup(&gradients, gradient);
1763 syntaxerror("unknown gradient %s", gradient);
1767 FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1768 filter->type = FILTERTYPE_GRADIENTGLOW;
1769 filter->gradient = &g->gradient;
1770 filter->blurx = blurx;
1771 filter->blury = blury;
1772 filter->strength = strength;
1773 filter->angle = angle;
1774 filter->distance = distance;
1775 filter->innershadow = innershadow;
1776 filter->knockout = knockout;
1777 filter->composite = composite;
1778 filter->ontop = ontop;
1779 filter->passes = passes;
1781 dictionary_put2(&filters, name, filter);
1784 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)
1786 if(dictionary_lookup(&filters, name))
1787 syntaxerror("filter %s defined twice", name);
1790 FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1791 filter->type = FILTERTYPE_DROPSHADOW;
1792 filter->color= color;
1793 filter->blurx = blurx;
1794 filter->blury = blury;
1795 filter->strength = strength;
1796 filter->angle = angle;
1797 filter->distance = distance;
1798 filter->innershadow = innershadow;
1799 filter->knockout = knockout;
1800 filter->composite = composite;
1801 filter->passes = passes;
1803 dictionary_put2(&filters, name, filter);
1806 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)
1808 if(dictionary_lookup(&filters, name))
1809 syntaxerror("filter %s defined twice", name);
1812 FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1813 filter->type = FILTERTYPE_BEVEL;
1814 filter->shadow = shadow;
1815 filter->highlight = highlight;
1816 filter->blurx = blurx;
1817 filter->blury = blury;
1818 filter->strength = strength;
1819 filter->angle = angle;
1820 filter->distance = distance;
1821 filter->innershadow = innershadow;
1822 filter->knockout = knockout;
1823 filter->composite = composite;
1824 filter->ontop = ontop;
1825 filter->passes = passes;
1827 dictionary_put2(&filters, name, filter);
1830 void s_blur(char*name, double blurx, double blury, int passes)
1832 if(dictionary_lookup(&filters, name))
1833 syntaxerror("filter %s defined twice", name);
1835 FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1836 filter->type = FILTERTYPE_BLUR;
1837 filter->blurx = blurx;
1838 filter->blury = blury;
1839 filter->passes = passes;
1841 dictionary_put2(&filters, name, filter);
1844 void s_action(const char*text)
1847 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1851 syntaxerror("Couldn't compile ActionScript");
1854 tag = swf_InsertTag(tag, ST_DOACTION);
1856 swf_ActionSet(tag, a);
1861 void s_initaction(const char*character, const char*text)
1865 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1869 syntaxerror("Couldn't compile ActionScript");
1872 c = (character_t*)dictionary_lookup(&characters, character);
1874 tag = swf_InsertTag(tag, ST_DOINITACTION);
1875 swf_SetU16(tag, c->id);
1876 swf_ActionSet(tag, a);
1881 int s_swf3action(char*name, char*action)
1884 instance_t* object = 0;
1886 object = (instance_t*)dictionary_lookup(&instances, name);
1887 if(!object && name && *name) {
1888 /* we have a name, but couldn't find it. Abort. */
1891 a = action_SetTarget(0, name);
1892 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1893 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1894 else if(!strcmp(action, "stop")) a = action_Stop(a);
1895 else if(!strcmp(action, "play")) a = action_Play(a);
1896 a = action_SetTarget(a, "");
1899 tag = swf_InsertTag(tag, ST_DOACTION);
1900 swf_ActionSet(tag, a);
1905 void s_outline(char*name, char*format, char*source)
1907 if(dictionary_lookup(&outlines, name))
1908 syntaxerror("outline %s defined twice", name);
1917 //swf_Shape10DrawerInit(&draw, 0);
1918 swf_Shape11DrawerInit(&draw, 0);
1920 draw_string(&draw, source);
1922 shape = swf_ShapeDrawerToShape(&draw);
1923 bounds = swf_ShapeDrawerGetBBox(&draw);
1924 draw.dealloc(&draw);
1926 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1927 outline->shape = shape;
1928 outline->bbox = bounds;
1930 dictionary_put2(&outlines, name, outline);
1933 int s_playsound(char*name, int loops, int nomultiple, int stop)
1939 sound = dictionary_lookup(&sounds, name);
1943 tag = swf_InsertTag(tag, ST_STARTSOUND);
1944 swf_SetU16(tag, sound->id); //id
1945 memset(&info, 0, sizeof(info));
1948 info.nomultiple = nomultiple;
1949 swf_SetSoundInfo(tag, &info);
1953 void s_includeswf(char*name, char*filename)
1961 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1962 f = open(filename,O_RDONLY|O_BINARY);
1964 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1965 s_box(name, 0, 0, black, 20, 0);
1968 if (swf_ReadSWF(f,&swf)<0) {
1969 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1970 s_box(name, 0, 0, black, 20, 0);
1975 /* FIXME: The following sets the bounding Box for the character.
1976 It is wrong for two reasons:
1977 a) It may be too small (in case objects in the movie clip at the borders)
1978 b) it may be too big (because the poor movie never got autocropped)
1982 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1983 swf_SetU16(tag, id);
1984 swf_SetU16(tag, swf.frameCount);
1986 swf_Relocate(&swf, idmap);
1988 ftag = swf.firstTag;
1992 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1993 if(cutout[t] == ftag->id) {
1997 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1999 if(ftag->id == ST_END)
2004 if(ftag->id != ST_SETBACKGROUNDCOLOR) {
2005 /* We simply dump all tags right after the sprite
2006 header, relying on the fact that swf_OptimizeTagOrder() will
2007 sort things out for us later.
2008 We also rely on the fact that the imported SWF is well-formed.
2010 tag = swf_InsertTag(tag, ftag->id);
2011 swf_SetBlock(tag, ftag->data, ftag->len);
2017 syntaxerror("Included file %s contains errors", filename);
2018 tag = swf_InsertTag(tag, ST_END);
2022 s_addcharacter(name, id, tag, r);
2025 SRECT s_getCharBBox(char*name)
2027 character_t* c = dictionary_lookup(&characters, name);
2028 if(!c) syntaxerror("character '%s' unknown(2)", name);
2031 SRECT s_getInstanceBBox(char*name)
2033 instance_t * i = dictionary_lookup(&instances, name);
2035 if(!i) syntaxerror("instance '%s' unknown(4)", name);
2037 if(!c) syntaxerror("internal error(5)");
2040 void s_getParameters(char*name, parameters_t* p)
2042 instance_t * i = dictionary_lookup(&instances, name);
2044 syntaxerror("instance '%s' unknown(10)", name);
2045 if (change_sets_all)
2046 readParameters(i->history, p, currentframe);
2050 void s_startclip(char*instance, char*character, parameters_t p)
2052 character_t* c = dictionary_lookup(&characters, character);
2056 syntaxerror("character %s not known", character);
2058 i = s_addinstance(instance, c, currentdepth);
2060 m = s_instancepos(i->character->size, &p);
2062 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2063 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2064 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2066 stack[stackpos].tag = tag;
2067 stack[stackpos].type = 2;
2076 swf_SetTagPos(stack[stackpos].tag, 0);
2077 swf_GetPlaceObject(stack[stackpos].tag, &p);
2078 p.clipdepth = currentdepth;
2080 swf_ClearTag(stack[stackpos].tag);
2081 swf_SetPlaceObject(stack[stackpos].tag, &p);
2085 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2087 history_begin(i->history, "x", currentframe, tag, p->x);
2088 history_begin(i->history, "y", currentframe, tag, p->y);
2089 history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2090 history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2091 history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2092 history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2093 history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2094 history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2095 history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2096 history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2097 history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2098 history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2099 history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2100 history_begin(i->history, "shear", currentframe, tag, p->shear);
2101 history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2102 history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2103 history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2104 history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2105 history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2106 history_beginFilter(i->history, currentframe, tag, p->filters);
2107 history_begin(i->history, "flags", currentframe, tag, 0);
2110 void s_put(char*instance, char*character, parameters_t p)
2112 character_t* c = dictionary_lookup(&characters, character);
2116 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2118 i = s_addinstance(instance, c, currentdepth);
2120 m = s_instancepos(i->character->size, &p);
2122 if(p.blendmode || p.filters)
2124 if(stack[0].swf->fileVersion < 8)
2127 warning("blendmodes only supported for flash version>=8");
2129 warning("filters only supported for flash version>=8");
2131 tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2134 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2135 setPlacement(tag, c->id, currentdepth, m, instance, &p, 0);
2136 setStartparameters(i, &p, tag);
2140 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2143 history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2145 history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2146 if (p.set & SF_SCALEX)
2147 history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2148 if (p.set & SF_SCALEY)
2149 history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2150 if (p.set & SF_CX_R)
2152 history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2153 history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2155 if (p.set & SF_CX_G)
2157 history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2158 history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2160 if (p.set & SF_CX_B)
2162 history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2163 history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2165 if (p.set & SF_CX_A)
2167 history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2168 history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2170 if (p.set & SF_ROTATE)
2171 history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2172 if (p.set & SF_SHEAR)
2173 history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2174 if (p.set & SF_PIVOT)
2176 history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2177 history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2181 history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2182 history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2184 if (p.set & SF_BLEND)
2185 history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2186 if (p.set & SF_FILTER)
2187 history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2190 void s_jump(char* instance, parameters_t p)
2192 instance_t* i = dictionary_lookup(&instances, instance);
2194 syntaxerror("instance %s not known", instance);
2195 recordChanges(i->history, p, CF_JUMP, 0);
2198 void s_change(char*instance, parameters_t p, interpolation_t* inter)
2200 instance_t* i = dictionary_lookup(&instances, instance);
2202 syntaxerror("instance %s not known", instance);
2203 recordChanges(i->history, p, CF_CHANGE, inter);
2206 void s_sweep(char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
2208 instance_t* i = dictionary_lookup(&instances, instance);
2210 syntaxerror("instance %s not known", instance);
2211 history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
2214 void s_toggle(char* instance, U16 flagsOn, U16 flagsOff)
2216 instance_t* i = dictionary_lookup(&instances, instance);
2218 syntaxerror("instance %s not known", instance);
2219 U16 flags = (U16)history_value(i->history, currentframe, "flags");
2222 history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
2225 void s_delinstance(char*instance)
2227 instance_t* i = dictionary_lookup(&instances, instance);
2229 syntaxerror("instance %s not known", instance);
2231 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2232 swf_SetU16(tag, i->depth);
2233 dictionary_del(&instances, instance);
2236 void s_schange(char*instance, parameters_t p, interpolation_t* inter)
2238 instance_t* i = dictionary_lookup(&instances, instance);
2240 syntaxerror("instance %s not known", instance);
2241 recordChanges(i->history, p, CF_SCHANGE, inter);
2247 syntaxerror(".end unexpected");
2248 switch (stack[stackpos-1].type)
2263 syntaxerror("internal error 1");
2267 // ------------------------------------------------------------------------
2269 typedef int command_func_t(map_t*args);
2271 SRECT parseBox(char*str)
2273 SRECT r = {0,0,0,0};
2274 float xmin, xmax, ymin, ymax;
2275 char*x = strchr(str, 'x');
2277 if(!strcmp(str, "autocrop")) {
2278 r.xmin = r.ymin = r.xmax = r.ymax = 0;
2282 d1 = strchr(x+1, ':');
2284 d2 = strchr(d1+1, ':');
2286 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2290 else if(d1 && !d2) {
2291 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2297 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2302 r.xmin = (SCOORD)(xmin*20);
2303 r.ymin = (SCOORD)(ymin*20);
2304 r.xmax = (SCOORD)(xmax*20);
2305 r.ymax = (SCOORD)(ymax*20);
2308 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2311 float parseFloat(char*str)
2315 int parseInt(char*str)
2320 if(str[0]=='+' || str[0]=='-')
2324 if(str[t]<'0' || str[t]>'9')
2325 syntaxerror("Not an Integer: \"%s\"", str);
2328 int parseTwip(char*str)
2332 if(str[0]=='+' || str[0]=='-') {
2337 dot = strchr(str, '.');
2341 return sign*parseInt(str)*20;
2343 char* old = strdup(str);
2344 int l=strlen(dot+1);
2347 for(s=str;s<dot-1;s++)
2348 if(*s<'0' || *s>'9')
2351 syntaxerror("Not a coordinate: \"%s\"", str);
2354 if(*s<'0' || *s>'9')
2357 syntaxerror("Not a coordinate: \"%s\"", str);
2359 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2360 dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2363 warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2367 return sign*atoi(str)*20;
2369 return sign*atoi(str)*20+atoi(dot)*2;
2371 return sign*atoi(str)*20+atoi(dot)/5;
2376 int parseArc(char* str)
2378 if (!strcmp(str, "short"))
2380 if (!strcmp(str, "long"))
2382 syntaxerror("invalid value for the arc parameter: %s", str);
2386 int parseDir(char* str)
2388 if (!strcmp(str, "clockwise"))
2390 if (!strcmp(str, "counterclockwise"))
2392 syntaxerror("invalid value for the dir parameter: %s", str);
2396 int isPoint(char*str)
2398 if(strchr(str, '('))
2404 SPOINT parsePoint(char*str)
2408 int l = strlen(str);
2409 char*comma = strchr(str, ',');
2410 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2411 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2412 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2413 p.x = parseTwip(tmp);
2414 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2415 p.y = parseTwip(tmp);
2419 int parseColor2(char*str, RGBA*color)
2421 int l = strlen(str);
2425 struct {unsigned char r,g,b;char*name;} colors[] =
2426 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2427 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2428 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2429 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2430 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2431 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2432 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2433 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2434 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2435 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2436 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2437 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2441 if(str[0]=='#' && (l==7 || l==9)) {
2442 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2444 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2446 color->r = r; color->g = g; color->b = b; color->a = a;
2449 int len=strlen(str);
2451 if(strchr(str, '/')) {
2452 len = strchr(str, '/')-str;
2453 sscanf(str+len+1,"%02x", &alpha);
2455 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2456 if(!strncmp(str, colors[t].name, len)) {
2461 color->r = r; color->g = g; color->b = b; color->a = a;
2467 RGBA parseColor(char*str)
2470 if(!parseColor2(str, &c))
2471 syntaxerror("Expression '%s' is not a color", str);
2475 typedef struct _muladd {
2480 MULADD parseMulAdd(char*str)
2483 char* str2 = (char*)malloc(strlen(str)+5);
2490 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2491 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2492 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2493 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2494 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2495 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2496 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2497 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2498 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2499 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2501 syntaxerror("'%s' is not a valid color transform expression", str);
2503 m.add = (int)(add*256);
2504 m.mul = (int)(mul*256);
2509 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2511 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2512 double m = ((double)m1.mul*(double)m2.mul)/256.0;
2514 if(a<-32768) a=-32768;
2515 if(a>32767) a=32767;
2516 if(m<-32768) m=-32768;
2517 if(m>32767) m=32767;
2523 float parsePxOrPercent(char*fontname, char*str)
2525 int l = strlen(str);
2526 if(strchr(str, '%'))
2527 return parsePercent(str);
2528 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2529 float p = atof(str);
2530 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2532 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2536 float parsePercent(char*str)
2538 int l = strlen(str);
2542 return atoi(str)/100.0;
2544 syntaxerror("Expression '%s' is not a percentage", str);
2547 int isPercent(char*str)
2549 return str[strlen(str)-1]=='%';
2551 int parseNewSize(char*str, int size)
2554 return parsePercent(str)*size;
2556 return (int)(atof(str)*20);
2559 int isColor(char*str)
2562 return parseColor2(str, &c);
2565 static char* lu(map_t* args, char*name)
2567 char* value = map_lookup(args, name);
2569 map_dump(args, stdout, "");
2570 syntaxerror("internal error 2: value %s should be set", name);
2575 static int c_flash(map_t*args)
2577 char* filename = map_lookup(args, "filename");
2578 char* compressstr = lu(args, "compress");
2579 char* change_modestr = lu(args, "change-sets-all");
2580 SRECT bbox = parseBox(lu(args, "bbox"));
2581 int version = parseInt(lu(args, "version"));
2582 int fps = (int)(parseFloat(lu(args, "fps"))*256);
2583 RGBA color = parseColor(lu(args, "background"));
2586 if(!filename || !*filename) {
2587 /* for compatibility */
2588 filename = map_lookup(args, "name");
2589 if(!filename || !*filename) {
2592 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2593 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2597 if(!filename || override_outputname)
2598 filename = outputname;
2600 if(!strcmp(compressstr, "default"))
2601 compress = version>=6;
2602 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2604 else if(!strcmp(compressstr, "no"))
2606 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2608 if(!strcmp(change_modestr, "yes"))
2609 change_sets_all = 1;
2611 if(strcmp(change_modestr, "no"))
2612 syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2614 s_swf(filename, bbox, version, fps, compress, color);
2617 int isRelative(char*str)
2619 return !strncmp(str, "<plus>", 6) ||
2620 !strncmp(str, "<minus>", 7);
2622 char* getOffset(char*str)
2624 if(!strncmp(str, "<plus>", 6))
2626 if(!strncmp(str, "<minus>", 7))
2628 syntaxerror("internal error (347)");
2631 int getSign(char*str)
2633 if(!strncmp(str, "<plus>", 6))
2635 if(!strncmp(str, "<minus>", 7))
2637 syntaxerror("internal error (348)");
2640 static dictionary_t points;
2641 static mem_t mpoints;
2642 int points_initialized = 0;
2644 static int c_interpolation(map_t *args)
2647 char* name = lu(args, "name");
2648 if (dictionary_lookup(&interpolations, name))
2649 syntaxerror("interpolation %s defined twice", name);
2651 interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2652 char* functionstr = lu(args, "function");
2653 inter->function = 0;
2654 for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2655 if (!strcmp(functionstr,interpolationFunctions[i]))
2657 inter->function = i + 1;
2660 if (!inter->function)
2661 syntaxerror("unkown interpolation function %s", functionstr);
2662 inter->speed = parseFloat(lu(args, "speed"));
2663 inter->amplitude = parseTwip(lu(args, "amplitude"));
2664 inter->growth = parseFloat(lu(args, "growth"));
2665 inter->bounces = parseInt(lu(args, "bounces"));
2666 inter->damping = parseFloat(lu(args, "damping"));
2667 inter->slope = parseFloat(lu(args, "slope"));
2669 dictionary_put2(&interpolations, name, inter);
2673 SPOINT getPoint(SRECT r, char*name)
2676 if(!strcmp(name, "center")) {
2678 p.x = (r.xmin + r.xmax)/2;
2679 p.y = (r.ymin + r.ymax)/2;
2682 if (!strcmp(name, "bottom-center")) {
2684 p.x = (r.xmin + r.xmax)/2;
2688 if (!strcmp(name, "top-center")) {
2690 p.x = (r.xmin + r.xmax)/2;
2694 if (!strcmp(name, "top-left")) {
2700 if (!strcmp(name, "top-right")) {
2706 if (!strcmp(name, "bottom-right")) {
2712 if (!strcmp(name, "bottom-left")) {
2718 if (!strcmp(name, "left-center")) {
2721 p.y = (r.ymin + r.ymax)/2;
2724 if (!strcmp(name, "right-center")) {
2727 p.y = (r.ymin + r.ymax)/2;
2732 if(points_initialized)
2733 l = (int)dictionary_lookup(&points, name);
2735 syntaxerror("Invalid point: \"%s\".", name);
2738 return *(SPOINT*)&mpoints.buffer[l];
2742 static int texture2(char*name, char*object, map_t*args, int errors)
2745 char*xstr = map_lookup(args, "x");
2746 char*ystr = map_lookup(args, "y");
2747 char*widthstr = map_lookup(args, "width");
2748 char*heightstr = map_lookup(args, "height");
2749 char*scalestr = map_lookup(args, "scale");
2750 char*scalexstr = map_lookup(args, "scalex");
2751 char*scaleystr = map_lookup(args, "scaley");
2752 char*rotatestr = map_lookup(args, "rotate");
2753 char* shearstr = map_lookup(args, "shear");
2754 char* radiusstr = map_lookup(args, "r");
2756 float scalex = 1.0, scaley = 1.0;
2757 float rotate=0, shear=0;
2759 if(!*xstr && !*ystr) {
2761 syntaxerror("x and y must be set");
2764 if(*scalestr && (*scalexstr || *scaleystr)) {
2765 syntaxerror("scale and scalex/scaley can't both be set");
2768 if((*widthstr || *heightstr) && *radiusstr) {
2769 syntaxerror("width/height and radius can't both be set");
2772 widthstr = radiusstr;
2773 heightstr = radiusstr;
2775 if(!*xstr) xstr="0";
2776 if(!*ystr) ystr="0";
2777 if(!*rotatestr) rotatestr="0";
2778 if(!*shearstr) shearstr="0";
2781 scalex = scaley = parsePercent(scalestr);
2782 } else if(*scalexstr || *scaleystr) {
2783 if(scalexstr) scalex = parsePercent(scalexstr);
2784 if(scaleystr) scaley = parsePercent(scaleystr);
2785 } else if(*widthstr || *heightstr) {
2788 s_getBitmapSize(object, &width, &height);
2790 scalex = (float)parseTwip(widthstr)/(float)width;
2792 scaley = (float)parseTwip(heightstr)/(float)height;
2794 x = parseTwip(xstr);
2795 y = parseTwip(ystr);
2796 rotate = parseFloat(rotatestr);
2797 shear = parseFloat(shearstr);
2799 s_texture(name, object, x,y,scalex,scaley,rotate, shear);
2804 static int c_texture(map_t*args)
2806 char*name = lu(args, "instance");
2807 char*object = lu(args, "character");
2808 return texture2(name, object, args, 1);
2811 static int c_gradient(map_t*args)
2813 char*name = lu(args, "name");
2814 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
2815 int rotate = parseInt(lu(args, "rotate"));
2819 syntaxerror("colon (:) expected");
2821 if(dictionary_lookup(&gradients, name))
2822 syntaxerror("gradient %s defined twice", name);
2824 s_gradient(name, text, radial, rotate);
2826 /* check whether we also have placement information,
2827 which would make this a positioned gradient.
2828 If there is placement information, texture2() will
2829 add a texture, which has priority over the gradient.
2831 texture2(name, name, args, 0);
2835 static char* checkFiltername(map_t* args)
2837 char* name = lu(args, "name");
2838 if (strchr(name, ','))
2839 syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
2843 static int c_blur(map_t*args)
2845 char*name = checkFiltername(args);
2846 char*blurstr = lu(args, "blur");
2847 char*blurxstr = lu(args, "blurx");
2848 char*blurystr = lu(args, "blury");
2849 float blurx=1.0, blury=1.0;
2851 blurx = parseFloat(blurstr);
2852 blury = parseFloat(blurstr);
2855 blurx = parseFloat(blurxstr);
2857 blury = parseFloat(blurystr);
2858 int passes = parseInt(lu(args, "passes"));
2859 s_blur(name, blurx, blury, passes);
2863 static int c_gradientglow(map_t*args)
2865 char*name = checkFiltername(args);
2866 char*gradient = lu(args, "gradient");
2867 char*blurstr = lu(args, "blur");
2868 char*blurxstr = lu(args, "blurx");
2869 char*blurystr = lu(args, "blury");
2870 float blurx=1.0, blury=1.0;
2872 blurx = parseFloat(blurstr);
2873 blury = parseFloat(blurstr);
2876 blurx = parseFloat(blurxstr);
2878 blury = parseFloat(blurystr);
2880 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2881 float distance = parseFloat(lu(args, "distance"));
2882 float strength = parseFloat(lu(args, "strength"));
2883 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2884 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2885 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2886 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2887 int passes = parseInt(lu(args, "passes"));
2889 s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2893 static int c_dropshadow(map_t*args)
2895 char*name = checkFiltername(args);
2896 RGBA color = parseColor(lu(args, "color"));
2897 char*blurstr = lu(args, "blur");
2898 char*blurxstr = lu(args, "blurx");
2899 char*blurystr = lu(args, "blury");
2900 float blurx=1.0, blury=1.0;
2902 blurx = parseFloat(blurstr);
2903 blury = parseFloat(blurstr);
2906 blurx = parseFloat(blurxstr);
2908 blury = parseFloat(blurystr);
2910 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2911 float distance = parseFloat(lu(args, "distance"));
2912 float strength = parseFloat(lu(args, "strength"));
2913 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2914 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2915 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2916 int passes = parseInt(lu(args, "passes"));
2918 s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
2922 static int c_bevel(map_t*args)
2924 char*name = checkFiltername(args);
2925 RGBA shadow = parseColor(lu(args, "shadow"));
2926 RGBA highlight = parseColor(lu(args, "highlight"));
2927 char*blurstr = lu(args, "blur");
2928 char*blurxstr = lu(args, "blurx");
2929 char*blurystr = lu(args, "blury");
2930 float blurx=1.0, blury=1.0;
2932 blurx = parseFloat(blurstr);
2933 blury = parseFloat(blurstr);
2936 blurx = parseFloat(blurxstr);
2938 blury = parseFloat(blurystr);
2940 float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
2941 float distance = parseFloat(lu(args, "distance"));
2942 float strength = parseFloat(lu(args, "strength"));
2943 char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
2944 char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
2945 char composite = strcmp(lu(args, "composite"),"composite")?0:1;
2946 char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
2947 int passes = parseInt(lu(args, "passes"));
2949 s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
2953 static int c_point(map_t*args)
2955 char*name = lu(args, "name");
2959 if(!points_initialized) {
2960 dictionary_init(&points);
2962 points_initialized = 1;
2964 p.x = parseTwip(lu(args, "x"));
2965 p.y = parseTwip(lu(args, "y"));
2966 pos = mem_put(&mpoints, &p, sizeof(p));
2967 string_set(&s1, name);
2969 dictionary_put(&points, s1, (void*)pos);
2972 static int c_play(map_t*args)
2974 char*name = lu(args, "name");
2975 char*loop = lu(args, "loop");
2976 char*nomultiple = lu(args, "nomultiple");
2978 if(!strcmp(nomultiple, "nomultiple"))
2981 nm = parseInt(nomultiple);
2983 if(s_playsound(name, parseInt(loop), nm, 0)) {
2985 } else if(s_swf3action(name, "play")) {
2991 static int c_stop(map_t*args)
2993 char*name = map_lookup(args, "name");
2995 if(s_playsound(name, 0,0,1))
2997 else if(s_swf3action(name, "stop"))
2999 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
3003 static int c_nextframe(map_t*args)
3005 char*name = lu(args, "name");
3007 if(s_swf3action(name, "nextframe")) {
3010 syntaxerror("I don't know anything about movie \"%s\"", name);
3014 static int c_previousframe(map_t*args)
3016 char*name = lu(args, "name");
3018 if(s_swf3action(name, "previousframe")) {
3021 syntaxerror("I don't know anything about movie \"%s\"", name);
3025 static int c_movement(map_t*args, int type)
3027 char*instance = lu(args, "name");
3035 xstr = lu(args, "x");
3036 ystr = lu(args, "y");
3038 s_getParameters(instance, &p);
3043 if(isRelative(xstr))
3045 if(type == PT_PUT || type == PT_STARTCLIP)
3046 syntaxerror("relative x values not allowed for initial put or startclip");
3047 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3051 p.x = parseTwip(xstr);
3057 if(isRelative(ystr))
3059 if(type == PT_PUT || type == PT_STARTCLIP)
3060 syntaxerror("relative y values not allowed for initial put or startclip");
3061 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3065 p.y = parseTwip(ystr);
3070 if (change_sets_all)
3078 char* interstr = lu(args, "interpolation");
3079 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3081 syntaxerror("unkown interpolation %s", interstr);
3082 s_change(instance, p, inter);
3087 char* interstr = lu(args, "interpolation");
3088 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3090 syntaxerror("unkown interpolation %s", interstr);
3091 s_schange(instance, p, inter);
3096 char* rstr = lu(args, "r");
3097 int radius = parseTwip(rstr);
3099 syntaxerror("sweep not possible: radius must be greater than 0.");
3100 char* dirstr = lu(args, "dir");
3101 int clockwise = parseDir(dirstr);
3102 char* arcstr = lu(args, "arc");
3103 int short_arc = parseArc(arcstr);
3104 char* interstr = lu(args, "interpolation");
3105 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3107 syntaxerror("unkown interpolation %s", interstr);
3108 s_sweep(instance, p, radius, clockwise, short_arc, inter);
3115 static int c_placement(map_t*args, int type)
3117 char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3120 char* luminancestr = lu(args, "luminance");
3121 char* scalestr = lu(args, "scale");
3122 char* scalexstr = lu(args, "scalex");
3123 char* scaleystr = lu(args, "scaley");
3124 char* rotatestr = lu(args, "rotate");
3125 char* shearstr = lu(args, "shear");
3126 char* xstr="", *pivotstr="";
3127 char* ystr="", *anglestr="";
3128 char*above = lu(args, "above"); /*FIXME*/
3129 char*below = lu(args, "below");
3130 char* rstr = lu(args, "red");
3131 char* gstr = lu(args, "green");
3132 char* bstr = lu(args, "blue");
3133 char* astr = lu(args, "alpha");
3134 char* pinstr = lu(args, "pin");
3135 char* as = map_lookup(args, "as");
3136 char* blendmode = lu(args, "blend");
3137 char* filterstr = lu(args, "filter");
3148 { // (?) .rotate or .arcchange
3149 pivotstr = lu(args, "pivot");
3150 anglestr = lu(args, "angle");
3154 xstr = lu(args, "x");
3155 ystr = lu(args, "y");
3159 luminance = parseMulAdd(luminancestr);
3163 luminance.mul = 256;
3168 if(scalexstr[0]||scaleystr[0])
3169 syntaxerror("scalex/scaley and scale cannot both be set");
3170 scalexstr = scaleystr = scalestr;
3173 if(type == PT_PUT || type == PT_STARTCLIP) {
3175 character = lu(args, "character");
3176 parameters_clear(&p);
3177 } else if (type == PT_BUTTON) {
3178 character = lu(args, "name");
3179 parameters_clear(&p);
3182 s_getParameters(instance, &p);
3188 if(isRelative(xstr))
3190 if(type == PT_PUT || type == PT_STARTCLIP)
3191 syntaxerror("relative x values not allowed for initial put or startclip");
3192 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3196 p.x = parseTwip(xstr);
3202 if(isRelative(ystr))
3204 if(type == PT_PUT || type == PT_STARTCLIP)
3205 syntaxerror("relative y values not allowed for initial put or startclip");
3206 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3210 p.y = parseTwip(ystr);
3215 /* scale, scalex, scaley */
3217 oldbbox = s_getCharBBox(character);
3219 oldbbox = s_getInstanceBBox(instance);
3220 oldwidth = oldbbox.xmax - oldbbox.xmin;
3221 oldheight = oldbbox.ymax - oldbbox.ymin;
3228 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3229 set = set | SF_SCALEX;
3237 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3238 set = set | SF_SCALEY;
3244 if(isRelative(rotatestr))
3245 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3247 p.rotate = parseFloat(rotatestr);
3248 set = set | SF_ROTATE;
3254 if(isRelative(shearstr))
3255 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3257 p.shear = parseFloat(shearstr);
3258 set = set | SF_SHEAR;
3263 if(isPoint(pivotstr))
3264 p.pivot = parsePoint(pivotstr);
3266 p.pivot = getPoint(oldbbox, pivotstr);
3267 set = set | SF_PIVOT;
3273 p.pin = parsePoint(pinstr);
3275 p.pin = getPoint(oldbbox, pinstr);
3279 /* color transform */
3281 if(rstr[0] || luminancestr[0])
3285 r = parseMulAdd(rstr);
3288 r.add = p.cxform.r0;
3289 r.mul = p.cxform.r1;
3291 r = mergeMulAdd(r, luminance);
3292 p.cxform.r0 = r.mul;
3293 p.cxform.r1 = r.add;
3294 set = set | SF_CX_R;
3296 if(gstr[0] || luminancestr[0])
3300 g = parseMulAdd(gstr);
3303 g.add = p.cxform.g0;
3304 g.mul = p.cxform.g1;
3306 g = mergeMulAdd(g, luminance);
3307 p.cxform.g0 = g.mul;
3308 p.cxform.g1 = g.add;
3309 set = set | SF_CX_G;
3311 if(bstr[0] || luminancestr[0])
3315 b = parseMulAdd(bstr);
3318 b.add = p.cxform.b0;
3319 b.mul = p.cxform.b1;
3321 b = mergeMulAdd(b, luminance);
3322 p.cxform.b0 = b.mul;
3323 p.cxform.b1 = b.add;
3324 set = set | SF_CX_B;
3328 MULADD a = parseMulAdd(astr);
3329 p.cxform.a0 = a.mul;
3330 p.cxform.a1 = a.add;
3331 set = set | SF_CX_A;
3338 for(t = 0; blendModeNames[t]; t++)
3340 if(!strcmp(blendModeNames[t], blendmode))
3348 syntaxerror("unknown blend mode: '%s'", blendmode);
3350 p.blendmode = blend;
3351 set = set | SF_BLEND;
3356 p.filters = parseFilters(filterstr);
3357 set = set | SF_FILTER;
3360 if (type == PT_CHANGE && set & (SF_X | SF_Y))
3361 warning("As of version 0.8.2 using the .change command to modify an \
3362 object's position on the stage is considered deprecated. Future \
3363 versions may consider x and y parameters for the .change command \
3364 to be illegal; please use the .move command.");
3366 if (change_sets_all)
3373 s_put(instance, character, p);
3377 char* interstr = lu(args, "interpolation");
3378 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3380 syntaxerror("unkown interpolation %s", interstr);
3381 s_change(instance, p, inter);
3386 char* interstr = lu(args, "interpolation");
3387 interpolation_t* inter = (interpolation_t*)dictionary_lookup(&interpolations, interstr);
3389 syntaxerror("unkown interpolation %s", interstr);
3390 s_schange(instance, p, inter);
3394 s_jump(instance, p);
3397 s_startclip(instance, character, p);
3401 s_buttonput(character, as, p);
3403 s_buttonput(character, "shape", p);
3409 static int c_put(map_t*args)
3411 c_placement(args, PT_PUT);
3414 static int c_change(map_t*args)
3416 if (currentframe == 0)
3417 warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3418 c_placement(args, PT_CHANGE);
3421 static int c_schange(map_t*args)
3423 c_placement(args, PT_SCHANGE);
3426 static int c_move(map_t* args)
3428 c_movement(args, PT_MOVE);
3431 static int c_smove(map_t* args)
3433 c_movement(args, PT_SMOVE);
3436 static int c_sweep(map_t* args)
3438 c_movement(args, PT_SWEEP);
3441 static int c_arcchange(map_t*args)
3443 c_placement(args, 0);
3446 static int c_jump(map_t*args)
3448 c_placement(args, PT_JUMP);
3451 static int c_startclip(map_t*args)
3453 c_placement(args, PT_STARTCLIP);
3456 static int c_show(map_t*args)
3458 c_placement(args, PT_BUTTON);
3461 static int c_toggle(map_t* args)
3463 char*instance = lu(args, "name");
3464 U16 flagsOn = 0x0000, flagsOff = 0xffff;
3465 char* alignstr = lu(args, "fixed_alignment");
3466 if (!strcmp(alignstr, "on"))
3467 flagsOn += IF_FIXED_ALIGNMENT;
3469 if (!strcmp(alignstr, "off"))
3470 flagsOff -= IF_FIXED_ALIGNMENT;
3472 syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3473 s_toggle(instance, flagsOn, flagsOff);
3476 static int c_del(map_t*args)
3478 char*instance = lu(args, "name");
3479 s_delinstance(instance);
3482 static int c_end(map_t*args)
3487 static int c_sprite(map_t*args)
3489 char* name = lu(args, "name");
3493 static int c_frame(map_t*args)
3495 char*framestr = lu(args, "n");
3496 char*cutstr = lu(args, "cut");
3498 char*name = lu(args, "name");
3499 char*anchor = lu(args, "anchor");
3502 if(!strcmp(anchor, "anchor") && !*name)
3507 if(strcmp(cutstr, "no"))
3509 if(isRelative(framestr)) {
3510 frame = s_getframe();
3511 if(getSign(framestr)<0)
3512 syntaxerror("relative frame expressions must be positive");
3513 frame += parseInt(getOffset(framestr));
3516 frame = parseInt(framestr);
3517 if(s_getframe() >= frame
3518 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3519 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3521 s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3524 static int c_primitive(map_t*args)
3526 char*name = lu(args, "name");
3527 char*command = lu(args, "commandname");
3528 int width=0, height=0, r=0;
3529 int linewidth = parseTwip(lu(args, "line"));
3530 char*colorstr = lu(args, "color");
3531 RGBA color = parseColor(colorstr);
3532 char*fillstr = lu(args, "fill");
3539 if(!strcmp(command, "circle"))
3541 else if(!strcmp(command, "filled"))
3545 width = parseTwip(lu(args, "width"));
3546 height = parseTwip(lu(args, "height"));
3547 } else if (type==1) {
3548 r = parseTwip(lu(args, "r"));
3549 } else if (type==2) {
3550 outline = lu(args, "outline");
3553 if(!strcmp(fillstr, "fill"))
3555 if(!strcmp(fillstr, "none"))
3557 if(width<0 || height<0 || linewidth<0 || r<0)
3558 syntaxerror("values width, height, line, r must be positive");
3560 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3561 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3562 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3566 static int c_textshape(map_t*args)
3568 char*name = lu(args, "name");
3569 char*text = lu(args, "text");
3570 char*font = lu(args, "font");
3571 float size = parsePxOrPercent(font, lu(args, "size"));
3573 s_textshape(name, font, size, text);
3577 static int c_swf(map_t*args)
3579 char*name = lu(args, "name");
3580 char*filename = lu(args, "filename");
3581 char*command = lu(args, "commandname");
3582 if(!strcmp(command, "shape"))
3583 warning("Please use .swf instead of .shape");
3584 s_includeswf(name, filename);
3588 static int c_font(map_t*args)
3590 char*name = lu(args, "name");
3591 char*filename = lu(args, "filename");
3592 s_font(name, filename);
3596 static int c_sound(map_t*args)
3598 char*name = lu(args, "name");
3599 char*filename = lu(args, "filename");
3600 s_sound(name, filename);
3604 static int c_text(map_t*args)
3606 char*name = lu(args, "name");
3607 char*text = lu(args, "text");
3608 char*font = lu(args, "font");
3609 float size = parsePxOrPercent(font, lu(args, "size"));
3610 RGBA color = parseColor(lu(args, "color"));
3611 s_text(name, font, text, (int)(size*100), color);
3615 static int c_soundtrack(map_t*args)
3620 static int c_quicktime(map_t*args)
3622 char*name = lu(args, "name");
3623 char*url = lu(args, "url");
3624 s_quicktime(name, url);
3628 static int c_image(map_t*args)
3630 char*command = lu(args, "commandname");
3631 char*name = lu(args, "name");
3632 char*filename = lu(args, "filename");
3633 if(!strcmp(command,"jpeg")) {
3634 int quality = (int)(parsePercent(lu(args, "quality"))*100);
3635 s_image(name, "jpeg", filename, quality);
3637 s_image(name, "png", filename, 0);
3642 static int c_outline(map_t*args)
3644 char*name = lu(args, "name");
3645 char*format = lu(args, "format");
3649 syntaxerror("colon (:) expected");
3651 s_outline(name, format, text);
3655 int fakechar(map_t*args)
3657 char*name = lu(args, "name");
3658 s_box(name, 0, 0, black, 20, 0);
3662 static int c_egon(map_t*args) {return fakechar(args);}
3663 static int c_button(map_t*args) {
3664 char*name = lu(args, "name");
3668 static int current_button_flags = 0;
3669 static int c_on_press(map_t*args)
3671 char*position = lu(args, "position");
3673 if(!strcmp(position, "inside")) {
3674 current_button_flags |= BC_OVERUP_OVERDOWN;
3675 } else if(!strcmp(position, "outside")) {
3676 //current_button_flags |= BC_IDLE_OUTDOWN;
3677 syntaxerror("IDLE_OVERDOWN not supported by SWF");
3678 } else if(!strcmp(position, "anywhere")) {
3679 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3682 if(type == RAWDATA) {
3684 s_buttonaction(current_button_flags, action);
3685 current_button_flags = 0;
3691 static int c_on_release(map_t*args)
3693 char*position = lu(args, "position");
3695 if(!strcmp(position, "inside")) {
3696 current_button_flags |= BC_OVERDOWN_OVERUP;
3697 } else if(!strcmp(position, "outside")) {
3698 current_button_flags |= BC_OUTDOWN_IDLE;
3699 } else if(!strcmp(position, "anywhere")) {
3700 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3703 if(type == RAWDATA) {
3705 s_buttonaction(current_button_flags, action);
3706 current_button_flags = 0;
3712 static int c_on_move_in(map_t*args)
3714 char*position = lu(args, "state");
3716 if(!strcmp(position, "pressed")) {
3717 current_button_flags |= BC_OUTDOWN_OVERDOWN;
3718 } else if(!strcmp(position, "not_pressed")) {
3719 current_button_flags |= BC_IDLE_OVERUP;
3720 } else if(!strcmp(position, "any")) {
3721 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
3724 if(type == RAWDATA) {
3726 s_buttonaction(current_button_flags, action);
3727 current_button_flags = 0;
3733 static int c_on_move_out(map_t*args)
3735 char*position = lu(args, "state");
3737 if(!strcmp(position, "pressed")) {
3738 current_button_flags |= BC_OVERDOWN_OUTDOWN;
3739 } else if(!strcmp(position, "not_pressed")) {
3740 current_button_flags |= BC_OVERUP_IDLE;
3741 } else if(!strcmp(position, "any")) {
3742 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
3745 if(type == RAWDATA) {
3747 s_buttonaction(current_button_flags, action);
3748 current_button_flags = 0;
3754 static int c_on_key(map_t*args)
3756 char*key = lu(args, "key");
3758 if(strlen(key)==1) {
3761 current_button_flags |= 0x4000 + (key[0]*0x200);
3763 syntaxerror("invalid character: %c"+key[0]);
3768 <ctrl-x> = 0x200*(x-'a')
3772 syntaxerror("invalid key: %s",key);
3775 if(type == RAWDATA) {
3777 s_buttonaction(current_button_flags, action);
3778 current_button_flags = 0;
3785 static int c_edittext(map_t*args)
3787 //"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"},
3788 char*name = lu(args, "name");
3789 char*font = lu(args, "font");
3790 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
3791 int width = parseTwip(lu(args, "width"));
3792 int height = parseTwip(lu(args, "height"));
3793 char*text = lu(args, "text");
3794 RGBA color = parseColor(lu(args, "color"));
3795 int maxlength = parseInt(lu(args, "maxlength"));
3796 char*variable = lu(args, "variable");
3797 char*passwordstr = lu(args, "password");
3798 char*wordwrapstr = lu(args, "wordwrap");
3799 char*multilinestr = lu(args, "multiline");
3800 char*htmlstr = lu(args, "html");
3801 char*noselectstr = lu(args, "noselect");
3802 char*readonlystr = lu(args, "readonly");
3803 char*borderstr = lu(args, "border");
3804 char*autosizestr = lu(args, "autosize");
3805 char*alignstr = lu(args, "align");
3809 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
3810 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
3811 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
3812 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
3813 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
3814 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
3815 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
3816 if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
3817 if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
3818 else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
3819 else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
3820 else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
3821 else syntaxerror("Unknown alignment: %s", alignstr);
3823 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
3827 static int c_morphshape(map_t*args) {return fakechar(args);}
3828 static int c_movie(map_t*args) {return fakechar(args);}
3830 static char* readfile(const char*filename)
3832 FILE*fi = fopen(filename, "rb");
3836 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
3837 fseek(fi, 0, SEEK_END);
3839 fseek(fi, 0, SEEK_SET);
3840 text = rfx_alloc(l+1);
3841 fread(text, l, 1, fi);
3847 static int c_action(map_t*args)
3849 char* filename = map_lookup(args, "filename");
3850 if(!filename ||!*filename) {
3852 if(type != RAWDATA) {
3853 syntaxerror("colon (:) expected");
3857 s_action(readfile(filename));
3863 static int c_initaction(map_t*args)
3865 char* character = lu(args, "name");
3866 char* filename = map_lookup(args, "filename");
3867 if(!filename ||!*filename) {
3869 if(type != RAWDATA) {
3870 syntaxerror("colon (:) expected");
3872 s_initaction(character, text);
3874 s_initaction(character, readfile(filename));
3882 command_func_t* func;
3885 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no"},
3886 {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
3887 // "import" type stuff
3888 {"swf", c_swf, "name filename"},
3889 {"shape", c_swf, "name filename"},
3890 {"jpeg", c_image, "name filename quality=80%"},
3891 {"png", c_image, "name filename"},
3892 {"movie", c_movie, "name filename"},
3893 {"sound", c_sound, "name filename"},
3894 {"font", c_font, "name filename glyphs="},
3895 {"soundtrack", c_soundtrack, "filename"},
3896 {"quicktime", c_quicktime, "url"},
3898 // generators of primitives
3900 {"point", c_point, "name x=0 y=0"},
3901 {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
3902 {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
3903 {"outline", c_outline, "name format=simple"},
3904 {"textshape", c_textshape, "name font size=100% text"},
3907 {"blur", c_blur, "name blur= blurx= blury= passes=1"},
3908 {"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"},
3909 {"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"},
3910 {"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"},
3912 // character generators
3913 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
3914 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
3915 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
3917 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
3918 {"text", c_text, "name text font size=100% color=white"},
3919 {"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="},
3920 {"morphshape", c_morphshape, "name start end"},
3921 {"button", c_button, "name"},
3922 {"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="},
3923 {"on_press", c_on_press, "position=inside"},
3924 {"on_release", c_on_release, "position=anywhere"},
3925 {"on_move_in", c_on_move_in, "state=not_pressed"},
3926 {"on_move_out", c_on_move_out, "state=not_pressed"},
3927 {"on_key", c_on_key, "key=any"},
3930 {"play", c_play, "name loop=0 @nomultiple=0"},
3931 {"stop", c_stop, "name= "},
3932 {"nextframe", c_nextframe, "name"},
3933 {"previousframe", c_previousframe, "name"},
3935 // object placement tags
3936 {"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="},
3937 {"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="},
3938 {"move", c_move, "name x= y= interpolation=linear"},
3939 {"smove", c_smove, "name x= y= interpolation=linear"},
3940 {"sweep", c_sweep, "name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
3941 {"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"},
3942 //{"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3943 {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
3944 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
3945 {"del", c_del, "name"},
3946 // virtual object placement
3947 {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
3949 {"toggle", c_toggle, "name fixed_alignment="},
3951 // commands which start a block
3952 //startclip (see above)
3953 {"sprite", c_sprite, "name"},
3954 {"action", c_action, "filename="},
3955 {"initaction", c_initaction, "name filename="},
3961 static map_t parseArguments(char*command, char*pattern)
3977 string_set(&t1, "commandname");
3978 string_set(&t2, command);
3979 map_put(&result, t1, t2);
3981 if(!pattern || !*pattern)
3988 if(!strncmp("<i> ", x, 3)) {
3990 if(type == COMMAND || type == RAWDATA) {
3992 syntaxerror("character name expected");
3994 name[pos].str = "instance";
3996 value[pos].str = text;
3997 value[pos].len = strlen(text);
4001 if(type == ASSIGNMENT)
4004 name[pos].str = "character";
4006 value[pos].str = text;
4007 value[pos].len = strlen(text);
4015 isboolean[pos] = (x[0] =='@');
4028 name[pos].len = d-x;
4033 name[pos].len = e-x;
4034 value[pos].str = e+1;
4035 value[pos].len = d-e-1;
4043 /* for(t=0;t<len;t++) {
4044 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4045 isboolean[t]?"(boolean)":"");
4050 if(type == RAWDATA || type == COMMAND) {
4055 // first, search for boolean arguments
4056 for(pos=0;pos<len;pos++)
4058 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4060 if(type == ASSIGNMENT)
4062 value[pos].str = text;
4063 value[pos].len = strlen(text);
4064 /*printf("setting boolean parameter %s (to %s)\n",
4065 strdup_n(name[pos], namelen[pos]),
4066 strdup_n(value[pos], valuelen[pos]));*/
4071 // second, search for normal arguments
4073 for(pos=0;pos<len;pos++)
4075 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4076 (type != ASSIGNMENT && !set[pos])) {
4078 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4080 if(type == ASSIGNMENT)
4083 value[pos].str = text;
4084 value[pos].len = strlen(text);
4086 printf("setting parameter %s (to %s)\n",
4087 strdup_n(name[pos].str, name[pos].len),
4088 strdup_n(value[pos].str, value[pos].len));
4094 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4098 for(t=0;t<len;t++) {
4099 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4102 for(t=0;t<len;t++) {
4103 if(value[t].str && value[t].str[0] == '*') {
4104 //relative default- take value from some other parameter
4106 for(s=0;s<len;s++) {
4107 if(value[s].len == value[t].len-1 &&
4108 !strncmp(&value[t].str[1], value[s].str, value[s].len))
4109 value[t].str = value[s].str;
4112 if(value[t].str == 0) {
4114 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4118 /* ok, now construct the dictionary from the parameters */
4122 map_put(&result, name[t], value[t]);
4126 static void parseArgumentsForCommand(char*command)
4131 msg("<verbose> parse Command: %s (line %d)", command, line);
4133 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4134 if(!strcmp(arguments[t].command, command)) {
4136 /* ugly hack- will be removed soon (once documentation and .sc generating
4137 utilities have been changed) */
4138 if(!strcmp(command, "swf") && !stackpos) {
4139 warning("Please use .flash instead of .swf- this will be mandatory soon");
4144 args = parseArguments(command, arguments[t].arguments);
4150 syntaxerror("command %s not known", command);
4152 // catch missing .flash directives at the beginning of a file
4153 if(strcmp(command, "flash") && !stackpos)
4155 syntaxerror("No movie defined- use .flash first");
4159 printf(".%s\n", command);fflush(stdout);
4160 map_dump(&args, stdout, "\t");fflush(stdout);
4163 (*arguments[nr].func)(&args);
4165 /*if(!strcmp(command, "button") ||
4166 !strcmp(command, "action")) {
4169 if(type == COMMAND) {
4170 if(!strcmp(text, "end"))
4185 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4186 * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4187 * No syntax checking is done */
4188 static void analyseArgumentsForCommand(char*command)
4194 msg("<verbose> analyse Command: %s (line %d)", command, line);
4196 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4198 if(!strcmp(arguments[t].command, command))
4200 args = parseArguments(command, arguments[t].arguments);
4206 printf(".%s\n", command);fflush(stdout);
4207 map_dump(&args, stdout, "\t");fflush(stdout);
4209 char* name = lu(&args, "name");
4210 if (!strcmp(command, "font"))
4212 if(dictionary_lookup(&fonts, name))
4213 syntaxerror("font %s defined twice", name);
4216 fontfile = lu(&args, "filename");
4217 font = swf_LoadFont(fontfile);
4219 warning("Couldn't open font file \"%s\"", fontfile);
4220 font = (SWFFONT*)malloc(sizeof(SWFFONT));
4221 memset(font, 0, sizeof(SWFFONT));
4223 swf_FontUseUTF8(font, lu(&args, "glyphs"));
4224 swf_FontPrepareForEditText(font);
4225 dictionary_put2(&fonts, name, font);
4229 SWFFONT* font = dictionary_lookup(&fonts, lu(&args, "font"));
4231 syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
4233 if (!strcmp(command, "edittext"))
4234 swf_FontUseAll(font);
4236 swf_FontUseUTF8(font, lu(&args, "text"));
4242 void skipParameters()
4246 while (type != COMMAND);
4250 void findFontUsage()
4252 char* fontRelated = "font;text;textshape;edittext;";
4253 while(!noMoreTokens())
4257 syntaxerror("command expected");
4258 if (strstr(fontRelated, text))
4259 analyseArgumentsForCommand(text);
4261 if(strcmp(text, "end"))
4270 dictionary_init(&fonts);
4271 cleanUp = &freeFontDictionary;
4275 int main (int argc,char ** argv)
4278 processargs(argc, argv);
4279 initLog(0,-1,0,0,-1,verbose);
4282 args_callback_usage(argv[0]);
4286 file = generateTokens(filename);
4288 fprintf(stderr, "parser returned error.\n");
4295 while(!noMoreTokens()) {
4298 syntaxerror("command expected");
4299 parseArgumentsForCommand(text);